"!==k[1]||lb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)n.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}n.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),l.appendChecked||n.grep(vb(p,"input"),wb),q=0;while(f=p[q++])if((!d||-1===n.inArray(f,d))&&(g=n.contains(f.ownerDocument,f),h=vb(o.appendChild(f),"script"),g&&Ab(h),c)){e=0;while(f=h[e++])pb.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.deleteExpando,m=n.event.special;null!=(d=a[h]);h++)if((b||n.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k?delete d[i]:typeof d.removeAttribute!==L?d.removeAttribute(i):d[i]=null,c.push(f))}}}),n.fn.extend({text:function(a){return W(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||z).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(vb(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&Ab(vb(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(vb(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return W(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(gb,""):void 0;if(!("string"!=typeof a||nb.test(a)||!l.htmlSerialize&&hb.test(a)||!l.leadingWhitespace&&ib.test(a)||sb[(kb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(jb,"<$1>$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(vb(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(vb(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,o=k-1,p=a[0],q=n.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&ob.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(i=n.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=n.map(vb(i,"script"),yb),f=g.length;k>j;j++)d=i,j!==o&&(d=n.clone(d,!0,!0),f&&n.merge(g,vb(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,n.map(g,zb),j=0;f>j;j++)d=g[j],pb.test(d.type||"")&&!n._data(d,"globalEval")&&n.contains(h,d)&&(d.src?n._evalUrl&&n._evalUrl(d.src):n.globalEval((d.text||d.textContent||d.innerHTML||"").replace(rb,"")));i=c=null}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],g=n(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Db,Eb={};function Fb(b,c){var d=n(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:n.css(d[0],"display");return d.detach(),e}function Gb(a){var b=z,c=Eb[a];return c||(c=Fb(a,b),"none"!==c&&c||(Db=(Db||n("")).appendTo(b.documentElement),b=(Db[0].contentWindow||Db[0].contentDocument).document,b.write(),b.close(),c=Fb(a,b),Db.detach()),Eb[a]=c),c}!function(){var a,b,c=z.createElement("div"),d="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;padding:0;margin:0;border:0";c.innerHTML=" a ",a=c.getElementsByTagName("a")[0],a.style.cssText="float:left;opacity:.5",l.opacity=/^0.5/.test(a.style.opacity),l.cssFloat=!!a.style.cssFloat,c.style.backgroundClip="content-box",c.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===c.style.backgroundClip,a=c=null,l.shrinkWrapBlocks=function(){var a,c,e,f;if(null==b){if(a=z.getElementsByTagName("body")[0],!a)return;f="border:0;width:0;height:0;position:absolute;top:0;left:-9999px",c=z.createElement("div"),e=z.createElement("div"),a.appendChild(c).appendChild(e),b=!1,typeof e.style.zoom!==L&&(e.style.cssText=d+";width:1px;padding:1px;zoom:1",e.innerHTML="
",e.firstChild.style.width="5px",b=3!==e.offsetWidth),a.removeChild(c),a=c=e=null}return b}}();var Hb=/^margin/,Ib=new RegExp("^("+T+")(?!px)[a-z%]+$","i"),Jb,Kb,Lb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Jb=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Kb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Jb(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),Ib.test(g)&&Hb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):z.documentElement.currentStyle&&(Jb=function(a){return a.currentStyle},Kb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Jb(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Ib.test(g)&&!Lb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Mb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h=z.createElement("div"),i="border:0;width:0;height:0;position:absolute;top:0;left:-9999px",j="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;padding:0;margin:0;border:0";h.innerHTML=" a ",b=h.getElementsByTagName("a")[0],b.style.cssText="float:left;opacity:.5",l.opacity=/^0.5/.test(b.style.opacity),l.cssFloat=!!b.style.cssFloat,h.style.backgroundClip="content-box",h.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===h.style.backgroundClip,b=h=null,n.extend(l,{reliableHiddenOffsets:function(){if(null!=c)return c;var a,b,d,e=z.createElement("div"),f=z.getElementsByTagName("body")[0];if(f)return e.setAttribute("className","t"),e.innerHTML=" a ",a=z.createElement("div"),a.style.cssText=i,f.appendChild(a).appendChild(e),e.innerHTML="",b=e.getElementsByTagName("td"),b[0].style.cssText="padding:0;margin:0;border:0;display:none",d=0===b[0].offsetHeight,b[0].style.display="",b[1].style.display="none",c=d&&0===b[0].offsetHeight,f.removeChild(a),e=f=null,c},boxSizing:function(){return null==d&&k(),d},boxSizingReliable:function(){return null==e&&k(),e},pixelPosition:function(){return null==f&&k(),f},reliableMarginRight:function(){var b,c,d,e;if(null==g&&a.getComputedStyle){if(b=z.getElementsByTagName("body")[0],!b)return;c=z.createElement("div"),d=z.createElement("div"),c.style.cssText=i,b.appendChild(c).appendChild(d),e=d.appendChild(z.createElement("div")),e.style.cssText=d.style.cssText=j,e.style.marginRight=e.style.width="0",d.style.width="1px",g=!parseFloat((a.getComputedStyle(e,null)||{}).marginRight),b.removeChild(c)}return g}});function k(){var b,c,h=z.getElementsByTagName("body")[0];h&&(b=z.createElement("div"),c=z.createElement("div"),b.style.cssText=i,h.appendChild(b).appendChild(c),c.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;display:block;padding:1px;border:1px;width:4px;margin-top:1%;top:1%",n.swap(h,null!=h.style.zoom?{zoom:1}:{},function(){d=4===c.offsetWidth}),e=!0,f=!1,g=!0,a.getComputedStyle&&(f="1%"!==(a.getComputedStyle(c,null)||{}).top,e="4px"===(a.getComputedStyle(c,null)||{width:"4px"}).width),h.removeChild(b),c=h=null)}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Nb=/alpha\([^)]*\)/i,Ob=/opacity\s*=\s*([^)]*)/,Pb=/^(none|table(?!-c[ea]).+)/,Qb=new RegExp("^("+T+")(.*)$","i"),Rb=new RegExp("^([+-])=("+T+")","i"),Sb={position:"absolute",visibility:"hidden",display:"block"},Tb={letterSpacing:0,fontWeight:400},Ub=["Webkit","O","Moz","ms"];function Vb(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Ub.length;while(e--)if(b=Ub[e]+c,b in a)return b;return d}function Wb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=n._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&V(d)&&(f[g]=n._data(d,"olddisplay",Gb(d.nodeName)))):f[g]||(e=V(d),(c&&"none"!==c||!e)&&n._data(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Xb(a,b,c){var d=Qb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Yb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+U[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+U[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+U[f]+"Width",!0,e))):(g+=n.css(a,"padding"+U[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+U[f]+"Width",!0,e)));return g}function Zb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Jb(a),g=l.boxSizing()&&"border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Kb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Ib.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Yb(a,b,c||(g?"border":"content"),d,f)+"px"}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Kb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":l.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;if(b=n.cssProps[h]||(n.cssProps[h]=Vb(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Rb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]="",i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Vb(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Kb(a,b,d)),"normal"===f&&b in Tb&&(f=Tb[b]),""===c||c?(e=parseFloat(f),c===!0||n.isNumeric(e)?e||0:f):f}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?0===a.offsetWidth&&Pb.test(n.css(a,"display"))?n.swap(a,Sb,function(){return Zb(a,b,d)}):Zb(a,b,d):void 0},set:function(a,c,d){var e=d&&Jb(a);return Xb(a,c,d?Yb(a,b,d,l.boxSizing()&&"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),l.opacity||(n.cssHooks.opacity={get:function(a,b){return Ob.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=n.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===n.trim(f.replace(Nb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Nb.test(f)?f.replace(Nb,e):f+" "+e)}}),n.cssHooks.marginRight=Mb(l.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},Kb,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+U[d]+b]=f[d]||f[d-2]||f[0];return e}},Hb.test(a)||(n.cssHooks[a+b].set=Xb)}),n.fn.extend({css:function(a,b){return W(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Jb(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)
+},a,b,arguments.length>1)},show:function(){return Wb(this,!0)},hide:function(){return Wb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){V(this)?n(this).show():n(this).hide()})}});function $b(a,b,c,d,e){return new $b.prototype.init(a,b,c,d,e)}n.Tween=$b,$b.prototype={constructor:$b,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=$b.propHooks[this.prop];return a&&a.get?a.get(this):$b.propHooks._default.get(this)},run:function(a){var b,c=$b.propHooks[this.prop];return this.pos=b=this.options.duration?n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):$b.propHooks._default.set(this),this}},$b.prototype.init.prototype=$b.prototype,$b.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},$b.propHooks.scrollTop=$b.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=$b.prototype.init,n.fx.step={};var _b,ac,bc=/^(?:toggle|show|hide)$/,cc=new RegExp("^(?:([+-])=|)("+T+")([a-z%]*)$","i"),dc=/queueHooks$/,ec=[jc],fc={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=cc.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&cc.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function gc(){return setTimeout(function(){_b=void 0}),_b=n.now()}function hc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=U[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function ic(a,b,c){for(var d,e=(fc[b]||[]).concat(fc["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function jc(a,b,c){var d,e,f,g,h,i,j,k,m=this,o={},p=a.style,q=a.nodeType&&V(a),r=n._data(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,m.always(function(){m.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=n.css(a,"display"),k=Gb(a.nodeName),"none"===j&&(j=k),"inline"===j&&"none"===n.css(a,"float")&&(l.inlineBlockNeedsLayout&&"inline"!==k?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",l.shrinkWrapBlocks()||m.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],bc.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||n.style(a,d)}if(!n.isEmptyObject(o)){r?"hidden"in r&&(q=r.hidden):r=n._data(a,"fxshow",{}),f&&(r.hidden=!q),q?n(a).show():m.done(function(){n(a).hide()}),m.done(function(){var b;n._removeData(a,"fxshow");for(b in o)n.style(a,b,o[b])});for(d in o)g=ic(q?r[d]:0,d,m),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function kc(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function lc(a,b,c){var d,e,f=0,g=ec.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=_b||gc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:_b||gc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(kc(k,j.opts.specialEasing);g>f;f++)if(d=ec[f].call(j,a,k,j.opts))return d;return n.map(k,ic,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(lc,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],fc[c]=fc[c]||[],fc[c].unshift(b)},prefilter:function(a,b){b?ec.unshift(a):ec.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(V).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=lc(this,n.extend({},a),f);(e||n._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=n._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&dc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=n._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(hc(b,!0),a,d,e)}}),n.each({slideDown:hc("show"),slideUp:hc("hide"),slideToggle:hc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=n.timers,c=0;for(_b=n.now();ca ",a=e.getElementsByTagName("a")[0],c=z.createElement("select"),d=c.appendChild(z.createElement("option")),b=e.getElementsByTagName("input")[0],a.style.cssText="top:1px",l.getSetAttribute="t"!==e.className,l.style=/top/.test(a.getAttribute("style")),l.hrefNormalized="/a"===a.getAttribute("href"),l.checkOn=!!b.value,l.optSelected=d.selected,l.enctype=!!z.createElement("form").enctype,c.disabled=!0,l.optDisabled=!d.disabled,b=z.createElement("input"),b.setAttribute("value",""),l.input=""===b.getAttribute("value"),b.value="t",b.setAttribute("type","radio"),l.radioValue="t"===b.value,a=b=c=d=e=null}();var mc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(mc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.text(a)}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(l.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)if(d=e[g],n.inArray(n.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var nc,oc,pc=n.expr.attrHandle,qc=/^(?:checked|selected)$/i,rc=l.getSetAttribute,sc=l.input;n.fn.extend({attr:function(a,b){return W(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===L?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?oc:nc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(F);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)?sc&&rc||!qc.test(c)?a[d]=!1:a[n.camelCase("default-"+c)]=a[d]=!1:n.attr(a,c,""),a.removeAttribute(rc?c:d)},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),oc={set:function(a,b,c){return b===!1?n.removeAttr(a,c):sc&&rc||!qc.test(c)?a.setAttribute(!rc&&n.propFix[c]||c,c):a[n.camelCase("default-"+c)]=a[c]=!0,c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=pc[b]||n.find.attr;pc[b]=sc&&rc||!qc.test(b)?function(a,b,d){var e,f;return d||(f=pc[b],pc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,pc[b]=f),e}:function(a,b,c){return c?void 0:a[n.camelCase("default-"+b)]?b.toLowerCase():null}}),sc&&rc||(n.attrHooks.value={set:function(a,b,c){return n.nodeName(a,"input")?void(a.defaultValue=b):nc&&nc.set(a,b,c)}}),rc||(nc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},pc.id=pc.name=pc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},n.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:nc.set},n.attrHooks.contenteditable={set:function(a,b,c){nc.set(a,""===b?!1:b,c)}},n.each(["width","height"],function(a,b){n.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),l.style||(n.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var tc=/^(?:input|select|textarea|button|object)$/i,uc=/^(?:a|area)$/i;n.fn.extend({prop:function(a,b){return W(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return a=n.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):tc.test(a.nodeName)||uc.test(a.nodeName)&&a.href?0:-1}}}}),l.hrefNormalized||n.each(["href","src"],function(a,b){n.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this}),l.enctype||(n.propFix.enctype="encoding");var vc=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(F)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(vc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(F)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(vc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(F)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===L||"boolean"===c)&&(this.className&&n._data(this,"__className__",this.className),this.className=this.className||a===!1?"":n._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(vc," ").indexOf(b)>=0)return!0;return!1}}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var wc=n.now(),xc=/\?/,yc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;n.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=n.trim(b+"");return e&&!n.trim(e.replace(yc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():n.error("Invalid JSON: "+b)},n.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||n.error("Invalid XML: "+b),c};var zc,Ac,Bc=/#.*$/,Cc=/([?&])_=[^&]*/,Dc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Ec=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Fc=/^(?:GET|HEAD)$/,Gc=/^\/\//,Hc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Ic={},Jc={},Kc="*/".concat("*");try{Ac=location.href}catch(Lc){Ac=z.createElement("a"),Ac.href="",Ac=Ac.href}zc=Hc.exec(Ac.toLowerCase())||[];function Mc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(F)||[];if(n.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nc(a,b,c,d){var e={},f=a===Jc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Oc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&n.extend(!0,a,c),a}function Pc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Qc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ac,type:"GET",isLocal:Ec.test(zc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Oc(Oc(a,n.ajaxSettings),b):Oc(n.ajaxSettings,a)},ajaxPrefilter:Mc(Ic),ajaxTransport:Mc(Jc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Dc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||Ac)+"").replace(Bc,"").replace(Gc,zc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(F)||[""],null==k.crossDomain&&(c=Hc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===zc[1]&&c[2]===zc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(zc[3]||("http:"===zc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),Nc(Ic,k,b,v),2===t)return v;h=k.global,h&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Fc.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(xc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Cc.test(e)?e.replace(Cc,"$1_="+wc++):e+(xc.test(e)?"&":"?")+"_="+wc++)),k.ifModified&&(n.lastModified[e]&&v.setRequestHeader("If-Modified-Since",n.lastModified[e]),n.etag[e]&&v.setRequestHeader("If-None-Match",n.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Kc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Nc(Jc,k,b,v)){v.readyState=1,h&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Pc(k,v,c)),u=Qc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(n.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){if(n.isFunction(a))return this.each(function(b){n(this).wrapAll(a.call(this,b))});if(this[0]){var b=n(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!l.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||n.css(a,"display"))},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var Rc=/%20/g,Sc=/\[\]$/,Tc=/\r?\n/g,Uc=/^(?:submit|button|image|reset|file)$/i,Vc=/^(?:input|select|textarea|keygen)/i;function Wc(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||Sc.test(a)?d(a,e):Wc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Wc(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Wc(c,a[c],b,e);return d.join("&").replace(Rc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&Vc.test(this.nodeName)&&!Uc.test(a)&&(this.checked||!X.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(Tc,"\r\n")}}):{name:b.name,value:c.replace(Tc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&$c()||_c()}:$c;var Xc=0,Yc={},Zc=n.ajaxSettings.xhr();a.ActiveXObject&&n(a).on("unload",function(){for(var a in Yc)Yc[a](void 0,!0)}),l.cors=!!Zc&&"withCredentials"in Zc,Zc=l.ajax=!!Zc,Zc&&n.ajaxTransport(function(a){if(!a.crossDomain||l.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Xc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Yc[g],b=void 0,f.onreadystatechange=n.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Yc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function $c(){try{return new a.XMLHttpRequest}catch(b){}}function _c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=z.head||n("head")[0]||z.documentElement;return{send:function(d,e){b=z.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var ad=[],bd=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=ad.pop()||n.expando+"_"+wc++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(bd.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&bd.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(bd,"$1"+e):b.jsonp!==!1&&(b.url+=(xc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,ad.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||z;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var cd=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&cd)return cd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=a.slice(h,a.length),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&n.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?n("").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var dd=a.document.documentElement;function ed(a){return n.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&n.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,n.contains(b,e)?(typeof e.getBoundingClientRect!==L&&(d=e.getBoundingClientRect()),c=ed(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===n.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(c=a.offset()),c.top+=n.css(a[0],"borderTopWidth",!0),c.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-n.css(d,"marginTop",!0),left:b.left-c.left-n.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||dd;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||dd})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);n.fn[a]=function(d){return W(this,function(a,d,e){var f=ed(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?n(f).scrollLeft():e,c?e:n(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=Mb(l.pixelPosition,function(a,c){return c?(c=Kb(a,b),Ib.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return W(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var fd=a.jQuery,gd=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=gd),b&&a.jQuery===n&&(a.jQuery=fd),n},typeof b===L&&(a.jQuery=a.$=n),n});
diff --git a/ewomail-admin/public/layer2.2/extend/layer.ext.js b/ewomail-admin/public/layer2.2/extend/layer.ext.js
new file mode 100644
index 0000000..d592dfd
--- /dev/null
+++ b/ewomail-admin/public/layer2.2/extend/layer.ext.js
@@ -0,0 +1,2 @@
+/*! layer弹层组件拓展类 */
+;!function(){layer.use("skin/layer.ext.css",function(){layer.layui_layer_extendlayerextjs=!0});var a=layer.cache||{},b=function(b){return a.skin?" "+a.skin+" "+a.skin+"-"+b:""};layer.prompt=function(a,c){a=a||{},"function"==typeof a&&(c=a);var d,e=2==a.formType?'
":function(){return'
'}();return layer.open($.extend({btn:["确定","取消"],content:e,skin:"layui-layer-prompt"+b("prompt"),success:function(a){d=a.find(".layui-layer-input"),d.focus()},yes:function(b){var e=d.val();""===e?d.focus():e.length>(a.maxlength||500)?layer.tips("最多输入"+(a.maxlength||500)+"个字数",d,{tips:1}):c&&c(e,b,d)}},a))},layer.tab=function(a){a=a||{};var c=a.tab||{};return layer.open($.extend({type:1,skin:"layui-layer-tab"+b("tab"),title:function(){var a=c.length,b=1,d="";if(a>0)for(d='
'+c[0].title+" ";a>b;b++)d+="
"+c[b].title+" ";return d}(),content:'
'+function(){var a=c.length,b=1,d="";if(a>0)for(d=''+(c[0].content||"no content")+" ";a>b;b++)d+=''+(c[b].content||"no content")+" ";return d}()+" ",success:function(b){var c=b.find(".layui-layer-title").children(),d=b.find(".layui-layer-tabmain").children();c.on("mousedown",function(b){b.stopPropagation?b.stopPropagation():b.cancelBubble=!0;var c=$(this),e=c.index();c.addClass("layui-layer-tabnow").siblings().removeClass("layui-layer-tabnow"),d.eq(e).show().siblings().hide(),"function"==typeof a.change&&a.change(e)})}},a))},layer.photos=function(a,c,d){function e(a,b,c){var d=new Image;d.onload=function(){d.onload=null,b(d)},d.onerror=function(a){d.onerror=null,c(a)},d.src=a}var f={};if(a=a||{},a.photos){var g=a.photos.constructor===Object,h=g?a.photos:{},i=h.data||[],j=h.start||0;if(f.imgIndex=j+1,g){if(0===i.length)return layer.msg("没有图片")}else{var k=$(a.photos),l=function(){return i=[],k.find(a.img||"img").each(function(a){var b=$(this);i.push({alt:b.attr("alt"),pid:b.attr("layer-pid"),src:b.attr("layer-src")||b.attr("src"),thumb:b.attr("src")})}),arguments.callee}();if(0===i.length)return;if(c||k.on("click",a.img||"img",function(){var b=$(this),c=b.index();l(),layer.photos($.extend(a,{photos:{start:c,data:i,tab:a.tab},full:a.full}),!0)}),!c)return}f.imgprev=function(a){f.imgIndex--,f.imgIndex<1&&(f.imgIndex=i.length),f.tabimg(a)},f.imgnext=function(a,b){f.imgIndex++,f.imgIndex>i.length&&(f.imgIndex=1,b)||f.tabimg(a)},f.keyup=function(a){if(!f.end){var b=a.keyCode;a.preventDefault(),37===b?f.imgprev(!0):39===b?f.imgnext(!0):27===b&&layer.close(f.index)}},f.tabimg=function(b){i.length<=1||(h.start=f.imgIndex-1,layer.close(f.index),layer.photos(a,!0,b))},f.event=function(){f.bigimg.hover(function(){f.imgsee.show()},function(){f.imgsee.hide()}),f.bigimg.find(".layui-layer-imgprev").on("click",function(a){a.preventDefault(),f.imgprev()}),f.bigimg.find(".layui-layer-imgnext").on("click",function(a){a.preventDefault(),f.imgnext()}),$(document).on("keyup",f.keyup)},f.loadi=layer.load(1,{shade:"shade"in a?!1:.9,scrollbar:!1}),e(i[j].src,function(c){layer.close(f.loadi),f.index=layer.open($.extend({type:1,area:function(){var b=[c.width,c.height],d=[$(window).width()-100,$(window).height()-100];return!a.full&&b[0]>d[0]&&(b[0]=d[0],b[1]=b[0]*d[1]/b[0]),[b[0]+"px",b[1]+"px"]}(),title:!1,shade:.9,shadeClose:!0,closeBtn:!1,move:".layui-layer-phimg img",moveType:1,scrollbar:!1,moveOut:!0,shift:5*Math.random()|0,skin:"layui-layer-photos"+b("photos"),content:'
",success:function(b,c){f.bigimg=b.find(".layui-layer-phimg"),f.imgsee=b.find(".layui-layer-imguide,.layui-layer-imgbar"),f.event(b),a.tab&&a.tab(i[j],b)},end:function(){f.end=!0,$(document).off("keyup",f.keyup)}},a))},function(){layer.close(f.loadi),layer.msg("当前图片地址异常
是否继续查看下一张?",{time:3e4,btn:["下一张","不看了"],yes:function(){i.length>1&&f.imgnext(!0,!0)}})})}}}();
\ No newline at end of file
diff --git a/ewomail-admin/public/layer2.2/layer.js b/ewomail-admin/public/layer2.2/layer.js
new file mode 100644
index 0000000..bc7141f
--- /dev/null
+++ b/ewomail-admin/public/layer2.2/layer.js
@@ -0,0 +1,2 @@
+/*! layer-v2.2 弹层组件 License LGPL http://layer.layui.com/ By 贤心 */
+;!function(a,b){"use strict";var c,d,e={getPath:function(){var a=document.scripts,b=a[a.length-1],c=b.src;if(!b.getAttribute("merge"))return c.substring(0,c.lastIndexOf("/")+1)}(),enter:function(a){13===a.keyCode&&a.preventDefault()},config:{},end:{},btn:["确定","取消"],type:["dialog","page","iframe","loading","tips"]},f={v:"2.2",ie6:!!a.ActiveXObject&&!a.XMLHttpRequest,index:0,path:e.getPath,config:function(a,b){var d=0;return a=a||{},f.cache=e.config=c.extend(e.config,a),f.path=e.config.path||f.path,"string"==typeof a.extend&&(a.extend=[a.extend]),f.use("skin/layer.css",a.extend&&a.extend.length>0?function g(){var c=a.extend;f.use(c[c[d]?d:d-1],d
'+(i?f.title[0]:f.title)+" ":"";return f.zIndex=g,b([f.shade?'
':"",''+(a&&2!=f.type?"":k)+'
'+(0==f.type&&-1!==f.icon?' ':"")+(1==f.type&&a?"":f.content||"")+'
'+function(){var a=j?' ':"";return f.closeBtn&&(a+=' '),a}()+" "+(f.btn?function(){var a="";"string"==typeof f.btn&&(f.btn=[f.btn]);for(var b=0,c=f.btn.length;c>b;b++)a+='
'+f.btn[b]+" ";return'
'+a+"
"}():"")+"
"],k),c},g.pt.creat=function(){var a=this,b=a.config,g=a.index,i=b.content,j="object"==typeof i;if(!c("#"+b.id)[0]){switch("string"==typeof b.area&&(b.area="auto"===b.area?["",""]:[b.area,""]),b.type){case 0:b.btn="btn"in b?b.btn:e.btn[0],f.closeAll("dialog");break;case 2:var i=b.content=j?b.content:[b.content||"http://layer.layui.com","auto"];b.content='';break;case 3:b.title=!1,b.closeBtn=!1,-1===b.icon&&0===b.icon,f.closeAll("loading");break;case 4:j||(b.content=[b.content,"body"]),b.follow=b.content[1],b.content=b.content[0]+' ',b.title=!1,b.fix=!1,b.tips="object"==typeof b.tips?b.tips:[b.tips,!0],b.tipsMore||f.closeAll("tips")}a.vessel(j,function(d,e){c("body").append(d[0]),j?function(){2==b.type||4==b.type?function(){c("body").append(d[1])}():function(){i.parents("."+h[0])[0]||(i.show().addClass("layui-layer-wrap").wrap(d[1]),c("#"+h[0]+g).find("."+h[5]).before(e))}()}():c("body").append(d[1]),a.layero=c("#"+h[0]+g),b.scrollbar||h.html.css("overflow","hidden").attr("layer-full",g)}).auto(g),2==b.type&&f.ie6&&a.layero.find("iframe").attr("src",i[0]),c(document).off("keydown",e.enter).on("keydown",e.enter),a.layero.on("keydown",function(a){c(document).off("keydown",e.enter)}),4==b.type?a.tips():a.offset(),b.fix&&d.on("resize",function(){a.offset(),(/^\d+%$/.test(b.area[0])||/^\d+%$/.test(b.area[1]))&&a.auto(g),4==b.type&&a.tips()}),b.time<=0||setTimeout(function(){f.close(a.index)},b.time),a.move().callback()}},g.pt.auto=function(a){function b(a){a=g.find(a),a.height(i[1]-j-k-2*(0|parseFloat(a.css("padding"))))}var e=this,f=e.config,g=c("#"+h[0]+a);""===f.area[0]&&f.maxWidth>0&&(/MSIE 7/.test(navigator.userAgent)&&f.btn&&g.width(g.innerWidth()),g.outerWidth()>f.maxWidth&&g.width(f.maxWidth));var i=[g.innerWidth(),g.innerHeight()],j=g.find(h[1]).outerHeight()||0,k=g.find("."+h[6]).outerHeight()||0;switch(f.type){case 2:b("iframe");break;default:""===f.area[1]?f.fix&&i[1]>=d.height()&&(i[1]=d.height(),b("."+h[5])):b("."+h[5])}return e},g.pt.offset=function(){var a=this,b=a.config,c=a.layero,e=[c.outerWidth(),c.outerHeight()],f="object"==typeof b.offset;a.offsetTop=(d.height()-e[1])/2,a.offsetLeft=(d.width()-e[0])/2,f?(a.offsetTop=b.offset[0],a.offsetLeft=b.offset[1]||a.offsetLeft):"auto"!==b.offset&&(a.offsetTop=b.offset,"rb"===b.offset&&(a.offsetTop=d.height()-e[1],a.offsetLeft=d.width()-e[0])),b.fix||(a.offsetTop=/%$/.test(a.offsetTop)?d.height()*parseFloat(a.offsetTop)/100:parseFloat(a.offsetTop),a.offsetLeft=/%$/.test(a.offsetLeft)?d.width()*parseFloat(a.offsetLeft)/100:parseFloat(a.offsetLeft),a.offsetTop+=d.scrollTop(),a.offsetLeft+=d.scrollLeft()),c.css({top:a.offsetTop,left:a.offsetLeft})},g.pt.tips=function(){var a=this,b=a.config,e=a.layero,f=[e.outerWidth(),e.outerHeight()],g=c(b.follow);g[0]||(g=c("body"));var i={width:g.outerWidth(),height:g.outerHeight(),top:g.offset().top,left:g.offset().left},j=e.find(".layui-layer-TipsG"),k=b.tips[0];b.tips[1]||j.remove(),i.autoLeft=function(){i.left+f[0]-d.width()>0?(i.tipLeft=i.left+i.width-f[0],j.css({right:12,left:"auto"})):i.tipLeft=i.left},i.where=[function(){i.autoLeft(),i.tipTop=i.top-f[1]-10,j.removeClass("layui-layer-TipsB").addClass("layui-layer-TipsT").css("border-right-color",b.tips[1])},function(){i.tipLeft=i.left+i.width+10,i.tipTop=i.top,j.removeClass("layui-layer-TipsL").addClass("layui-layer-TipsR").css("border-bottom-color",b.tips[1])},function(){i.autoLeft(),i.tipTop=i.top+i.height+10,j.removeClass("layui-layer-TipsT").addClass("layui-layer-TipsB").css("border-right-color",b.tips[1])},function(){i.tipLeft=i.left-f[0]-10,i.tipTop=i.top,j.removeClass("layui-layer-TipsR").addClass("layui-layer-TipsL").css("border-bottom-color",b.tips[1])}],i.where[k-1](),1===k?i.top-(d.scrollTop()+f[1]+16)<0&&i.where[2]():2===k?d.width()-(i.left+i.width+f[0]+16)>0||i.where[3]():3===k?i.top-d.scrollTop()+i.height+f[1]+16-d.height()>0&&i.where[0]():4===k&&f[0]+16-i.left>0&&i.where[1](),e.find("."+h[5]).css({"background-color":b.tips[1],"padding-right":b.closeBtn?"30px":""}),e.css({left:i.tipLeft,top:i.tipTop})},g.pt.move=function(){var a=this,b=a.config,e={setY:0,moveLayer:function(){var a=e.layero,b=parseInt(a.css("margin-left")),c=parseInt(e.move.css("left"));0===b||(c-=b),"fixed"!==a.css("position")&&(c-=a.parent().offset().left,e.setY=0),a.css({left:c,top:parseInt(e.move.css("top"))-e.setY})}},f=a.layero.find(b.move);return b.move&&f.attr("move","ok"),f.css({cursor:b.move?"move":"auto"}),c(b.move).on("mousedown",function(a){if(a.preventDefault(),"ok"===c(this).attr("move")){e.ismove=!0,e.layero=c(this).parents("."+h[0]);var f=e.layero.offset().left,g=e.layero.offset().top,i=e.layero.outerWidth()-6,j=e.layero.outerHeight()-6;c("#layui-layer-moves")[0]||c("body").append('
'),e.move=c("#layui-layer-moves"),b.moveType&&e.move.css({visibility:"hidden"}),e.moveX=a.pageX-e.move.position().left,e.moveY=a.pageY-e.move.position().top,"fixed"!==e.layero.css("position")||(e.setY=d.scrollTop())}}),c(document).mousemove(function(a){if(e.ismove){var c=a.pageX-e.moveX,f=a.pageY-e.moveY;if(a.preventDefault(),!b.moveOut){e.setY=d.scrollTop();var g=d.width()-e.move.outerWidth(),h=e.setY;0>c&&(c=0),c>g&&(c=g),h>f&&(f=h),f>d.height()-e.move.outerHeight()+e.setY&&(f=d.height()-e.move.outerHeight()+e.setY)}e.move.css({left:c,top:f}),b.moveType&&e.moveLayer(),c=f=g=h=null}}).mouseup(function(){try{e.ismove&&(e.moveLayer(),e.move.remove(),b.moveEnd&&b.moveEnd()),e.ismove=!1}catch(a){e.ismove=!1}}),a},g.pt.callback=function(){function a(){var a=g.cancel&&g.cancel(b.index);a===!1||f.close(b.index)}var b=this,d=b.layero,g=b.config;b.openLayer(),g.success&&(2==g.type?d.find("iframe").on("load",function(){g.success(d,b.index)}):g.success(d,b.index)),f.ie6&&b.IE6(d),d.find("."+h[6]).children("a").on("click",function(){var e=c(this).index();g["btn"+(e+1)]&&g["btn"+(e+1)](b.index,d),0===e?g.yes?g.yes(b.index,d):f.close(b.index):1===e?a():g["btn"+(e+1)]||f.close(b.index)}),d.find("."+h[7]).on("click",a),g.shadeClose&&c("#layui-layer-shade"+b.index).on("click",function(){f.close(b.index)}),d.find(".layui-layer-min").on("click",function(){f.min(b.index,g),g.min&&g.min(d)}),d.find(".layui-layer-max").on("click",function(){c(this).hasClass("layui-layer-maxmin")?(f.restore(b.index),g.restore&&g.restore(d)):(f.full(b.index,g),g.full&&g.full(d))}),g.end&&(e.end[b.index]=g.end)},e.reselect=function(){c.each(c("select"),function(a,b){var d=c(this);d.parents("."+h[0])[0]||1==d.attr("layer")&&c("."+h[0]).length<1&&d.removeAttr("layer").show(),d=null})},g.pt.IE6=function(a){function b(){a.css({top:f+(e.config.fix?d.scrollTop():0)})}var e=this,f=a.offset().top;b(),d.scroll(b),c("select").each(function(a,b){var d=c(this);d.parents("."+h[0])[0]||"none"===d.css("display")||d.attr({layer:"1"}).hide(),d=null})},g.pt.openLayer=function(){var a=this;f.zIndex=a.config.zIndex,f.setTop=function(a){var b=function(){f.zIndex++,a.css("z-index",f.zIndex+1)};return f.zIndex=parseInt(a[0].style.zIndex),a.on("mousedown",b),f.zIndex}},e.record=function(a){var b=[a.outerWidth(),a.outerHeight(),a.position().top,a.position().left+parseFloat(a.css("margin-left"))];a.find(".layui-layer-max").addClass("layui-layer-maxmin"),a.attr({area:b})},e.rescollbar=function(a){h.html.attr("layer-full")==a&&(h.html[0].style.removeProperty?h.html[0].style.removeProperty("overflow"):h.html[0].style.removeAttribute("overflow"),h.html.removeAttr("layer-full"))},a.layer=f,f.getChildFrame=function(a,b){return b=b||c("."+h[4]).attr("times"),c("#"+h[0]+b).find("iframe").contents().find(a)},f.getFrameIndex=function(a){return c("#"+a).parents("."+h[4]).attr("times")},f.iframeAuto=function(a){if(a){var b=f.getChildFrame("html",a).outerHeight(),d=c("#"+h[0]+a),e=d.find(h[1]).outerHeight()||0,g=d.find("."+h[6]).outerHeight()||0;d.css({height:b+e+g}),d.find("iframe").css({height:b})}},f.iframeSrc=function(a,b){c("#"+h[0]+a).find("iframe").attr("src",b)},f.style=function(a,b){var d=c("#"+h[0]+a),f=d.attr("type"),g=d.find(h[1]).outerHeight()||0,i=d.find("."+h[6]).outerHeight()||0;(f===e.type[1]||f===e.type[2])&&(d.css(b),f===e.type[2]&&d.find("iframe").css({height:parseFloat(b.height)-g-i}))},f.min=function(a,b){var d=c("#"+h[0]+a),g=d.find(h[1]).outerHeight()||0;e.record(d),f.style(a,{width:180,height:g,overflow:"hidden"}),d.find(".layui-layer-min").hide(),"page"===d.attr("type")&&d.find(h[4]).hide(),e.rescollbar(a)},f.restore=function(a){var b=c("#"+h[0]+a),d=b.attr("area").split(",");b.attr("type");f.style(a,{width:parseFloat(d[0]),height:parseFloat(d[1]),top:parseFloat(d[2]),left:parseFloat(d[3]),overflow:"visible"}),b.find(".layui-layer-max").removeClass("layui-layer-maxmin"),b.find(".layui-layer-min").show(),"page"===b.attr("type")&&b.find(h[4]).show(),e.rescollbar(a)},f.full=function(a){var b,g=c("#"+h[0]+a);e.record(g),h.html.attr("layer-full")||h.html.css("overflow","hidden").attr("layer-full",a),clearTimeout(b),b=setTimeout(function(){var b="fixed"===g.css("position");f.style(a,{top:b?0:d.scrollTop(),left:b?0:d.scrollLeft(),width:d.width(),height:d.height()}),g.find(".layui-layer-min").hide()},100)},f.title=function(a,b){var d=c("#"+h[0]+(b||f.index)).find(h[1]);d.html(a)},f.close=function(a){var b=c("#"+h[0]+a),d=b.attr("type");if(b[0]){if(d===e.type[1]&&"object"===b.attr("conType")){b.children(":not(."+h[5]+")").remove();for(var g=0;2>g;g++)b.find(".layui-layer-wrap").unwrap().hide()}else{if(d===e.type[2])try{var i=c("#"+h[4]+a)[0];i.contentWindow.document.write(""),i.contentWindow.close(),b.find("."+h[5])[0].removeChild(i)}catch(j){}b[0].innerHTML="",b.remove()}c("#layui-layer-moves, #layui-layer-shade"+a).remove(),f.ie6&&e.reselect(),e.rescollbar(a),c(document).off("keydown",e.enter),"function"==typeof e.end[a]&&e.end[a](),delete e.end[a]}},f.closeAll=function(a){c.each(c("."+h[0]),function(){var b=c(this),d=a?b.attr("type")===a:1;d&&f.close(b.attr("times")),d=null})},e.run=function(){c=jQuery,d=c(a),h.html=c("html"),f.open=function(a){var b=new g(a);return b.index}},"function"==typeof define?define(function(){return e.run(),f}):function(){e.run(),f.use("skin/layer.css")}()}(window);
\ No newline at end of file
diff --git a/ewomail-admin/public/layer2.2/skin/default/icon-ext.png b/ewomail-admin/public/layer2.2/skin/default/icon-ext.png
new file mode 100644
index 0000000..bbbb669
Binary files /dev/null and b/ewomail-admin/public/layer2.2/skin/default/icon-ext.png differ
diff --git a/ewomail-admin/public/layer2.2/skin/default/icon.png b/ewomail-admin/public/layer2.2/skin/default/icon.png
new file mode 100644
index 0000000..3e17da8
Binary files /dev/null and b/ewomail-admin/public/layer2.2/skin/default/icon.png differ
diff --git a/ewomail-admin/public/layer2.2/skin/default/loading-0.gif b/ewomail-admin/public/layer2.2/skin/default/loading-0.gif
new file mode 100644
index 0000000..6f3c953
Binary files /dev/null and b/ewomail-admin/public/layer2.2/skin/default/loading-0.gif differ
diff --git a/ewomail-admin/public/layer2.2/skin/default/loading-1.gif b/ewomail-admin/public/layer2.2/skin/default/loading-1.gif
new file mode 100644
index 0000000..db3a483
Binary files /dev/null and b/ewomail-admin/public/layer2.2/skin/default/loading-1.gif differ
diff --git a/ewomail-admin/public/layer2.2/skin/default/loading-2.gif b/ewomail-admin/public/layer2.2/skin/default/loading-2.gif
new file mode 100644
index 0000000..5bb90fd
Binary files /dev/null and b/ewomail-admin/public/layer2.2/skin/default/loading-2.gif differ
diff --git a/ewomail-admin/public/layer2.2/skin/layer.css b/ewomail-admin/public/layer2.2/skin/layer.css
new file mode 100644
index 0000000..6ff92bb
--- /dev/null
+++ b/ewomail-admin/public/layer2.2/skin/layer.css
@@ -0,0 +1,682 @@
+/*!
+
+ @Name: layer's style
+ @Author: 拼图响应式前端CSS框架,作者-大火兔在贤心基础上调整
+ @Site: www.pintuer.com
+
+ */
+
+*html {
+ background-image: url(about:blank);
+ background-attachment: fixed;
+}
+html #layui_layer_skinlayercss {
+ display: none;
+ position: absolute;
+ width: 1989px;
+}
+/* common */
+
+.layui-layer-shade,
+.layui-layer {
+ position: fixed;
+ _position: absolute;
+ pointer-events: auto;
+}
+.layui-layer-shade {
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ _height: expression(document.body.offsetHeight+"px");
+}
+.layui-layer {
+ top: 150px;
+ left: 50%;
+ margin: 0;
+ padding: 0;
+ background-color: #fff;
+ -webkit-background-clip: content;
+ border: 1px solid #ddd;
+ box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+ border-radius: 4px;
+ background-color: #fff;
+}
+.layui-layer-close {
+ position: absolute;
+}
+.layui-layer-content {
+ position: relative;
+}
+.layui-layer-border {
+ border: 1px solid #B2B2B2;
+ border: 1px solid rgba(0, 0, 0, .3);
+ box-shadow: 1px 1px 5px rgba(0, 0, 0, .2);
+}
+.layui-layer-moves {
+ position: absolute;
+ border: 3px solid #666;
+ border: 3px solid rgba(0, 0, 0, .5);
+ cursor: move;
+ background-color: #fff;
+ background-color: rgba(255, 255, 255, .3);
+ filter: alpha(opacity=50);
+}
+.layui-layer-load {
+ background: url(default/loading-0.gif) #fff center center no-repeat;
+}
+.layui-layer-ico {
+ background: url(default/icon.png) no-repeat;
+}
+.layui-layer-dialog .layui-layer-ico,
+.layui-layer-setwin a,
+.layui-layer-btn a {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+ vertical-align: top;
+}
+/* 动画 */
+
+.layui-layer {
+ border-radius: 2px;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-duration: .3s;
+ animation-duration: .3s;
+}
+@-webkit-keyframes bounceIn {
+ /* 默认 */
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale(.5);
+ transform: scale(.5)
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: scale(1);
+ transform: scale(1)
+ }
+}
+@keyframes bounceIn {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale(.5);
+ -ms-transform: scale(.5);
+ transform: scale(.5)
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: scale(1);
+ -ms-transform: scale(1);
+ transform: scale(1)
+ }
+}
+.layui-anim {
+ -webkit-animation-name: bounceIn;
+ animation-name: bounceIn
+}
+@-webkit-keyframes bounceOut {
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale(.7);
+ transform: scale(.7)
+ }
+ 30% {
+ -webkit-transform: scale(1.03);
+ transform: scale(1.03)
+ }
+ 0% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ }
+}
+@keyframes bounceOut {
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale(.7);
+ -ms-transform: scale(.7);
+ transform: scale(.7)
+ }
+ 30% {
+ -webkit-transform: scale(1.03);
+ -ms-transform: scale(1.03);
+ transform: scale(1.03)
+ }
+ 0% {
+ -webkit-transform: scale(1);
+ -ms-transform: scale(1);
+ transform: scale(1)
+ }
+}
+.layui-anim-close {
+ -webkit-animation-name: bounceOut;
+ animation-name: bounceOut;
+ -webkit-animation-duration: .2s;
+ animation-duration: .2s;
+}
+@-webkit-keyframes zoomInDown {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale(.1) translateY(-2000px);
+ transform: scale(.1) translateY(-2000px);
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out
+ }
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale(.475) translateY(60px);
+ transform: scale(.475) translateY(60px);
+ -webkit-animation-timing-function: ease-out;
+ animation-timing-function: ease-out
+ }
+}
+@keyframes zoomInDown {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale(.1) translateY(-2000px);
+ -ms-transform: scale(.1) translateY(-2000px);
+ transform: scale(.1) translateY(-2000px);
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out
+ }
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale(.475) translateY(60px);
+ -ms-transform: scale(.475) translateY(60px);
+ transform: scale(.475) translateY(60px);
+ -webkit-animation-timing-function: ease-out;
+ animation-timing-function: ease-out
+ }
+}
+.layui-anim-01 {
+ -webkit-animation-name: zoomInDown;
+ animation-name: zoomInDown
+}
+@-webkit-keyframes fadeInUpBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translateY(2000px);
+ transform: translateY(2000px)
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: translateY(0);
+ transform: translateY(0)
+ }
+}
+@keyframes fadeInUpBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translateY(2000px);
+ -ms-transform: translateY(2000px);
+ transform: translateY(2000px)
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: translateY(0);
+ -ms-transform: translateY(0);
+ transform: translateY(0)
+ }
+}
+.layui-anim-02 {
+ -webkit-animation-name: fadeInUpBig;
+ animation-name: fadeInUpBig
+}
+@-webkit-keyframes zoomInLeft {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale(.1) translateX(-2000px);
+ transform: scale(.1) translateX(-2000px);
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out
+ }
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale(.475) translateX(48px);
+ transform: scale(.475) translateX(48px);
+ -webkit-animation-timing-function: ease-out;
+ animation-timing-function: ease-out
+ }
+}
+@keyframes zoomInLeft {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale(.1) translateX(-2000px);
+ -ms-transform: scale(.1) translateX(-2000px);
+ transform: scale(.1) translateX(-2000px);
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out
+ }
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale(.475) translateX(48px);
+ -ms-transform: scale(.475) translateX(48px);
+ transform: scale(.475) translateX(48px);
+ -webkit-animation-timing-function: ease-out;
+ animation-timing-function: ease-out
+ }
+}
+.layui-anim-03 {
+ -webkit-animation-name: zoomInLeft;
+ animation-name: zoomInLeft
+}
+@-webkit-keyframes rollIn {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translateX(-100%) rotate(-120deg);
+ transform: translateX(-100%) rotate(-120deg)
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: translateX(0px) rotate(0deg);
+ transform: translateX(0px) rotate(0deg)
+ }
+}
+@keyframes rollIn {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translateX(-100%) rotate(-120deg);
+ -ms-transform: translateX(-100%) rotate(-120deg);
+ transform: translateX(-100%) rotate(-120deg)
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: translateX(0px) rotate(0deg);
+ -ms-transform: translateX(0px) rotate(0deg);
+ transform: translateX(0px) rotate(0deg)
+ }
+}
+.layui-anim-04 {
+ -webkit-animation-name: rollIn;
+ animation-name: rollIn
+}
+@keyframes fadeIn {
+ 0% {
+ opacity: 0
+ }
+ 100% {
+ opacity: 1
+ }
+}
+.layui-anim-05 {
+ -webkit-animation-name: fadeIn;
+ animation-name: fadeIn
+}
+@-webkit-keyframes shake {
+ 0%, 100% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0)
+ }
+ 10%,
+ 30%,
+ 50%,
+ 70%,
+ 90% {
+ -webkit-transform: translateX(-10px);
+ transform: translateX(-10px)
+ }
+ 20%,
+ 40%,
+ 60%,
+ 80% {
+ -webkit-transform: translateX(10px);
+ transform: translateX(10px)
+ }
+}
+@keyframes shake {
+ 0%, 100% {
+ -webkit-transform: translateX(0);
+ -ms-transform: translateX(0);
+ transform: translateX(0)
+ }
+ 10%,
+ 30%,
+ 50%,
+ 70%,
+ 90% {
+ -webkit-transform: translateX(-10px);
+ -ms-transform: translateX(-10px);
+ transform: translateX(-10px)
+ }
+ 20%,
+ 40%,
+ 60%,
+ 80% {
+ -webkit-transform: translateX(10px);
+ -ms-transform: translateX(10px);
+ transform: translateX(10px)
+ }
+}
+.layui-anim-06 {
+ -webkit-animation-name: shake;
+ animation-name: shake
+}
+@-webkit-keyframes fadeIn {
+ 0% {
+ opacity: 0
+ }
+ 100% {
+ opacity: 1
+ }
+}
+/* 标题栏 */
+
+.layui-layer-title {
+ padding: 0 80px 0 20px;
+ height: 42px;
+ line-height: 42px;
+ border-bottom: 1px solid #ddd;
+ font-size: 16px;
+ color: #333;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ background-color: #F8F8F8;
+ border-radius: 2px 2px 0 0;
+}
+.layui-layer-setwin {
+ position: absolute;
+ right: 15px;
+ *right: 0;
+ top: 15px;
+ font-size: 0;
+ line-height: initial;
+}
+.layui-layer-setwin a {
+ position: relative;
+ width: 16px;
+ height: 16px;
+ margin-left: 10px;
+ font-size: 12px;
+ _overflow: hidden;
+}
+.layui-layer-setwin .layui-layer-min cite {
+ position: absolute;
+ width: 14px;
+ height: 2px;
+ left: 0;
+ top: 50%;
+ margin-top: -1px;
+ background-color: #2E2D3C;
+ cursor: pointer;
+ _overflow: hidden;
+}
+.layui-layer-setwin .layui-layer-min:hover cite {
+ background-color: #2D93CA;
+}
+.layui-layer-setwin .layui-layer-max {
+ background-position: -32px -40px;
+}
+.layui-layer-setwin .layui-layer-max:hover {
+ background-position: -16px -40px;
+}
+.layui-layer-setwin .layui-layer-maxmin {
+ background-position: -65px -40px;
+}
+.layui-layer-setwin .layui-layer-maxmin:hover {
+ background-position: -49px -40px;
+}
+.layui-layer-setwin .layui-layer-close1 {
+ background-position: 0 -40px;
+ cursor: pointer;
+}
+.layui-layer-setwin .layui-layer-close1:hover {
+ opacity: 0.7;
+}
+.layui-layer-setwin .layui-layer-close2 {
+ position: absolute;
+ right: -28px;
+ top: -28px;
+ width: 30px;
+ height: 30px;
+ margin-left: 0;
+ background-position: -149px -31px;
+ *right: -18px;
+ _display: none;
+}
+.layui-layer-setwin .layui-layer-close2:hover {
+ background-position: -180px -31px;
+}
+/* 按钮栏 */
+
+.layui-layer-btn {
+ text-align: right;
+ padding: 0 10px 12px;
+ pointer-events: auto;
+}
+.layui-layer-btn a {
+ height: 28px;
+ line-height: 28px;
+ margin: 0 6px;
+ padding: 0 15px;
+ border: 1px #dedede solid;
+ background-color: #f1f1f1;
+ color: #333;
+ border-radius: 2px;
+ font-weight: 400;
+ cursor: pointer;
+ text-decoration: none;
+}
+.layui-layer-btn a:hover {
+ opacity: 0.9;
+ text-decoration: none;
+}
+.layui-layer-btn a:active {
+ opacity: 0.7;
+}
+.layui-layer-btn .layui-layer-btn0 {
+ border-color: #2c7;
+ background-color: #2c7;
+ color: #fff;
+}
+/* 定制化 */
+
+.layui-layer-dialog {
+ min-width: 260px;
+ border: 1px solid #ddd;
+ box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+ border-radius: 4px;
+ background-color: #fff;
+}
+.layui-layer-dialog .layui-layer-content {
+ position: relative;
+ padding: 20px;
+ line-height: 24px;
+ word-break: break-all;
+ overflow: hidden;
+ font-size: 14px;
+ overflow: auto;
+}
+.layui-layer-dialog .layui-layer-content .layui-layer-ico {
+ position: absolute;
+ top: 16px;
+ left: 15px;
+ _left: -40px;
+ width: 30px;
+ height: 30px;
+}
+.layui-layer-ico1 {
+ background-position: -30px 0
+}
+.layui-layer-ico2 {
+ background-position: -60px 0;
+}
+.layui-layer-ico3 {
+ background-position: -90px 0;
+}
+.layui-layer-ico4 {
+ background-position: -120px 0;
+}
+.layui-layer-ico5 {
+ background-position: -150px 0;
+}
+.layui-layer-ico6 {
+ background-position: -180px 0;
+}
+.layui-layer-rim {
+ border: 1px solid #ddd;
+ box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+ border-radius: 4px;
+ background-color: #fff;
+}
+.layui-layer-msg {
+ min-width: 180px;
+ border: 1px solid #ddd;
+ box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+ border-radius: 4px;
+ background-color: #fff;
+}
+.layui-layer-hui {
+ min-width: 100px;
+ background-color: #000;
+ filter: alpha(opacity=60);
+ background-color: rgba(0, 0, 0, 0.6);
+ color: #fff;
+ border: none;
+ box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+ border-radius: 4px;
+}
+.layui-layer-hui .layui-layer-content {
+ padding: 12px 25px;
+ text-align: center;
+}
+.layui-layer-dialog .layui-layer-padding {
+ padding: 20px 20px 20px 55px;
+ text-align: left;
+}
+.layui-layer-page .layui-layer-content {
+ position: relative;
+ overflow: auto;
+}
+.layui-layer-page .layui-layer-btn,
+.layui-layer-iframe .layui-layer-btn {
+ padding-top: 10px;
+}
+.layui-layer-nobg {
+ background: none;
+}
+.layui-layer-iframe .layui-layer-content {
+ overflow: hidden;
+}
+.layui-layer-iframe iframe {
+ display: block;
+ width: 100%;
+ border: 1px solid #ddd;
+ box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+ border-radius: 4px;
+ background-color: #fff;
+}
+.layui-layer-loading {
+ border-radius: 100%;
+ background: none;
+ box-shadow: none;
+ border: none;
+}
+.layui-layer-loading .layui-layer-content {
+ width: 60px;
+ height: 24px;
+ background: url(default/loading-0.gif) no-repeat;
+}
+.layui-layer-loading .layui-layer-loading1 {
+ width: 37px;
+ height: 37px;
+ background: url(default/loading-1.gif) no-repeat;
+}
+.layui-layer-loading .layui-layer-loading2,
+.layui-layer-ico16 {
+ width: 32px;
+ height: 32px;
+ background: url(default/loading-2.gif) no-repeat;
+}
+.layui-layer-tips {
+ background: none;
+ box-shadow: none;
+ border: none;
+ box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+ border-radius: 4px;
+ background-color: #fff;
+}
+.layui-layer-tips .layui-layer-content {
+ position: relative;
+ line-height: 22px;
+ min-width: 12px;
+ padding: 5px 10px;
+ font-size: 12px;
+ _float: left;
+ border-radius: 3px;
+ box-shadow: 1px 1px 3px rgba(0, 0, 0, .3);
+ background-color: #FF9900;
+ color: #fff;
+}
+.layui-layer-tips .layui-layer-close {
+ right: -2px;
+ top: -1px;
+}
+.layui-layer-tips i.layui-layer-TipsG {
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-width: 8px;
+ border-color: transparent;
+ border-style: dashed;
+ *overflow: hidden;
+}
+.layui-layer-tips i.layui-layer-TipsT,
+.layui-layer-tips i.layui-layer-TipsB {
+ left: 5px;
+ border-right-style: solid;
+ border-right-color: #FF9900;
+}
+.layui-layer-tips i.layui-layer-TipsT {
+ bottom: -8px;
+}
+.layui-layer-tips i.layui-layer-TipsB {
+ top: -8px;
+}
+.layui-layer-tips i.layui-layer-TipsR,
+.layui-layer-tips i.layui-layer-TipsL {
+ top: 1px;
+ border-bottom-style: solid;
+ border-bottom-color: #FF9900;
+}
+.layui-layer-tips i.layui-layer-TipsR {
+ left: -8px;
+}
+.layui-layer-tips i.layui-layer-TipsL {
+ right: -8px;
+}
+/* skin */
+
+.layui-layer-lan[type="dialog"] {
+ min-width: 280px;
+}
+.layui-layer-lan .layui-layer-title {
+ background: #4476A7;
+ color: #fff;
+ border: none;
+}
+.layui-layer-lan .layui-layer-lan .layui-layer-btn {
+ padding: 10px;
+ text-align: right;
+ border-top: 1px solid #E9E7E7
+}
+.layui-layer-lan .layui-layer-btn a {
+ background: #BBB5B5;
+ border: none;
+}
+.layui-layer-lan .layui-layer-btn .layui-layer-btn1 {
+ background: #C9C5C5;
+}
+.layui-layer-molv .layui-layer-title {
+ background: #009f95;
+ color: #fff;
+ border: none;
+}
+.layui-layer-molv .layui-layer-btn a {
+ background: #009f95;
+}
+.layui-layer-molv .layui-layer-btn .layui-layer-btn1 {
+ background: #92B8B1;
+}
\ No newline at end of file
diff --git a/ewomail-admin/public/layer2.2/skin/layer.ext.css b/ewomail-admin/public/layer2.2/skin/layer.ext.css
new file mode 100644
index 0000000..9ac14e4
--- /dev/null
+++ b/ewomail-admin/public/layer2.2/skin/layer.ext.css
@@ -0,0 +1,199 @@
+/*!
+
+ @Name: layer拓展样式
+ @Date: 2012.12.13
+ @Author: 拼图响应式前端CSS框架,作者-大火兔在贤心基础上调整
+ @blog: www.pintuer.com
+
+ */
+
+.layui-layer-imgbar,
+.layui-layer-imgtit a,
+.layui-layer-tab .layui-layer-title span {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.layui-layer-iconext {
+ background: url(default/icon-ext.png) no-repeat;
+}
+
+html #layui_layer_skinlayerextcss {
+ display: none;
+ position: absolute;
+ width: 1989px;
+}
+
+.layui-layer-prompt .layui-layer-input {
+ display: block;
+ width: 220px;
+ height: 30px;
+ margin: 0 auto;
+ line-height: 30px;
+ padding: 0 5px;
+ border: 1px solid #ccc;
+ box-shadow: 1px 1px 5px rgba(0, 0, 0, .1) inset;
+ color: #333;
+}
+
+.layui-layer-prompt textarea.layui-layer-input {
+ width: 300px;
+ height: 100px;
+ line-height: 20px;
+}
+
+.layui-layer-tab {
+ border: 1px solid #ddd;
+ box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+ border-radius: 4px;
+ background-color: #fff;
+}
+
+ .layui-layer-tab .layui-layer-title {
+ padding-left: 0;
+ border-bottom: 1px solid #ccc;
+ background-color: #eee;
+ overflow: visible;
+ }
+
+ .layui-layer-tab .layui-layer-title span {
+ position: relative;
+ float: left;
+ min-width: 80px;
+ max-width: 260px;
+ padding: 0 20px;
+ text-align: center;
+ cursor: default;
+ overflow: hidden;
+ }
+
+ .layui-layer-tab .layui-layer-title span.layui-layer-tabnow {
+ height: 43px;
+ border-left: 1px solid #ccc;
+ border-right: 1px solid #ccc;
+ background-color: #fff;
+ z-index: 10;
+ }
+
+ .layui-layer-tab .layui-layer-title span:first-child {
+ border-left: none;
+ }
+
+.layui-layer-tabmain {
+ line-height: 24px;
+ clear: both;
+}
+
+ .layui-layer-tabmain .layui-layer-tabli {
+ display: none;
+ }
+
+ .layui-layer-tabmain .layui-layer-tabli.xubox_tab_layer {
+ display: block;
+ }
+
+.xubox_tabclose {
+ position: absolute;
+ right: 10px;
+ top: 5px;
+ cursor: pointer;
+}
+
+.layui-layer-photos {
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ background: url(default/xubox_loading1.gif) center center no-repeat #000;
+}
+
+ .layui-layer-photos .layui-layer-content {
+ overflow: hidden;
+ text-align: center;
+ }
+
+ .layui-layer-photos .layui-layer-phimg img {
+ position: relative;
+ width: 100%;
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+ vertical-align: top;
+ }
+
+.layui-layer-imgbar,
+.layui-layer-imguide {
+ display: none;
+}
+
+.layui-layer-imgnext,
+.layui-layer-imgprev {
+ position: absolute;
+ top: 50%;
+ width: 27px;
+ _width: 44px;
+ height: 44px;
+ margin-top: -22px;
+ outline: 0;
+ blr: expression(this.onFocus=this.blur());
+}
+
+.layui-layer-imgprev {
+ left: 10px;
+ background-position: -5px -5px;
+ _background-position: -70px -5px;
+}
+
+ .layui-layer-imgprev:hover {
+ background-position: -33px -5px;
+ _background-position: -120px -5px;
+ }
+
+.layui-layer-imgnext {
+ right: 10px;
+ _right: 8px;
+ background-position: -5px -50px;
+ _background-position: -70px -50px;
+}
+
+ .layui-layer-imgnext:hover {
+ background-position: -33px -50px;
+ _background-position: -120px -50px;
+ }
+
+.layui-layer-imgbar {
+ position: absolute;
+ left: 0;
+ bottom: 0;
+ width: 100%;
+ height: 32px;
+ line-height: 32px;
+ background-color: rgba(0, 0, 0, .8);
+ background-color: #000\9;
+ filter: Alpha(opacity=80);
+ color: #fff;
+ overflow: hidden;
+ font-size: 0;
+}
+
+.layui-layer-imgtit * {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+ vertical-align: top;
+ font-size: 12px;
+}
+
+.layui-layer-imgtit a {
+ max-width: 65%;
+ overflow: hidden;
+ color: #fff;
+}
+
+ .layui-layer-imgtit a:hover {
+ color: #fff;
+ text-decoration: underline;
+ }
+
+.layui-layer-imgtit em {
+ padding-left: 10px;
+ font-style: normal;
+}
diff --git a/ewomail-admin/public/pintuer.css b/ewomail-admin/public/pintuer.css
new file mode 100644
index 0000000..172681f
--- /dev/null
+++ b/ewomail-admin/public/pintuer.css
@@ -0,0 +1,9799 @@
+/*重设*/
+html {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+
+body,
+div,
+span,
+object,
+iframe,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p,
+blockquote,
+pre,
+a,
+abbr,
+acronym,
+address,
+code,
+del,
+dfn,
+em,
+q,
+dl,
+dt,
+dd,
+ol,
+ul,
+li,
+fieldset,
+form,
+legend,
+caption,
+tbody,
+tfoot,
+thead,
+article,
+aside,
+dialog,
+figure,
+footer,
+header,
+hgroup,
+nav,
+section {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 14px;
+ font: inherit;
+ vertical-align: baseline;
+}
+
+article,
+aside,
+details,
+figcaption,
+figure,
+dialog,
+footer,
+header,
+hgroup,
+menu,
+nav,
+section {
+ display: block;
+}
+
+body {
+ font-size: 14px;
+ color: #333;
+ background: #fff;
+ font-family: "Microsoft YaHei", "simsun", "Helvetica Neue", Arial, Helvetica, sans-serif;
+}
+
+img {
+ border: 0;
+ vertical-align: bottom;
+}
+
+::-webkit-input-placeholder {
+ color: #999;
+}
+
+:-moz-placeholder {
+ color: #999;
+}
+
+::-moz-placeholder {
+ color: #999;
+}
+
+:-ms-input-placeholder {
+ color: #ccc;
+}
+
+* {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+*:before,
+*:after {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+
+textarea {
+ overflow: auto;
+}
+
+input:focus,
+textarea:focus,
+button:focus,
+select:focus {
+ outline: none;
+}
+
+input::-ms-clear {
+ display: none;
+}
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+nav,
+section,
+summary {
+ display: block;
+}
+
+audio,
+canvas,
+progress,
+video {
+ display: inline-block;
+ vertical-align: baseline;
+}
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+[hidden],
+template {
+ display: none;
+}
+
+a {
+ background: transparent;
+}
+
+a:active,
+a:hover {
+ outline: 0;
+}
+
+a:focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+b,
+strong {
+ font-weight: bold;
+}
+
+dfn {
+ font-style: italic;
+}
+
+mark {
+ color: #000;
+ background: #ff0;
+}
+
+small {
+ font-size: 80%;
+}
+
+sub,
+sup {
+ position: relative;
+ font-size: 75%;
+ line-height: 0;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -.5em;
+}
+
+sub {
+ bottom: -.25em;
+}
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+figure {
+ margin: 1em 40px;
+}
+
+hr {
+ height: 0;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+
+pre {
+ overflow: auto;
+}
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, monospace;
+ font-size: 1em;
+}
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ margin: 0;
+ font: inherit;
+}
+
+button {
+ overflow: visible;
+}
+
+button,
+select {
+ text-transform: none;
+}
+
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button;
+ cursor: pointer;
+}
+
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+
+input {
+ line-height: normal;
+}
+
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box;
+ padding: 0;
+}
+
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+input[type="search"] {
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ -webkit-appearance: textfield;
+}
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+fieldset {
+ padding: .35em .625em .75em;
+ margin: 0 2px;
+ border: 1px solid #c0c0c0;
+}
+
+legend {
+ padding: 0;
+ border: 0;
+}
+
+optgroup {
+ font-weight: bold;
+}
+
+table {
+ border-spacing: 0;
+ border-collapse: collapse;
+}
+
+td,
+th {
+ padding: 0;
+}
+
+
+/*按钮*/
+
+.button {
+ border: solid 1px #ddd;
+ background: transparent;
+ border-radius: 4px;
+ font-size: 14px;
+ padding: 6px 15px;
+ margin: 0;
+ display: inline-block;
+ line-height: 20px;
+ transition: all 1s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+}
+
+.button[disabled] {
+ pointer-events: none;
+ cursor: not-allowed;
+ webkit-box-shadow: none;
+ box-shadow: none;
+ filter: alpha(opacity=50);
+ opacity: .5;
+}
+
+.button:active {
+ background-image: none;
+ outline: 0;
+ transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+}
+
+.button:hover {
+ transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+}
+
+.button-block {
+ display: block;
+ width: 100%;
+}
+
+.button-large {
+ padding: 15px 20px;
+ font-size: 24px;
+ line-height: 24px;
+}
+
+.button-big {
+ padding: 10px 15px;
+ font-size: 18px;
+ line-height: 22px;
+}
+
+.button-small {
+ padding: 5px 10px;
+ font-size: 12px;
+ font-weight: normal;
+ line-height: 18px;
+}
+
+.button-little {
+ padding: 3px 5px;
+ font-size: 12px;
+ font-weight: normal;
+ line-height: 16px;
+}
+
+.button.bg-main,
+.button.bg-sub,
+.button.bg-dot,
+.button.bg-black,
+.button.bg-gray,
+.button.bg-red,
+.button.bg-yellow,
+.button.bg-blue,
+.button.bg-green {
+ color: #fff;
+}
+
+
+/*-----------------------元件--------------------------*/
+
+
+/*容器*/
+
+.layout {
+ width: 100%;
+}
+
+.container,
+.container-layout {
+ margin: 0 auto;
+ padding: 0 10px;
+}
+
+@media (min-width: 760px) {
+ .container {
+ width: 750px;
+ }
+}
+
+@media (min-width: 1000px) {
+ .container {
+ width: 1000px;
+ }
+}
+
+@media (min-width: 1200px) {
+ .container {
+ width: 1200px;
+ }
+}
+
+
+/*网格*/
+
+
+/*默认x,大xb,中xm,小xs*/
+
+.line {
+ margin: 0;
+ padding: 0;
+}
+
+.x1,
+.x2,
+.x3,
+.x4,
+.x5,
+.x6,
+.x7,
+.x8,
+.x9,
+.x10,
+.x11,
+.x12,
+.xl1,
+.xl2,
+.xl3,
+.xl4,
+.xl5,
+.xl6,
+.xl7,
+.xl8,
+.xl9,
+.xl10,
+.xl11,
+.xl12,
+.xs1,
+.xs2,
+.xs3,
+.xs4,
+.xs5,
+.xs6,
+.xs7,
+.xs8,
+.xs9,
+.xs10,
+.xs11,
+.xs12,
+.xm1,
+.xm2,
+.xm3,
+.xm4,
+.xm5,
+.xm6,
+.xm7,
+.xm8,
+.xm9,
+.xm10,
+.xm11,
+.xm12,
+.xb1,
+.xb2,
+.xb3,
+.xb4,
+.xb5,
+.xb6,
+.xb7,
+.xb8,
+.xb9,
+.xb10,
+.xb11,
+.xb12 {
+ position: relative;
+ min-height: 1px;
+}
+
+.line-big {
+ margin-left: -10px;
+ margin-right: -10px;
+}
+
+.line-big .x1,
+.line-big .x2,
+.line-big .x3,
+.line-big .x4,
+.line-big .x5,
+.line-big .x6,
+.line-big .x7,
+.line-big .x8,
+.line-big .x9,
+.line-big .x10,
+.line-big .x11,
+.line-big .x12,
+.line-big .xl1,
+.line-big .xl2,
+.line-big .xl3,
+.line-big .xl4,
+.line-big .xl5,
+.line-big .xl6,
+.line-big .xl7,
+.line-big .xl8,
+.line-big .xl9,
+.line-big .xl10,
+.line-big .xl11,
+.line-big .xl12,
+.line-big .xs1,
+.line-big .xs2,
+.line-big .xs3,
+.line-big .xs4,
+.line-big .xs5,
+.line-big .xs6,
+.line-big .xs7,
+.line-big .xs8,
+.line-big .xs9,
+.line-big .xs10,
+.line-big .xs11,
+.line-big .xs12,
+.line-big .xm1,
+.line-big .xm2,
+.line-big .xm3,
+.line-big .xm4,
+.line-big .xm5,
+.line-big .xm6,
+.line-big .xm7,
+.line-big .xm8,
+.line-big .xm9,
+.line-big .xm10,
+.line-big .xm11,
+.line-big .xm12,
+.line-big .xb1,
+.line-big .xb2,
+.line-big .xb3,
+.line-big .xb4,
+.line-big .xb5,
+.line-big .xb6,
+.line-big .xb7,
+.line-big .xb8,
+.line-big .xb9,
+.line-big .xb10,
+.line-big .xb11,
+.line-big .xb12 {
+ position: relative;
+ min-height: 1px;
+ padding-right: 10px;
+ padding-left: 10px;
+}
+
+.line-middle {
+ margin-left: -5px;
+ margin-right: -5px;
+}
+
+.line-middle .x1,
+.line-middle .x2,
+.line-middle .x3,
+.line-middle .x4,
+.line-middle .x5,
+.line-middle .x6,
+.line-middle .x7,
+.line-middle .x8,
+.line-middle .x9,
+.line-middle .x10,
+.line-middle .x11,
+.line-middle .x12,
+.line-middle .xl1,
+.line-middle .xl2,
+.line-middle .xl3,
+.line-middle .xl4,
+.line-middle .xl5,
+.line-middle .xl6,
+.line-middle .xl7,
+.line-middle .xl8,
+.line-middle .xl9,
+.line-middle .xl10,
+.line-middle .xl11,
+.line-middle .xl12,
+.line-middle .xs1,
+.line-middle .xs2,
+.line-middle .xs3,
+.line-middle .xs4,
+.line-middle .xs5,
+.line-middle .xs6,
+.line-middle .xs7,
+.line-middle .xs8,
+.line-middle .xs9,
+.line-middle .xs10,
+.line-middle .xs11,
+.line-middle .xs12,
+.line-middle .xm1,
+.line-middle .xm2,
+.line-middle .xm3,
+.line-middle .xm4,
+.line-middle .xm5,
+.line-middle .xm6,
+.line-middle .xm7,
+.line-middle .xm8,
+.line-middle .xm9,
+.line-middle .xm10,
+.line-middle .xm11,
+.line-middle .xm12,
+.line-middle .xb1,
+.line-middle .xb2,
+.line-middle .xb3,
+.line-middle .xb4,
+.line-middle .xb5,
+.line-middle .xb6,
+.line-middle .xb7,
+.line-middle .xb8,
+.line-middle .xb9,
+.line-middle .xb10,
+.line-middle .xb11,
+.line-middle .xb12 {
+ position: relative;
+ min-height: 1px;
+ padding-right: 5px;
+ padding-left: 5px;
+}
+
+.line-small {
+ margin-left: -2px;
+ margin-right: -2px;
+}
+
+.line-small .x1,
+.line-small .x2,
+.line-small .x3,
+.line-small .x4,
+.line-small .x5,
+.line-small .x6,
+.line-small .x7,
+.line-small .x8,
+.line-small .x9,
+.line-small .x10,
+.line-small .x11,
+.line-small .x12,
+.line-small .xl1,
+.line-small .xl2,
+.line-small .xl3,
+.line-small .xl4,
+.line-small .xl5,
+.line-small .xl6,
+.line-small .xl7,
+.line-small .xl8,
+.line-small .xl9,
+.line-small .xl10,
+.line-small .xl11,
+.line-small .xl12,
+.line-small .xs1,
+.line-small .xs2,
+.line-small .xs3,
+.line-small .xs4,
+.line-small .xs5,
+.line-small .xs6,
+.line-small .xs7,
+.line-small .xs8,
+.line-small .xs9,
+.line-small .xs10,
+.line-small .xs11,
+.line-small .xs12,
+.line-small .xm1,
+.line-small .xm2,
+.line-small .xm3,
+.line-small .xm4,
+.line-small .xm5,
+.line-small .xm6,
+.line-small .xm7,
+.line-small .xm8,
+.line-small .xm9,
+.line-small .xm10,
+.line-small .xm11,
+.line-small .xm12,
+.line-small .xb1,
+.line-small .xb2,
+.line-small .xb3,
+.line-small .xb4,
+.line-small .xb5,
+.line-small .xb6,
+.line-small .xb7,
+.line-small .xb8,
+.line-small .xb9,
+.line-small .xb10,
+.line-small .xb11,
+.line-small .xb12 {
+ position: relative;
+ min-height: 1px;
+ padding-right: 2px;
+ padding-left: 2px;
+}
+
+.x1,
+.x2,
+.x3,
+.x4,
+.x5,
+.x6,
+.x7,
+.x8,
+.x9,
+.x10,
+.x11,
+.x12 {
+ float: left;
+}
+
+.x1 {
+ width: 8.33333333%;
+}
+
+.x2 {
+ width: 16.66666667%;
+}
+
+.x3 {
+ width: 25%;
+}
+
+.x4 {
+ width: 33.33333333%;
+}
+
+.x5 {
+ width: 41.66666667%;
+}
+
+.x6 {
+ width: 50%;
+}
+
+.x7 {
+ width: 58.33333333%;
+}
+
+.x8 {
+ width: 66.66666667%;
+}
+
+.x9 {
+ width: 75%;
+}
+
+.x10 {
+ width: 83.33333333%;
+}
+
+.x11 {
+ width: 91.66666667%;
+}
+
+.x12 {
+ width: 100%;
+}
+
+.x0-left {
+ left: 0;
+}
+
+.x1-left {
+ left: 8.33333333%;
+}
+
+.x2-left {
+ left: 16.66666667%;
+}
+
+.x3-left {
+ left: 25%;
+}
+
+.x4-left {
+ left: 33.33333333%;
+}
+
+.x5-left {
+ left: 41.66666667%;
+}
+
+.x6-left {
+ left: 50%;
+}
+
+.x7-left {
+ left: 58.33333333%;
+}
+
+.x8-left {
+ left: 66.66666667%;
+}
+
+.x9-left {
+ left: 75%;
+}
+
+.x10-left {
+ left: 83.33333333%;
+}
+
+.x11-left {
+ left: 91.66666667%;
+}
+
+.x12-left {
+ left: 100%;
+}
+
+.x0-right {
+ right: 0;
+}
+
+.x1-right {
+ right: 8.33333333%;
+}
+
+.x2-right {
+ right: 16.66666667%;
+}
+
+.x3-right {
+ right: 25%;
+}
+
+.x4-right {
+ right: 33.33333333%;
+}
+
+.x5-right {
+ right: 41.66666667%;
+}
+
+.x6-right {
+ right: 50%;
+}
+
+.x7-right {
+ right: 58.33333333%;
+}
+
+.x8-right {
+ right: 66.66666667%;
+}
+
+.x9-right {
+ right: 75%;
+}
+
+.x10-right {
+ right: 83.33333333%;
+}
+
+.x11-right {
+ right: 91.66666667%;
+}
+
+.x12-right {
+ right: 100%;
+}
+
+.x0-move {
+ margin-left: 0;
+}
+
+.x1-move {
+ margin-left: 8.33333333%;
+}
+
+.x2-move {
+ margin-left: 16.66666667%;
+}
+
+.x3-move {
+ margin-left: 25%;
+}
+
+.x4-move {
+ margin-left: 33.33333333%;
+}
+
+.x5-move {
+ margin-left: 41.66666667%;
+}
+
+.x6-move {
+ margin-left: 50%;
+}
+
+.x7-move {
+ margin-left: 58.33333333%;
+}
+
+.x8-move {
+ margin-left: 66.66666667%;
+}
+
+.x9-move {
+ margin-left: 75%;
+}
+
+.x10-move {
+ margin-left: 83.33333333%;
+}
+
+.x11-move {
+ margin-left: 91.66666667%;
+}
+
+.x12-move {
+ margin-left: 100%;
+}
+
+@media (min-width: 300px) {
+ .xl1,
+ .xl2,
+ .xl3,
+ .xl4,
+ .xl5,
+ .xl6,
+ .xl7,
+ .xl8,
+ .xl9,
+ .xl10,
+ .xl11,
+ .xl12 {
+ float: left;
+ }
+ .xl1 {
+ width: 8.33333333%;
+ }
+ .xl2 {
+ width: 16.66666667%;
+ }
+ .xl3 {
+ width: 25%;
+ }
+ .xl4 {
+ width: 33.33333333%;
+ }
+ .xl5 {
+ width: 41.66666667%;
+ }
+ .xl6 {
+ width: 50%;
+ }
+ .xl7 {
+ width: 58.33333333%;
+ }
+ .xl8 {
+ width: 66.66666667%;
+ }
+ .xl9 {
+ width: 75%;
+ }
+ .xl10 {
+ width: 83.33333333%;
+ }
+ .xl11 {
+ width: 91.66666667%;
+ }
+ .xl12 {
+ width: 100%;
+ }
+ .xl0-left {
+ left: 0;
+ }
+ .xl1-left {
+ left: 8.33333333%;
+ }
+ .xl2-left {
+ left: 16.66666667%;
+ }
+ .xl3-left {
+ left: 25%;
+ }
+ .xl4-left {
+ left: 33.33333333%;
+ }
+ .xl5-left {
+ left: 41.66666667%;
+ }
+ .xl6-left {
+ left: 50%;
+ }
+ .xl7-left {
+ left: 58.33333333%;
+ }
+ .xl8-left {
+ left: 66.66666667%;
+ }
+ .xl9-left {
+ left: 75%;
+ }
+ .xl10-left {
+ left: 83.33333333%;
+ }
+ .xl11-left {
+ left: 91.66666667%;
+ }
+ .xl12-left {
+ left: 100%;
+ }
+ .xl0-right {
+ right: 0;
+ }
+ .xl1-right {
+ right: 8.33333333%;
+ }
+ .xl2-right {
+ right: 16.66666667%;
+ }
+ .xl3-right {
+ right: 25%;
+ }
+ .xl4-right {
+ right: 33.33333333%;
+ }
+ .xl5-right {
+ right: 41.66666667%;
+ }
+ .xl6-right {
+ right: 50%;
+ }
+ .xl7-right {
+ right: 58.33333333%;
+ }
+ .xl8-right {
+ right: 66.66666667%;
+ }
+ .xl9-right {
+ right: 75%;
+ }
+ .xl10-right {
+ right: 83.33333333%;
+ }
+ .xl11-right {
+ right: 91.66666667%;
+ }
+ .xl12-right {
+ right: 100%;
+ }
+ .xl0-move {
+ margin-left: 0;
+ }
+ .xl1-move {
+ margin-left: 8.33333333%;
+ }
+ .xl2-move {
+ margin-left: 16.66666667%;
+ }
+ .xl3-move {
+ margin-left: 25%;
+ }
+ .xl4-move {
+ margin-left: 33.33333333%;
+ }
+ .xl5-move {
+ margin-left: 41.66666667%;
+ }
+ .xl6-move {
+ margin-left: 50%;
+ }
+ .xl7-move {
+ margin-left: 58.33333333%;
+ }
+ .xl8-move {
+ margin-left: 66.66666667%;
+ }
+ .xl9-move {
+ margin-left: 75%;
+ }
+ .xl10-move {
+ margin-left: 83.33333333%;
+ }
+ .xl11-move {
+ margin-left: 91.66666667%;
+ }
+ .xl12-move {
+ margin-left: 100%;
+ }
+}
+
+@media (min-width: 760px) {
+ .xs1,
+ .xs2,
+ .xs3,
+ .xs4,
+ .xs5,
+ .xs6,
+ .xs7,
+ .xs8,
+ .xs9,
+ .xs10,
+ .xs11,
+ .xs12 {
+ float: left;
+ }
+ .xs1 {
+ width: 8.33333333%;
+ }
+ .xs2 {
+ width: 16.66666667%;
+ }
+ .xs3 {
+ width: 25%;
+ }
+ .xs4 {
+ width: 33.33333333%;
+ }
+ .xs5 {
+ width: 41.66666667%;
+ }
+ .xs6 {
+ width: 50%;
+ }
+ .xs7 {
+ width: 58.33333333%;
+ }
+ .xs8 {
+ width: 66.66666667%;
+ }
+ .xs9 {
+ width: 75%;
+ }
+ .xs10 {
+ width: 83.33333333%;
+ }
+ .xs11 {
+ width: 91.66666667%;
+ }
+ .xs12 {
+ width: 100%;
+ }
+ .xs0-left {
+ left: 0;
+ }
+ .xs1-left {
+ left: 8.33333333%;
+ }
+ .xs2-left {
+ left: 16.66666667%;
+ }
+ .xs3-left {
+ left: 25%;
+ }
+ .xs4-left {
+ left: 33.33333333%;
+ }
+ .xs5-left {
+ left: 41.66666667%;
+ }
+ .xs6-left {
+ left: 50%;
+ }
+ .xs7-left {
+ left: 58.33333333%;
+ }
+ .xs8-left {
+ left: 66.66666667%;
+ }
+ .xs9-left {
+ left: 75%;
+ }
+ .xs10-left {
+ left: 83.33333333%;
+ }
+ .xs11-left {
+ left: 91.66666667%;
+ }
+ .xs12-left {
+ left: 100%;
+ }
+ .xs0-right {
+ right: 0;
+ }
+ .xs1-right {
+ right: 8.33333333%;
+ }
+ .xs2-right {
+ right: 16.66666667%;
+ }
+ .xs3-right {
+ right: 25%;
+ }
+ .xs4-right {
+ right: 33.33333333%;
+ }
+ .xs5-right {
+ right: 41.66666667%;
+ }
+ .xs6-right {
+ right: 50%;
+ }
+ .xs7-right {
+ right: 58.33333333%;
+ }
+ .xs8-right {
+ right: 66.66666667%;
+ }
+ .xs9-right {
+ right: 75%;
+ }
+ .xs10-right {
+ right: 83.33333333%;
+ }
+ .xs11-right {
+ right: 91.66666667%;
+ }
+ .xs12-right {
+ right: 100%;
+ }
+ .xs0-move {
+ margin-left: 0;
+ }
+ .xs1-move {
+ margin-left: 8.33333333%;
+ }
+ .xs2-move {
+ margin-left: 16.66666667%;
+ }
+ .xs3-move {
+ margin-left: 25%;
+ }
+ .xs4-move {
+ margin-left: 33.33333333%;
+ }
+ .xs5-move {
+ margin-left: 41.66666667%;
+ }
+ .xs6-move {
+ margin-left: 50%;
+ }
+ .xs7-move {
+ margin-left: 58.33333333%;
+ }
+ .xs8-move {
+ margin-left: 66.66666667%;
+ }
+ .xs9-move {
+ margin-left: 75%;
+ }
+ .xs10-move {
+ margin-left: 83.33333333%;
+ }
+ .xs11-move {
+ margin-left: 91.66666667%;
+ }
+ .xs12-move {
+ margin-left: 100%;
+ }
+}
+
+@media (min-width: 1000px) {
+ .xm1,
+ .xm2,
+ .xm3,
+ .xm4,
+ .xm5,
+ .xm6,
+ .xm7,
+ .xm8,
+ .xm9,
+ .xm10,
+ .xm11,
+ .xm12 {
+ float: left;
+ }
+ .xm1 {
+ width: 8.33333333%;
+ }
+ .xm2 {
+ width: 16.66666667%;
+ }
+ .xm3 {
+ width: 25%;
+ }
+ .xm4 {
+ width: 33.33333333%;
+ }
+ .xm5 {
+ width: 41.66666667%;
+ }
+ .xm6 {
+ width: 50%;
+ }
+ .xm7 {
+ width: 58.33333333%;
+ }
+ .xm8 {
+ width: 66.66666667%;
+ }
+ .xm9 {
+ width: 75%;
+ }
+ .xm10 {
+ width: 83.33333333%;
+ }
+ .xm11 {
+ width: 91.66666667%;
+ }
+ .xm12 {
+ width: 100%;
+ }
+ .xm0-left {
+ left: 0;
+ }
+ .xm1-left {
+ left: 8.33333333%;
+ }
+ .xm2-left {
+ left: 16.66666667%;
+ }
+ .xm3-left {
+ left: 25%;
+ }
+ .xm4-left {
+ left: 33.33333333%;
+ }
+ .xm5-left {
+ left: 41.66666667%;
+ }
+ .xm6-left {
+ left: 50%;
+ }
+ .xm7-left {
+ left: 58.33333333%;
+ }
+ .xm8-left {
+ left: 66.66666667%;
+ }
+ .xm9-left {
+ left: 75%;
+ }
+ .xm10-left {
+ left: 83.33333333%;
+ }
+ .xm11-left {
+ left: 91.66666667%;
+ }
+ .xm12-left {
+ left: 100%;
+ }
+ .xm0-right {
+ right: 0;
+ }
+ .xm1-right {
+ right: 8.33333333%;
+ }
+ .xm2-right {
+ right: 16.66666667%;
+ }
+ .xm3-right {
+ right: 25%;
+ }
+ .xm4-right {
+ right: 33.33333333%;
+ }
+ .xm5-right {
+ right: 41.66666667%;
+ }
+ .xm6-right {
+ right: 50%;
+ }
+ .xm7-right {
+ right: 58.33333333%;
+ }
+ .xm8-right {
+ right: 66.66666667%;
+ }
+ .xm9-right {
+ right: 75%;
+ }
+ .xm10-right {
+ right: 83.33333333%;
+ }
+ .xm11-right {
+ right: 91.66666667%;
+ }
+ .xm12-right {
+ right: 100%;
+ }
+ .xm0-move {
+ margin-left: 0;
+ }
+ .xm1-move {
+ margin-left: 8.33333333%;
+ }
+ .xm2-move {
+ margin-left: 16.66666667%;
+ }
+ .xm3-move {
+ margin-left: 25%;
+ }
+ .xm4-move {
+ margin-left: 33.33333333%;
+ }
+ .xm5-move {
+ margin-left: 41.66666667%;
+ }
+ .xm6-move {
+ margin-left: 50%;
+ }
+ .xm7-move {
+ margin-left: 58.33333333%;
+ }
+ .xm8-move {
+ margin-left: 66.66666667%;
+ }
+ .xm9-move {
+ margin-left: 75%;
+ }
+ .xm10-move {
+ margin-left: 83.33333333%;
+ }
+ .xm11-move {
+ margin-left: 91.66666667%;
+ }
+ .xm12-move {
+ margin-left: 100%;
+ }
+}
+
+@media (min-width: 1200px) {
+ .xb1,
+ .xb2,
+ .xb3,
+ .xb4,
+ .xb5,
+ .xb6,
+ .xb7,
+ .xb8,
+ .xb9,
+ .xb10,
+ .xb11,
+ .xb12 {
+ float: left;
+ }
+ .xb1 {
+ width: 8.33333333%;
+ }
+ .xb2 {
+ width: 16.66666667%;
+ }
+ .xb3 {
+ width: 25%;
+ }
+ .xb4 {
+ width: 33.33333333%;
+ }
+ .xb5 {
+ width: 41.66666667%;
+ }
+ .xb6 {
+ width: 50%;
+ }
+ .xb7 {
+ width: 58.33333333%;
+ }
+ .xb8 {
+ width: 66.66666667%;
+ }
+ .xb9 {
+ width: 75%;
+ }
+ .xb10 {
+ width: 83.33333333%;
+ }
+ .xb11 {
+ width: 91.66666667%;
+ }
+ .xb12 {
+ width: 100%;
+ }
+ .xb0-left {
+ left: 0;
+ }
+ .xb1-left {
+ left: 8.33333333%;
+ }
+ .xb2-left {
+ left: 16.66666667%;
+ }
+ .xb3-left {
+ left: 25%;
+ }
+ .xb4-left {
+ left: 33.33333333%;
+ }
+ .xb5-left {
+ left: 41.66666667%;
+ }
+ .xb6-left {
+ left: 50%;
+ }
+ .xb7-left {
+ left: 58.33333333%;
+ }
+ .xb8-left {
+ left: 66.66666667%;
+ }
+ .xb9-left {
+ left: 75%;
+ }
+ .xb10-left {
+ left: 83.33333333%;
+ }
+ .xb11-left {
+ left: 91.66666667%;
+ }
+ .xb12-left {
+ left: 100%;
+ }
+ .xb0-right {
+ right: 0;
+ }
+ .xb1-right {
+ right: 8.33333333%;
+ }
+ .xb2-right {
+ right: 16.66666667%;
+ }
+ .xb3-right {
+ right: 25%;
+ }
+ .xb4-right {
+ right: 33.33333333%;
+ }
+ .xb5-right {
+ right: 41.66666667%;
+ }
+ .xb6-right {
+ right: 50%;
+ }
+ .xb7-right {
+ right: 58.33333333%;
+ }
+ .xb8-right {
+ right: 66.66666667%;
+ }
+ .xb9-right {
+ right: 75%;
+ }
+ .xb10-right {
+ right: 83.33333333%;
+ }
+ .xb11-right {
+ right: 91.66666667%;
+ }
+ .xb12-right {
+ right: 100%;
+ }
+ .xb0-move {
+ margin-left: 0;
+ }
+ .xb1-move {
+ margin-left: 8.33333333%;
+ }
+ .xb2-move {
+ margin-left: 16.66666667%;
+ }
+ .xb3-move {
+ margin-left: 25%;
+ }
+ .xb4-move {
+ margin-left: 33.33333333%;
+ }
+ .xb5-move {
+ margin-left: 41.66666667%;
+ }
+ .xb6-move {
+ margin-left: 50%;
+ }
+ .xb7-move {
+ margin-left: 58.33333333%;
+ }
+ .xb8-move {
+ margin-left: 66.66666667%;
+ }
+ .xb9-move {
+ margin-left: 75%;
+ }
+ .xb10-move {
+ margin-left: 83.33333333%;
+ }
+ .xb11-move {
+ margin-left: 91.66666667%;
+ }
+ .xb12-move {
+ margin-left: 100%;
+ }
+}
+
+
+/*响应式显示*/
+
+@media (max-width: 760px) {
+ .show-l {
+ display: block !important;
+ }
+ .hidden-l {
+ display: none !important;
+ }
+}
+
+@media (min-width: 761px) and (max-width: 1000px) {
+ .show-s {
+ display: block !important;
+ }
+ .hidden-s {
+ display: none !important;
+ }
+}
+
+@media (min-width: 1001px) and (max-width: 1200px) {
+ .show-m {
+ display: block !important;
+ }
+ .hidden-m {
+ display: none !important;
+ }
+}
+
+@media (min-width: 1201px) {
+ .show-b {
+ display: block !important;
+ }
+ .hidden-b {
+ display: none !important;
+ }
+}
+
+
+/*小图标*/
+
+@font-face {
+ font-family: 'FontAwesome';
+ src: url('http://libs.baidu.com/fontawesome/4.1.0/fonts/fontawesome-webfont.eot?v=4.1.0');
+ src: url('http://libs.baidu.com/fontawesome/4.1.0/fonts/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'), url('http://libs.baidu.com/fontawesome/4.1.0/fonts/fontawesome-webfont.woff?v=4.1.0') format('woff'), url('http://libs.baidu.com/fontawesome/4.1.0/fonts/fontawesome-webfont.ttf?v=4.1.0') format('truetype'), url('http://libs.baidu.com/fontawesome/4.1.0/fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+
+[class*='icon-']:before {
+ display: inline-block;
+ font-family: "FontAwesome";
+ font-weight: normal;
+ font-style: normal;
+ vertical-align: baseline;
+ line-height: 1;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-glass:before {
+ content: "\f000";
+}
+
+.icon-music:before {
+ content: "\f001";
+}
+
+.icon-search:before {
+ content: "\f002";
+}
+
+.icon-envelope-o:before {
+ content: "\f003";
+}
+
+.icon-heart:before {
+ content: "\f004";
+}
+
+.icon-star:before {
+ content: "\f005";
+}
+
+.icon-star-o:before {
+ content: "\f006";
+}
+
+.icon-user:before {
+ content: "\f007";
+}
+
+.icon-film:before {
+ content: "\f008";
+}
+
+.icon-th-large:before {
+ content: "\f009";
+}
+
+.icon-th:before {
+ content: "\f00a";
+}
+
+.icon-th-list:before {
+ content: "\f00b";
+}
+
+.icon-check:before {
+ content: "\f00c";
+}
+
+.icon-times:before {
+ content: "\f00d";
+}
+
+.icon-search-plus:before {
+ content: "\f00e";
+}
+
+.icon-search-minus:before {
+ content: "\f010";
+}
+
+.icon-power-off:before {
+ content: "\f011";
+}
+
+.icon-signal:before {
+ content: "\f012";
+}
+
+.icon-gear:before,
+.icon-cog:before {
+ content: "\f013";
+}
+
+.icon-trash-o:before {
+ content: "\f014";
+}
+
+.icon-home:before {
+ content: "\f015";
+}
+
+.icon-file-o:before {
+ content: "\f016";
+}
+
+.icon-clock-o:before {
+ content: "\f017";
+}
+
+.icon-road:before {
+ content: "\f018";
+}
+
+.icon-download:before {
+ content: "\f019";
+}
+
+.icon-arrow-circle-o-down:before {
+ content: "\f01a";
+}
+
+.icon-arrow-circle-o-up:before {
+ content: "\f01b";
+}
+
+.icon-inbox:before {
+ content: "\f01c";
+}
+
+.icon-play-circle-o:before {
+ content: "\f01d";
+}
+
+.icon-rotate-right:before,
+.icon-repeat:before {
+ content: "\f01e";
+}
+
+.icon-refresh:before {
+ content: "\f021";
+}
+
+.icon-list-alt:before {
+ content: "\f022";
+}
+
+.icon-lock:before {
+ content: "\f023";
+}
+
+.icon-flag:before {
+ content: "\f024";
+}
+
+.icon-headphones:before {
+ content: "\f025";
+}
+
+.icon-volume-off:before {
+ content: "\f026";
+}
+
+.icon-volume-down:before {
+ content: "\f027";
+}
+
+.icon-volume-up:before {
+ content: "\f028";
+}
+
+.icon-qrcode:before {
+ content: "\f029";
+}
+
+.icon-barcode:before {
+ content: "\f02a";
+}
+
+.icon-tag:before {
+ content: "\f02b";
+}
+
+.icon-tags:before {
+ content: "\f02c";
+}
+
+.icon-book:before {
+ content: "\f02d";
+}
+
+.icon-bookmark:before {
+ content: "\f02e";
+}
+
+.icon-print:before {
+ content: "\f02f";
+}
+
+.icon-camera:before {
+ content: "\f030";
+}
+
+.icon-font:before {
+ content: "\f031";
+}
+
+.icon-bold:before {
+ content: "\f032";
+}
+
+.icon-italic:before {
+ content: "\f033";
+}
+
+.icon-text-height:before {
+ content: "\f034";
+}
+
+.icon-text-width:before {
+ content: "\f035";
+}
+
+.icon-align-left:before {
+ content: "\f036";
+}
+
+.icon-align-center:before {
+ content: "\f037";
+}
+
+.icon-align-right:before {
+ content: "\f038";
+}
+
+.icon-align-justify:before {
+ content: "\f039";
+}
+
+.icon-list:before {
+ content: "\f03a";
+}
+
+.icon-dedent:before,
+.icon-outdent:before {
+ content: "\f03b";
+}
+
+.icon-indent:before {
+ content: "\f03c";
+}
+
+.icon-video-camera:before {
+ content: "\f03d";
+}
+
+.icon-photo:before,
+.icon-image:before,
+.icon-picture-o:before {
+ content: "\f03e";
+}
+
+.icon-pencil:before {
+ content: "\f040";
+}
+
+.icon-map-marker:before {
+ content: "\f041";
+}
+
+.icon-adjust:before {
+ content: "\f042";
+}
+
+.icon-tint:before {
+ content: "\f043";
+}
+
+.icon-edit:before,
+.icon-pencil-square-o:before {
+ content: "\f044";
+}
+
+.icon-share-square-o:before {
+ content: "\f045";
+}
+
+.icon-check-square-o:before {
+ content: "\f046";
+}
+
+.icon-arrows:before {
+ content: "\f047";
+}
+
+.icon-step-backward:before {
+ content: "\f048";
+}
+
+.icon-fast-backward:before {
+ content: "\f049";
+}
+
+.icon-backward:before {
+ content: "\f04a";
+}
+
+.icon-play:before {
+ content: "\f04b";
+}
+
+.icon-pause:before {
+ content: "\f04c";
+}
+
+.icon-stop:before {
+ content: "\f04d";
+}
+
+.icon-forward:before {
+ content: "\f04e";
+}
+
+.icon-fast-forward:before {
+ content: "\f050";
+}
+
+.icon-step-forward:before {
+ content: "\f051";
+}
+
+.icon-eject:before {
+ content: "\f052";
+}
+
+.icon-chevron-left:before {
+ content: "\f053";
+}
+
+.icon-chevron-right:before {
+ content: "\f054";
+}
+
+.icon-plus-circle:before {
+ content: "\f055";
+}
+
+.icon-minus-circle:before {
+ content: "\f056";
+}
+
+.icon-times-circle:before {
+ content: "\f057";
+}
+
+.icon-check-circle:before {
+ content: "\f058";
+}
+
+.icon-question-circle:before {
+ content: "\f059";
+}
+
+.icon-info-circle:before {
+ content: "\f05a";
+}
+
+.icon-crosshairs:before {
+ content: "\f05b";
+}
+
+.icon-times-circle-o:before {
+ content: "\f05c";
+}
+
+.icon-check-circle-o:before {
+ content: "\f05d";
+}
+
+.icon-ban:before {
+ content: "\f05e";
+}
+
+.icon-arrow-left:before {
+ content: "\f060";
+}
+
+.icon-arrow-right:before {
+ content: "\f061";
+}
+
+.icon-arrow-up:before {
+ content: "\f062";
+}
+
+.icon-arrow-down:before {
+ content: "\f063";
+}
+
+.icon-mail-forward:before,
+.icon-share:before {
+ content: "\f064";
+}
+
+.icon-expand:before {
+ content: "\f065";
+}
+
+.icon-compress:before {
+ content: "\f066";
+}
+
+.icon-plus:before {
+ content: "\f067";
+}
+
+.icon-minus:before {
+ content: "\f068";
+}
+
+.icon-asterisk:before {
+ content: "\f069";
+}
+
+.icon-exclamation-circle:before {
+ content: "\f06a";
+}
+
+.icon-gift:before {
+ content: "\f06b";
+}
+
+.icon-leaf:before {
+ content: "\f06c";
+}
+
+.icon-fire:before {
+ content: "\f06d";
+}
+
+.icon-eye:before {
+ content: "\f06e";
+}
+
+.icon-eye-slash:before {
+ content: "\f070";
+}
+
+.icon-warning:before,
+.icon-exclamation-triangle:before {
+ content: "\f071";
+}
+
+.icon-plane:before {
+ content: "\f072";
+}
+
+.icon-calendar:before {
+ content: "\f073";
+}
+
+.icon-random:before {
+ content: "\f074";
+}
+
+.icon-comment:before {
+ content: "\f075";
+}
+
+.icon-magnet:before {
+ content: "\f076";
+}
+
+.icon-chevron-up:before {
+ content: "\f077";
+}
+
+.icon-chevron-down:before {
+ content: "\f078";
+}
+
+.icon-retweet:before {
+ content: "\f079";
+}
+
+.icon-shopping-cart:before {
+ content: "\f07a";
+}
+
+.icon-folder:before {
+ content: "\f07b";
+}
+
+.icon-folder-open:before {
+ content: "\f07c";
+}
+
+.icon-arrows-v:before {
+ content: "\f07d";
+}
+
+.icon-arrows-h:before {
+ content: "\f07e";
+}
+
+.icon-bar-chart-o:before {
+ content: "\f080";
+}
+
+.icon-twitter-square:before {
+ content: "\f081";
+}
+
+.icon-facebook-square:before {
+ content: "\f082";
+}
+
+.icon-camera-retro:before {
+ content: "\f083";
+}
+
+.icon-key:before {
+ content: "\f084";
+}
+
+.icon-gears:before,
+.icon-cogs:before {
+ content: "\f085";
+}
+
+.icon-comments:before {
+ content: "\f086";
+}
+
+.icon-thumbs-o-up:before {
+ content: "\f087";
+}
+
+.icon-thumbs-o-down:before {
+ content: "\f088";
+}
+
+.icon-star-half:before {
+ content: "\f089";
+}
+
+.icon-heart-o:before {
+ content: "\f08a";
+}
+
+.icon-sign-out:before {
+ content: "\f08b";
+}
+
+.icon-linkedin-square:before {
+ content: "\f08c";
+}
+
+.icon-thumb-tack:before {
+ content: "\f08d";
+}
+
+.icon-external-link:before {
+ content: "\f08e";
+}
+
+.icon-sign-in:before {
+ content: "\f090";
+}
+
+.icon-trophy:before {
+ content: "\f091";
+}
+
+.icon-github-square:before {
+ content: "\f092";
+}
+
+.icon-upload:before {
+ content: "\f093";
+}
+
+.icon-lemon-o:before {
+ content: "\f094";
+}
+
+.icon-phone:before {
+ content: "\f095";
+}
+
+.icon-square-o:before {
+ content: "\f096";
+}
+
+.icon-bookmark-o:before {
+ content: "\f097";
+}
+
+.icon-phone-square:before {
+ content: "\f098";
+}
+
+.icon-twitter:before {
+ content: "\f099";
+}
+
+.icon-facebook:before {
+ content: "\f09a";
+}
+
+.icon-github:before {
+ content: "\f09b";
+}
+
+.icon-unlock:before {
+ content: "\f09c";
+}
+
+.icon-credit-card:before {
+ content: "\f09d";
+}
+
+.icon-rss:before {
+ content: "\f09e";
+}
+
+.icon-hdd-o:before {
+ content: "\f0a0";
+}
+
+.icon-bullhorn:before {
+ content: "\f0a1";
+}
+
+.icon-bell:before {
+ content: "\f0f3";
+}
+
+.icon-certificate:before {
+ content: "\f0a3";
+}
+
+.icon-hand-o-right:before {
+ content: "\f0a4";
+}
+
+.icon-hand-o-left:before {
+ content: "\f0a5";
+}
+
+.icon-hand-o-up:before {
+ content: "\f0a6";
+}
+
+.icon-hand-o-down:before {
+ content: "\f0a7";
+}
+
+.icon-arrow-circle-left:before {
+ content: "\f0a8";
+}
+
+.icon-arrow-circle-right:before {
+ content: "\f0a9";
+}
+
+.icon-arrow-circle-up:before {
+ content: "\f0aa";
+}
+
+.icon-arrow-circle-down:before {
+ content: "\f0ab";
+}
+
+.icon-globe:before {
+ content: "\f0ac";
+}
+
+.icon-wrench:before {
+ content: "\f0ad";
+}
+
+.icon-tasks:before {
+ content: "\f0ae";
+}
+
+.icon-filter:before {
+ content: "\f0b0";
+}
+
+.icon-briefcase:before {
+ content: "\f0b1";
+}
+
+.icon-arrows-alt:before {
+ content: "\f0b2";
+}
+
+.icon-group:before,
+.icon-users:before {
+ content: "\f0c0";
+}
+
+.icon-chain:before,
+.icon-link:before {
+ content: "\f0c1";
+}
+
+.icon-cloud:before {
+ content: "\f0c2";
+}
+
+.icon-flask:before {
+ content: "\f0c3";
+}
+
+.icon-cut:before,
+.icon-scissors:before {
+ content: "\f0c4";
+}
+
+.icon-copy:before,
+.icon-files-o:before {
+ content: "\f0c5";
+}
+
+.icon-paperclip:before {
+ content: "\f0c6";
+}
+
+.icon-save:before,
+.icon-floppy-o:before {
+ content: "\f0c7";
+}
+
+.icon-square:before {
+ content: "\f0c8";
+}
+
+.icon-navicon:before,
+.icon-reorder:before,
+.icon-bars:before {
+ content: "\f0c9";
+}
+
+.icon-list-ul:before {
+ content: "\f0ca";
+}
+
+.icon-list-ol:before {
+ content: "\f0cb";
+}
+
+.icon-strikethrough:before {
+ content: "\f0cc";
+}
+
+.icon-underline:before {
+ content: "\f0cd";
+}
+
+.icon-table:before {
+ content: "\f0ce";
+}
+
+.icon-magic:before {
+ content: "\f0d0";
+}
+
+.icon-truck:before {
+ content: "\f0d1";
+}
+
+.icon-pinterest:before {
+ content: "\f0d2";
+}
+
+.icon-pinterest-square:before {
+ content: "\f0d3";
+}
+
+.icon-google-plus-square:before {
+ content: "\f0d4";
+}
+
+.icon-google-plus:before {
+ content: "\f0d5";
+}
+
+.icon-money:before {
+ content: "\f0d6";
+}
+
+.icon-caret-down:before {
+ content: "\f0d7";
+}
+
+.icon-caret-up:before {
+ content: "\f0d8";
+}
+
+.icon-caret-left:before {
+ content: "\f0d9";
+}
+
+.icon-caret-right:before {
+ content: "\f0da";
+}
+
+.icon-columns:before {
+ content: "\f0db";
+}
+
+.icon-unsorted:before,
+.icon-sort:before {
+ content: "\f0dc";
+}
+
+.icon-sort-down:before,
+.icon-sort-desc:before {
+ content: "\f0dd";
+}
+
+.icon-sort-up:before,
+.icon-sort-asc:before {
+ content: "\f0de";
+}
+
+.icon-envelope:before {
+ content: "\f0e0";
+}
+
+.icon-linkedin:before {
+ content: "\f0e1";
+}
+
+.icon-rotate-left:before,
+.icon-undo:before {
+ content: "\f0e2";
+}
+
+.icon-legal:before,
+.icon-gavel:before {
+ content: "\f0e3";
+}
+
+.icon-dashboard:before,
+.icon-tachometer:before {
+ content: "\f0e4";
+}
+
+.icon-comment-o:before {
+ content: "\f0e5";
+}
+
+.icon-comments-o:before {
+ content: "\f0e6";
+}
+
+.icon-flash:before,
+.icon-bolt:before {
+ content: "\f0e7";
+}
+
+.icon-sitemap:before {
+ content: "\f0e8";
+}
+
+.icon-umbrella:before {
+ content: "\f0e9";
+}
+
+.icon-paste:before,
+.icon-clipboard:before {
+ content: "\f0ea";
+}
+
+.icon-lightbulb-o:before {
+ content: "\f0eb";
+}
+
+.icon-exchange:before {
+ content: "\f0ec";
+}
+
+.icon-cloud-download:before {
+ content: "\f0ed";
+}
+
+.icon-cloud-upload:before {
+ content: "\f0ee";
+}
+
+.icon-user-md:before {
+ content: "\f0f0";
+}
+
+.icon-stethoscope:before {
+ content: "\f0f1";
+}
+
+.icon-suitcase:before {
+ content: "\f0f2";
+}
+
+.icon-bell-o:before {
+ content: "\f0a2";
+}
+
+.icon-coffee:before {
+ content: "\f0f4";
+}
+
+.icon-cutlery:before {
+ content: "\f0f5";
+}
+
+.icon-file-text-o:before {
+ content: "\f0f6";
+}
+
+.icon-building-o:before {
+ content: "\f0f7";
+}
+
+.icon-hospital-o:before {
+ content: "\f0f8";
+}
+
+.icon-ambulance:before {
+ content: "\f0f9";
+}
+
+.icon-medkit:before {
+ content: "\f0fa";
+}
+
+.icon-fighter-jet:before {
+ content: "\f0fb";
+}
+
+.icon-beer:before {
+ content: "\f0fc";
+}
+
+.icon-h-square:before {
+ content: "\f0fd";
+}
+
+.icon-plus-square:before {
+ content: "\f0fe";
+}
+
+.icon-angle-double-left:before {
+ content: "\f100";
+}
+
+.icon-angle-double-right:before {
+ content: "\f101";
+}
+
+.icon-angle-double-up:before {
+ content: "\f102";
+}
+
+.icon-angle-double-down:before {
+ content: "\f103";
+}
+
+.icon-angle-left:before {
+ content: "\f104";
+}
+
+.icon-angle-right:before {
+ content: "\f105";
+}
+
+.icon-angle-up:before {
+ content: "\f106";
+}
+
+.icon-angle-down:before {
+ content: "\f107";
+}
+
+.icon-desktop:before {
+ content: "\f108";
+}
+
+.icon-laptop:before {
+ content: "\f109";
+}
+
+.icon-tablet:before {
+ content: "\f10a";
+}
+
+.icon-mobile-phone:before,
+.icon-mobile:before {
+ content: "\f10b";
+}
+
+.icon-circle-o:before {
+ content: "\f10c";
+}
+
+.icon-quote-left:before {
+ content: "\f10d";
+}
+
+.icon-quote-right:before {
+ content: "\f10e";
+}
+
+.icon-spinner:before {
+ content: "\f110";
+}
+
+.icon-circle:before {
+ content: "\f111";
+}
+
+.icon-mail-reply:before,
+.icon-reply:before {
+ content: "\f112";
+}
+
+.icon-github-alt:before {
+ content: "\f113";
+}
+
+.icon-folder-o:before {
+ content: "\f114";
+}
+
+.icon-folder-open-o:before {
+ content: "\f115";
+}
+
+.icon-smile-o:before {
+ content: "\f118";
+}
+
+.icon-frown-o:before {
+ content: "\f119";
+}
+
+.icon-meh-o:before {
+ content: "\f11a";
+}
+
+.icon-gamepad:before {
+ content: "\f11b";
+}
+
+.icon-keyboard-o:before {
+ content: "\f11c";
+}
+
+.icon-flag-o:before {
+ content: "\f11d";
+}
+
+.icon-flag-checkered:before {
+ content: "\f11e";
+}
+
+.icon-terminal:before {
+ content: "\f120";
+}
+
+.icon-code:before {
+ content: "\f121";
+}
+
+.icon-mail-reply-all:before,
+.icon-reply-all:before {
+ content: "\f122";
+}
+
+.icon-star-half-empty:before,
+.icon-star-half-full:before,
+.icon-star-half-o:before {
+ content: "\f123";
+}
+
+.icon-location-arrow:before {
+ content: "\f124";
+}
+
+.icon-crop:before {
+ content: "\f125";
+}
+
+.icon-code-fork:before {
+ content: "\f126";
+}
+
+.icon-unlink:before,
+.icon-chain-broken:before {
+ content: "\f127";
+}
+
+.icon-question:before {
+ content: "\f128";
+}
+
+.icon-info:before {
+ content: "\f129";
+}
+
+.icon-exclamation:before {
+ content: "\f12a";
+}
+
+.icon-superscript:before {
+ content: "\f12b";
+}
+
+.icon-subscript:before {
+ content: "\f12c";
+}
+
+.icon-eraser:before {
+ content: "\f12d";
+}
+
+.icon-puzzle-piece:before {
+ content: "\f12e";
+}
+
+.icon-microphone:before {
+ content: "\f130";
+}
+
+.icon-microphone-slash:before {
+ content: "\f131";
+}
+
+.icon-shield:before {
+ content: "\f132";
+}
+
+.icon-calendar-o:before {
+ content: "\f133";
+}
+
+.icon-fire-extinguisher:before {
+ content: "\f134";
+}
+
+.icon-rocket:before {
+ content: "\f135";
+}
+
+.icon-maxcdn:before {
+ content: "\f136";
+}
+
+.icon-chevron-circle-left:before {
+ content: "\f137";
+}
+
+.icon-chevron-circle-right:before {
+ content: "\f138";
+}
+
+.icon-chevron-circle-up:before {
+ content: "\f139";
+}
+
+.icon-chevron-circle-down:before {
+ content: "\f13a";
+}
+
+.icon-html5:before {
+ content: "\f13b";
+}
+
+.icon-css3:before {
+ content: "\f13c";
+}
+
+.icon-anchor:before {
+ content: "\f13d";
+}
+
+.icon-unlock-alt:before {
+ content: "\f13e";
+}
+
+.icon-bullseye:before {
+ content: "\f140";
+}
+
+.icon-ellipsis-h:before {
+ content: "\f141";
+}
+
+.icon-ellipsis-v:before {
+ content: "\f142";
+}
+
+.icon-rss-square:before {
+ content: "\f143";
+}
+
+.icon-play-circle:before {
+ content: "\f144";
+}
+
+.icon-ticket:before {
+ content: "\f145";
+}
+
+.icon-minus-square:before {
+ content: "\f146";
+}
+
+.icon-minus-square-o:before {
+ content: "\f147";
+}
+
+.icon-level-up:before {
+ content: "\f148";
+}
+
+.icon-level-down:before {
+ content: "\f149";
+}
+
+.icon-check-square:before {
+ content: "\f14a";
+}
+
+.icon-pencil-square:before {
+ content: "\f14b";
+}
+
+.icon-external-link-square:before {
+ content: "\f14c";
+}
+
+.icon-share-square:before {
+ content: "\f14d";
+}
+
+.icon-compass:before {
+ content: "\f14e";
+}
+
+.icon-toggle-down:before,
+.icon-caret-square-o-down:before {
+ content: "\f150";
+}
+
+.icon-toggle-up:before,
+.icon-caret-square-o-up:before {
+ content: "\f151";
+}
+
+.icon-toggle-right:before,
+.icon-caret-square-o-right:before {
+ content: "\f152";
+}
+
+.icon-euro:before,
+.icon-eur:before {
+ content: "\f153";
+}
+
+.icon-gbp:before {
+ content: "\f154";
+}
+
+.icon-dollar:before,
+.icon-usd:before {
+ content: "\f155";
+}
+
+.icon-rupee:before,
+.icon-inr:before {
+ content: "\f156";
+}
+
+.icon-cny:before,
+.icon-rmb:before,
+.icon-yen:before,
+.icon-jpy:before {
+ content: "\f157";
+}
+
+.icon-ruble:before,
+.icon-rouble:before,
+.icon-rub:before {
+ content: "\f158";
+}
+
+.icon-won:before,
+.icon-krw:before {
+ content: "\f159";
+}
+
+.icon-bitcoin:before,
+.icon-btc:before {
+ content: "\f15a";
+}
+
+.icon-file:before {
+ content: "\f15b";
+}
+
+.icon-file-text:before {
+ content: "\f15c";
+}
+
+.icon-sort-alpha-asc:before {
+ content: "\f15d";
+}
+
+.icon-sort-alpha-desc:before {
+ content: "\f15e";
+}
+
+.icon-sort-amount-asc:before {
+ content: "\f160";
+}
+
+.icon-sort-amount-desc:before {
+ content: "\f161";
+}
+
+.icon-sort-numeric-asc:before {
+ content: "\f162";
+}
+
+.icon-sort-numeric-desc:before {
+ content: "\f163";
+}
+
+.icon-thumbs-up:before {
+ content: "\f164";
+}
+
+.icon-thumbs-down:before {
+ content: "\f165";
+}
+
+.icon-youtube-square:before {
+ content: "\f166";
+}
+
+.icon-youtube:before {
+ content: "\f167";
+}
+
+.icon-xing:before {
+ content: "\f168";
+}
+
+.icon-xing-square:before {
+ content: "\f169";
+}
+
+.icon-youtube-play:before {
+ content: "\f16a";
+}
+
+.icon-dropbox:before {
+ content: "\f16b";
+}
+
+.icon-stack-overflow:before {
+ content: "\f16c";
+}
+
+.icon-instagram:before {
+ content: "\f16d";
+}
+
+.icon-flickr:before {
+ content: "\f16e";
+}
+
+.icon-adn:before {
+ content: "\f170";
+}
+
+.icon-bitbucket:before {
+ content: "\f171";
+}
+
+.icon-bitbucket-square:before {
+ content: "\f172";
+}
+
+.icon-tumblr:before {
+ content: "\f173";
+}
+
+.icon-tumblr-square:before {
+ content: "\f174";
+}
+
+.icon-long-arrow-down:before {
+ content: "\f175";
+}
+
+.icon-long-arrow-up:before {
+ content: "\f176";
+}
+
+.icon-long-arrow-left:before {
+ content: "\f177";
+}
+
+.icon-long-arrow-right:before {
+ content: "\f178";
+}
+
+.icon-apple:before {
+ content: "\f179";
+}
+
+.icon-windows:before {
+ content: "\f17a";
+}
+
+.icon-android:before {
+ content: "\f17b";
+}
+
+.icon-linux:before {
+ content: "\f17c";
+}
+
+.icon-dribbble:before {
+ content: "\f17d";
+}
+
+.icon-skype:before {
+ content: "\f17e";
+}
+
+.icon-foursquare:before {
+ content: "\f180";
+}
+
+.icon-trello:before {
+ content: "\f181";
+}
+
+.icon-female:before {
+ content: "\f182";
+}
+
+.icon-male:before {
+ content: "\f183";
+}
+
+.icon-gittip:before {
+ content: "\f184";
+}
+
+.icon-sun-o:before {
+ content: "\f185";
+}
+
+.icon-moon-o:before {
+ content: "\f186";
+}
+
+.icon-archive:before {
+ content: "\f187";
+}
+
+.icon-bug:before {
+ content: "\f188";
+}
+
+.icon-vk:before {
+ content: "\f189";
+}
+
+.icon-weibo:before {
+ content: "\f18a";
+}
+
+.icon-renren:before {
+ content: "\f18b";
+}
+
+.icon-pagelines:before {
+ content: "\f18c";
+}
+
+.icon-stack-exchange:before {
+ content: "\f18d";
+}
+
+.icon-arrow-circle-o-right:before {
+ content: "\f18e";
+}
+
+.icon-arrow-circle-o-left:before {
+ content: "\f190";
+}
+
+.icon-toggle-left:before,
+.icon-caret-square-o-left:before {
+ content: "\f191";
+}
+
+.icon-dot-circle-o:before {
+ content: "\f192";
+}
+
+.icon-wheelchair:before {
+ content: "\f193";
+}
+
+.icon-vimeo-square:before {
+ content: "\f194";
+}
+
+.icon-turkish-lira:before,
+.icon-try:before {
+ content: "\f195";
+}
+
+.icon-plus-square-o:before {
+ content: "\f196";
+}
+
+.icon-space-shuttle:before {
+ content: "\f197";
+}
+
+.icon-slack:before {
+ content: "\f198";
+}
+
+.icon-envelope-square:before {
+ content: "\f199";
+}
+
+.icon-wordpress:before {
+ content: "\f19a";
+}
+
+.icon-openid:before {
+ content: "\f19b";
+}
+
+.icon-institution:before,
+.icon-bank:before,
+.icon-university:before {
+ content: "\f19c";
+}
+
+.icon-mortar-board:before,
+.icon-graduation-cap:before {
+ content: "\f19d";
+}
+
+.icon-yahoo:before {
+ content: "\f19e";
+}
+
+.icon-google:before {
+ content: "\f1a0";
+}
+
+.icon-reddit:before {
+ content: "\f1a1";
+}
+
+.icon-reddit-square:before {
+ content: "\f1a2";
+}
+
+.icon-stumbleupon-circle:before {
+ content: "\f1a3";
+}
+
+.icon-stumbleupon:before {
+ content: "\f1a4";
+}
+
+.icon-delicious:before {
+ content: "\f1a5";
+}
+
+.icon-digg:before {
+ content: "\f1a6";
+}
+
+.icon-pied-piper-square:before,
+.icon-pied-piper:before {
+ content: "\f1a7";
+}
+
+.icon-pied-piper-alt:before {
+ content: "\f1a8";
+}
+
+.icon-drupal:before {
+ content: "\f1a9";
+}
+
+.icon-joomla:before {
+ content: "\f1aa";
+}
+
+.icon-language:before {
+ content: "\f1ab";
+}
+
+.icon-fax:before {
+ content: "\f1ac";
+}
+
+.icon-building:before {
+ content: "\f1ad";
+}
+
+.icon-child:before {
+ content: "\f1ae";
+}
+
+.icon-paw:before {
+ content: "\f1b0";
+}
+
+.icon-spoon:before {
+ content: "\f1b1";
+}
+
+.icon-cube:before {
+ content: "\f1b2";
+}
+
+.icon-cubes:before {
+ content: "\f1b3";
+}
+
+.icon-behance:before {
+ content: "\f1b4";
+}
+
+.icon-behance-square:before {
+ content: "\f1b5";
+}
+
+.icon-steam:before {
+ content: "\f1b6";
+}
+
+.icon-steam-square:before {
+ content: "\f1b7";
+}
+
+.icon-recycle:before {
+ content: "\f1b8";
+}
+
+.icon-automobile:before,
+.icon-car:before {
+ content: "\f1b9";
+}
+
+.icon-cab:before,
+.icon-taxi:before {
+ content: "\f1ba";
+}
+
+.icon-tree:before {
+ content: "\f1bb";
+}
+
+.icon-spotify:before {
+ content: "\f1bc";
+}
+
+.icon-deviantart:before {
+ content: "\f1bd";
+}
+
+.icon-soundcloud:before {
+ content: "\f1be";
+}
+
+.icon-database:before {
+ content: "\f1c0";
+}
+
+.icon-file-pdf-o:before {
+ content: "\f1c1";
+}
+
+.icon-file-word-o:before {
+ content: "\f1c2";
+}
+
+.icon-file-excel-o:before {
+ content: "\f1c3";
+}
+
+.icon-file-powerpoint-o:before {
+ content: "\f1c4";
+}
+
+.icon-file-photo-o:before,
+.icon-file-picture-o:before,
+.icon-file-image-o:before {
+ content: "\f1c5";
+}
+
+.icon-file-zip-o:before,
+.icon-file-archive-o:before {
+ content: "\f1c6";
+}
+
+.icon-file-sound-o:before,
+.icon-file-audio-o:before {
+ content: "\f1c7";
+}
+
+.icon-file-movie-o:before,
+.icon-file-video-o:before {
+ content: "\f1c8";
+}
+
+.icon-file-code-o:before {
+ content: "\f1c9";
+}
+
+.icon-vine:before {
+ content: "\f1ca";
+}
+
+.icon-codepen:before {
+ content: "\f1cb";
+}
+
+.icon-jsfiddle:before {
+ content: "\f1cc";
+}
+
+.icon-life-bouy:before,
+.icon-life-saver:before,
+.icon-support:before,
+.icon-life-ring:before {
+ content: "\f1cd";
+}
+
+.icon-circle-o-notch:before {
+ content: "\f1ce";
+}
+
+.icon-ra:before,
+.icon-rebel:before {
+ content: "\f1d0";
+}
+
+.icon-ge:before,
+.icon-empire:before {
+ content: "\f1d1";
+}
+
+.icon-git-square:before {
+ content: "\f1d2";
+}
+
+.icon-git:before {
+ content: "\f1d3";
+}
+
+.icon-hacker-news:before {
+ content: "\f1d4";
+}
+
+.icon-tencent-weibo:before {
+ content: "\f1d5";
+}
+
+.icon-qq:before {
+ content: "\f1d6";
+}
+
+.icon-wechat:before,
+.icon-weixin:before {
+ content: "\f1d7";
+}
+
+.icon-send:before,
+.icon-paper-plane:before {
+ content: "\f1d8";
+}
+
+.icon-send-o:before,
+.icon-paper-plane-o:before {
+ content: "\f1d9";
+}
+
+.icon-history:before {
+ content: "\f1da";
+}
+
+.icon-circle-thin:before {
+ content: "\f1db";
+}
+
+.icon-header:before {
+ content: "\f1dc";
+}
+
+.icon-paragraph:before {
+ content: "\f1dd";
+}
+
+.icon-sliders:before {
+ content: "\f1de";
+}
+
+.icon-share-alt:before {
+ content: "\f1e0";
+}
+
+.icon-share-alt-square:before {
+ content: "\f1e1";
+}
+
+.icon-bomb:before {
+ content: "\f1e2";
+}
+
+.close {
+ display: inline-block;
+ font-size: 24px;
+ cursor: pointer;
+ line-height: 24px;
+}
+
+.close:before {
+ content: "\00d7";
+}
+
+.leftward {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ margin-left: 2px;
+ vertical-align: middle;
+ border-right: 4px solid;
+ border-top: 4px solid transparent;
+ border-bottom: 4px solid transparent;
+}
+
+.rightward {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ margin-left: 2px;
+ vertical-align: middle;
+ border-left: 4px solid;
+ border-top: 4px solid transparent;
+ border-bottom: 4px solid transparent;
+}
+
+.upward {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ margin-left: 2px;
+ vertical-align: middle;
+ border-bottom: 4px solid;
+ border-right: 4px solid transparent;
+ border-left: 4px solid transparent;
+}
+
+.downward,
+.arrow {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ margin-left: 2px;
+ vertical-align: middle;
+ border-top: 4px solid;
+ border-right: 4px solid transparent;
+ border-left: 4px solid transparent;
+}
+
+
+/*标签*/
+
+.tag {
+ font-size: 75%;
+ border-radius: 0.25em;
+ background: #999;
+ padding: 0.1em 0.5em 0.2em;
+ color: #fff;
+}
+
+.tag.bg-back,
+.tag.bg-mix,
+.tag.bg-white,
+.tag.bg-red-light,
+.tag.bg-yellow-light,
+.tag.bg-blue-light,
+.tag.bg-green-light {
+ color: inherit;
+}
+
+
+/*徽章*/
+
+.badge {
+ display: inline-block;
+ min-width: 10px;
+ padding: 3px 7px;
+ font-size: 12px;
+ line-height: 1;
+ color: #fff;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ background-color: #999;
+ border-radius: 2em;
+}
+
+.badge:empty {
+ display: none
+}
+
+.badge.bg-back,
+.badge.bg-mix {
+ color: inherit;
+}
+
+.badge.bg-white,
+.badge.bg-red-light,
+.badge.bg-yellow-light,
+.badge.bg-blue-light,
+.badge.bg-green-light {
+ color: #333;
+}
+
+.badge-corner {
+ position: relative;
+}
+
+.badge-corner .badge {
+ position: absolute;
+ right: -10px;
+ top: -9px;
+ font-weight: normal;
+ cursor: pointer;
+}
+
+
+/*进度条*/
+
+.progress {
+ height: 14px;
+ overflow: hidden;
+ background-color: #f5f5f5;
+ border-radius: 7px;
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+}
+
+.progress-bar {
+ color: #fff;
+ float: left;
+ background-color: #0a0;
+ display: inline-block;
+ font-size: 12px;
+ line-height: 14px;
+ text-align: center;
+}
+
+.progress-bar:after {
+ content: "\3000";
+}
+
+.progress .progress-bar:last-child {
+ border-radius: 0 7px 7px 0;
+}
+
+.progress-big {
+ height: 26px;
+ border-radius: 13px;
+}
+
+.progress-big .progress-bar {
+ font-size: 14px;
+ line-height: 26px;
+}
+
+.progress-big .progress-bar:last-child {
+ border-radius: 0 13px 13px 0;
+}
+
+.progress-small {
+ height: 6px;
+ border-radius: 3px;
+}
+
+.progress-small .progress-bar {
+ font-size: 6px;
+ line-height: 6px;
+}
+
+.progress-small .progress-bar:last-child {
+ border-radius: 0 3px 3px 0;
+}
+
+.progress-bar.bg-back,
+.progress-bar.bg-mix,
+.progress-bar.bg-white {
+ color: inherit;
+}
+
+@-webkit-keyframes progress-bar-active {
+ from {
+ background-position: 30px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+
+@keyframes progress-bar-active {
+ from {
+ background-position: 30px 0;
+ }
+ to {
+ background-position: 0 0;
+ }
+}
+
+.progress-striped .progress-bar {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .25) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .25) 50%, rgba(255, 255, 255, .25) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .25) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .25) 50%, rgba(255, 255, 255, .25) 75%, transparent 75%, transparent);
+ background-size: 30px 30px;
+}
+
+.progress.active .progress-bar {
+ -webkit-animation: progress-bar-active 2s linear infinite normal;
+ animation: progress-bar-active 2s linear infinite normal;
+}
+
+
+/*范围*/
+
+.range {
+ position: raelative;
+ height: 10px;
+ background-color: #f5f5f5;
+ border-radius: 5px;
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+}
+
+.range-scroll {
+ position: aabsolute;
+ width: 16px;
+ height: 16px;
+ margin-top: -3px;
+ border-radius: 8px;
+ cursor: pointer;
+ -webkit-box-shadow: 1px 1px 1px rgba(0, 0, 0, .175);
+ box-shadow: 1px 1px 1px rgba(0, 0, 0, .175);
+}
+
+.range-bar {
+ position: absaolute;
+ height: 10px;
+ float: left;
+ display: inline-block;
+ border-radius: 5px;
+}
+
+.range-bar span {
+ position: relative;
+}
+
+.range-scroll-left {
+ float: left;
+ margin-left: -8px;
+}
+
+.range-scroll-right {
+ float: right;
+ margin-right: -8px;
+}
+
+.range-group {
+ display: table;
+}
+
+.range-group .range-area,
+.range-group input {
+ display: table-cell;
+}
+
+.range-group .range-area {
+ width: 100%;
+}
+
+.range-group input {
+ width: 1%;
+}
+
+
+/*下拉菜单*/
+
+.drop {
+ position: relative;
+}
+
+.drop-menu {
+ position: absolute;
+ display: none;
+ top: 100%;
+ left: 0;
+ z-index: 1;
+ float: left;
+ min-width: 160px;
+ padding: 5px 0;
+ margin: 1px 0 0;
+ list-style: none;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, .15);
+ border-radius: 4px;
+ -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+ box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+}
+
+.drop-menu.pull-right {
+ right: 0;
+ left: auto;
+}
+
+.drop-menu a {
+ color: #333;
+ padding: 5px 20px;
+ display: block;
+ clear: both;
+ white-space: nowrap;
+ transition: all 1s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+}
+
+.drop-menu a:hover,
+.drop-menu a:focus {
+ background: #f5f5f5;
+ transition: all 1s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+}
+
+.drop-menu .disabled a {
+ color: #999;
+ pointer-events: none;
+}
+
+.drop-menu .disabled a:hover,
+.drop-menu .disabled a:focus {
+ cursor: not-allowed;
+}
+
+.drop-menu .divider {
+ background-color: #ddd;
+ height: 1px;
+ overflow: hidden;
+ margin: 8px 0;
+}
+
+.drop-menu .drop-meun-head {
+ display: block;
+ padding: 5px 20px;
+ font-size: 12px;
+ color: #999;
+}
+
+.open .drop-menu {
+ display: block;
+}
+
+
+/*按钮组*/
+
+.button-group,
+.button-group-y {
+ display: inline-block;
+ position: relative;
+ vertical-align: middle;
+}
+
+.button-group .button,
+.button-group .button-group {
+ float: left;
+ position: relative;
+ font-weight: normal;
+}
+
+.button-group :not(:first-child):not(:last-child):not(.dropdown-toggle):not(.dropdown-hover).button,
+.button-group .button-group .button {
+ border-radius: 0;
+}
+
+.button-group .button,
+.button-group .button-group .button {
+ margin-left: -1px;
+}
+
+.button-group :first-child:not(:last-child).button:not(.dropdown-toggle):not(.dropdown-hover) {
+ border-top-right-radius: 0px;
+ border-bottom-right-radius: 0px;
+}
+
+.button-group :last-child:not(:first-child).button:not(.dropdown-toggle):not(.dropdown-hover) {
+ border-bottom-left-radius: 0px;
+ border-top-left-radius: 0px;
+}
+
+.button-group .button-group:first-child .button:last-child,
+.button-group .button-group:first-child .dropdown-toggle {
+ border-top-left-radius: 5px;
+ border-bottom-left-radius: 5px;
+}
+
+.button-group .button-group:last-child .button:first-child {
+ border-top-right-radius: 5px;
+ border-bottom-right-radius: 5px;
+}
+
+.button-group :not(:first-child).dropdown-toggle {
+ border-bottom-left-radius: 0px;
+ border-top-left-radius: 0px;
+ padding: 6px;
+}
+
+.button-toolbar {
+ display: inline-block;
+}
+
+.button-toolbar .button-group {
+ display: inline-block;
+}
+
+.button-group-y .button,
+.button-group-y .button-group {
+ float: none;
+ clear: both;
+ display: block;
+ width: 100%;
+ font-weight: normal;
+}
+
+.button-group-y :not(:first-child):not(:last-child):not(.dropdown-toggle).button,
+.button-group-y .button-group .button {
+ border-radius: 0;
+}
+
+.button-group-y .button,
+.button-group-y .button-group-y .button,
+.button-group-y .button-group .button {
+ margin-left: 0;
+ margin-top: -1px;
+}
+
+.button-group-y :first-child:not(:last-child).button:not(.dropdown-toggle) {
+ border-bottom-left-radius: 0px;
+ border-bottom-right-radius: 0px;
+}
+
+.button-group-y :last-child:not(:first-child).button:not(.dropdown-toggle) {
+ border-top-right-radius: 0px;
+ border-top-left-radius: 0px;
+}
+
+.button-group-y .button-group:first-child .button:last-child,
+.button-group-y .button-group:first-child .dropdown-toggle {
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+}
+
+.button-group-y .button-group:last-child .button:first-child {
+ border-bottom-left-radius: 5px;
+ border-bottom-right-radius: 5px;
+}
+
+.button-group-justified {
+ display: table;
+ width: 100%;
+ table-layout: fixed;
+ border-collapse: separate;
+ text-align: center;
+}
+
+.button-group-justified > .button,
+.button-group-justified > .button-group {
+ display: table-cell;
+ float: none;
+ width: 1%;
+}
+
+.button-group-justified > .button-group .button {
+ width: 100%;
+ margin: 0;
+}
+
+.button-group-justified .drop-menu {
+ text-align: left;
+}
+
+.button-group-large .button {
+ padding: 15px 20px;
+ font-size: 24px;
+ line-height: 24px;
+ font-weight: bold;
+}
+
+.button-group-big .button {
+ padding: 10px 15px;
+ font-size: 18px;
+ line-height: 22px;
+}
+
+.button-group-small .button {
+ padding: 5px 10px;
+ font-size: 12px;
+ font-weight: normal;
+ line-height: 18px;
+}
+
+.button-group-little .button {
+ padding: 3px 5px;
+ font-size: 12px;
+ font-weight: normal;
+ line-height: 16px;
+}
+
+
+/*单选多选*/
+
+.button-group label input {
+ position: absolute;
+ filter: alpha(opacity=0);
+ opacity: 0;
+ z-index: -1;
+}
+
+.border-red .button.active,
+.border-yellow .button.active,
+.border-blue .button.active,
+.border-green .button.active,
+.border-main .button.active,
+.border-sub .button.active,
+.border-dot .button.active,
+.border-black .button.active,
+.border-gray .button.active {
+ color: #fff;
+}
+
+
+/*按钮下拉*/
+
+.dropup .drop-menu {
+ top: auto;
+ bottom: 100%;
+ margin-bottom: 1px;
+}
+
+
+/*选择*/
+
+.selected-inline li {
+ position: relative;
+ display: inline-block;
+ width: auto;
+ border: solid 1px #ddd;
+ border-radius: 4px;
+ margin-right: 5px;
+ padding: 3px 9px;
+ cursor: pointer;
+}
+
+.selected-inline .selected {
+ border: solid 2px #f60;
+ padding: 2px 8px;
+}
+
+
+/*文字色块*/
+
+.txt {
+ display: inline-block;
+ width: 48px;
+ height: 48px;
+ line-height: 48px;
+ text-align: center;
+ background-color: #f5f5f5;
+}
+
+.txt-border {
+ display: inline-block;
+ width: 48px;
+ height: 48px;
+ line-height: 48px;
+ border: solid 1px #ddd;
+ padding: 3px;
+ vertical-align: bottom;
+}
+
+.txt-border .txt {
+ display: block;
+ width: 100%;
+ height: 100%;
+ line-height: 40px;
+}
+
+.txt.bg-main,
+.txt.bg-sub,
+.txt.bg-dot,
+.txt.bg-black,
+.txt.bg-gray,
+.txt.bg-red,
+.txt.bg-yellow,
+.txt.bg-blue,
+.txt.bg-green {
+ color: #fff;
+}
+
+.txt .bg-main,
+.txt .bg-sub,
+.txt .bg-dot,
+.txt .bg-black,
+.txt .bg-gray,
+.txt .bg-red,
+.txt .bg-yellow,
+.txt .bg-blue,
+.txt .bg-green {
+ color: #fff;
+}
+
+.txt span {
+ font-size: 12px;
+}
+
+.txt-border.txt-large {
+ padding: 5px;
+}
+
+.txt-large {
+ width: 128px;
+ height: 128px;
+ line-height: 128px;
+ font-size: 36px;
+}
+
+.txt-large .txt {
+ width: 116px;
+ height: 116px;
+ line-height: 116px;
+}
+
+.txt-large strong {
+ font-size: 80px;
+ font-weight: normal;
+}
+
+.txt-border.txt-big {
+ padding: 4px;
+}
+
+.txt-big {
+ width: 64px;
+ height: 64px;
+ line-height: 64px;
+ font-size: 20px;
+}
+
+.txt-big .txt {
+ width: 54px;
+ height: 54px;
+ line-height: 54px;
+}
+
+.txt-big strong {
+ font-size: 36px;
+ font-weight: normal;
+}
+
+.txt-border.txt-small {
+ padding: 2px;
+}
+
+.txt-small {
+ width: 32px;
+ height: 32px;
+ line-height: 32px;
+}
+
+.txt-small .txt {
+ width: 26px;
+ height: 26px;
+ line-height: 26px;
+}
+
+.txt-border.txt-little {
+ padding: 1px;
+}
+
+.txt-little {
+ width: 16px;
+ height: 16px;
+ line-height: 16px;
+ font-size: 12px;
+}
+
+.txt-little .txt {
+ width: 12px;
+ height: 12px;
+ line-height: 12px;
+ font-size: 12px;
+}
+
+
+/*媒体*/
+
+.media,
+.media-body {
+ overflow: hidden;
+ zoom: 1;
+}
+
+.media,
+.media .media {
+ margin-top: 15px;
+}
+
+.media:first-child {
+ margin-top: 0;
+}
+
+.media-body {
+ margin-top: 3px;
+}
+
+.media strong {
+ display: block;
+}
+
+.media p {
+ margin: 5px 0 0 0;
+ text-align: justify;
+ line-height: 18px;
+}
+
+.media.media-y {
+ text-align: center;
+}
+
+.media.media-x .media-body {
+ margin: 0;
+}
+
+.media.media-x .float-left {
+ margin-right: 10px;
+}
+
+.media.media-x .float-right {
+ margin-left: 10px;
+}
+
+.media.media-x strong {
+ margin-bottom: 5px;
+}
+
+.media-inline .media {
+ display: inline-block;
+ margin-right: 15px;
+ margin-top: 0;
+}
+
+.media-inline .media:last-child {
+ margin-right: 0;
+}
+
+
+/*表单*/
+
+.input {
+ font-size: 14px;
+ padding: 6px;
+ border: solid 1px #ddd;
+ width: 100%;
+ height: 34px;
+ line-height: 20px;
+ display: block;
+ border-radius: 4px;
+ -webkit-appearance: none;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset;
+ transition: all 1s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+}
+
+.label {
+ padding-bottom: 7px;
+ display: block;
+ line-height: 20px;
+}
+
+.label label {
+ font-weight: bold;
+}
+
+.input-file {
+ display: inline-block;
+ position: relative;
+ overflow: hidden;
+ text-align: center;
+ width: auto;
+ color: #333;
+}
+
+.input-file input[type="file"] {
+ position: absolute;
+ top: 0;
+ right: 0;
+ font-size: 14px;
+ background-color: #fff;
+ transform: translate(-300px, 0px) scale(4);
+ height: 40px;
+ opacity: 0;
+ filter: alpha(opacity=0);
+}
+
+.input:focus {
+ border-color: #09c;
+ transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+}
+
+.input-auto {
+ width: auto;
+ display: inline-block;
+}
+
+input[disabled],
+input[readonly],
+textarea[disabled],
+textarea[readonly],
+select[disabled],
+select[readonly] {
+ cursor: not-allowed;
+ background: #eee;
+}
+
+
+/*IE6无效*/
+
+textarea.input {
+ height: auto;
+}
+
+.input-note,
+.label .float-right {
+ color: #999;
+ font-size: 12px;
+ padding-top: 2px;
+ line-height: 18px;
+}
+
+.field {
+ position: relative;
+}
+
+.form-group {
+ padding-bottom: 10px;
+}
+
+.field-icon .input {
+ text-indent: 25px;
+}
+
+.field-icon .icon {
+ position: absolute;
+ left: 0;
+ right: auto;
+ width: 34px;
+ height: 34px;
+ text-align: center;
+ line-height: 34px;
+ font-size: 16px;
+ font-weight: normal;
+}
+
+.field-icon-right .icon {
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: 34px;
+ height: 34px;
+ text-align: center;
+ line-height: 34px;
+ font-size: 16px;
+ font-weight: normal;
+}
+
+
+/*横向排列form-x*/
+
+.form-x .form-group:after,
+.form-inline:after {
+ clear: both;
+ content: " ";
+ display: block;
+ height: 0;
+ overflow: hidden;
+ visibility: hidden;
+}
+
+@media (min-width: 760px) {
+ .form-x .form-group .label {
+ float: left;
+ width: 15%;
+ text-align: right;
+ padding: 7px 7px 7px 0;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ }
+ .form-x .form-group .field {
+ float: left;
+ width: 85%;
+ }
+ .form-x .form-button {
+ margin-left: 15%;
+ }
+}
+
+@media (min-width: 760px) {
+ .form-inline {
+ display: inline-block;
+ }
+ .form-inline .input {
+ width: auto;
+ display: inline-block;
+ }
+ .form-inline .form-group {
+ display: inline-table;
+ padding-bottom: 0;
+ vertical-align: middle;
+ }
+ .form-inline .form-group .input-group {
+ display: inline-table;
+ width: auto;
+ vertical-align: middle;
+ }
+ .form-inline .form-group .input-group .input {
+ width: auto;
+ }
+ .form-inline .form-group .label {
+ display: inline-block;
+ }
+ .form-inline .form-group .field {
+ display: inline-block;
+ }
+ .form-inline .form-button {
+ display: inline-block;
+ vertical-align: middle;
+ }
+ .form-inline .form-button .button {
+ width: auto;
+ }
+ .form-auto .input {
+ width: auto;
+ display: inline-block;
+ }
+ .form-auto .input-group {
+ display: inline-table;
+ width: auto;
+ display: inline-block;
+ }
+ .form-auto .input-group .input {
+ width: auto;
+ display: inline-block;
+ }
+ .input-inline {
+ padding-left: 1px;
+ }
+ .input-inline input {
+ position: relative;
+ float: left;
+ border-radius: 0;
+ margin-left: -1px;
+ width: auto;
+ }
+ .form-small .input-inline input,
+ .form-big .input-inline input {
+ border-radius: 0;
+ }
+ .input-inline input:first-child {
+ left: 1px;
+ border-radius: 4px 0 0 4px;
+ }
+ .input-inline input:last-child {
+ border-radius: 0 4px 4px 0;
+ }
+}
+
+.input-block {
+ padding-top: 8px;
+}
+
+.input-block:first-child {
+ padding-top: 1px;
+}
+
+.input-block input {
+ position: relative;
+ margin-top: -1px;
+ border-radius: 0;
+}
+
+.form-small .input-block input,
+.form-big .input-block input {
+ border-radius: 0;
+}
+
+.input-block input:first-child {
+ border-radius: 4px 4px 0 0;
+}
+
+.input-block input:last-child {
+ border-radius: 0 0 4px 4px;
+}
+
+.label-block label {
+ display: block;
+ line-height: 24px;
+}
+
+
+/*输入框组*/
+
+.input-group {
+ border-collapse: separate;
+ display: table;
+ position: relative;
+}
+
+.input-group .addon,
+.input-group .addbtn,
+.input-group .input {
+ display: table-cell;
+}
+
+.input-group .addon,
+.input-group .addbtn {
+ width: 1%;
+ white-space: nowrap;
+ vertical-align: middle;
+}
+
+.input-group .addbtn .button {
+ font-weight: normal;
+}
+
+.input-group .input {
+ width: 100%;
+}
+
+.input-group .addon {
+ background-color: #f5f5f5;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ line-height: 1;
+ padding: 6px 12px;
+ text-align: center;
+}
+
+.input-group .addon:first-child,
+.input-group .addbtn:first-child .button {
+ border-right: 0 none;
+}
+
+.input-group .addon:first-child,
+.input-group .addbtn:first-child .button,
+.input-group .input:first-child {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.input-group .addon:last-child,
+.input-group .addbtn:last-child .button {
+ border-left: 0 none;
+}
+
+.input-group .addon:last-child,
+.input-group .addbtn:last-child .button,
+.input-group .input:last-child {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.input-group .addon:not(:first-child):not(:last-child),
+.input-group .addbtn:not(:first-child):not(:last-child) .button,
+.input-group .input:not(:first-child):not(:last-child) {
+ border-radius: 0;
+}
+
+
+/*验证提示*/
+
+.form-tips .form-group .field {
+ position: relative;
+ zoom: 1;
+}
+
+.form-tips .input-help {
+ position: absolute;
+ z-index: 1;
+ float: left;
+ left: 0;
+ top: 100%;
+}
+
+.form-tips .input-help ul {
+ border: solid 1px #ddd;
+ background: #fff;
+ padding: 10px 10px 10px 25px;
+ box-shadow: 0 0 5px #ddd;
+ border-radius: 4px;
+ width: 160px;
+ min-width: 160px;
+ width: auto;
+ _width: 160px;
+}
+
+
+/*尺寸*/
+
+.input-big,
+.form-big .input,
+.form-big .button {
+ padding: 10px;
+ font-size: 16px;
+ line-height: 24px;
+ height: 46px;
+}
+
+.input-small,
+.form-small .input,
+.form-small .button {
+ padding: 5px;
+ font-size: 12px;
+ line-height: 18px;
+ height: 28px;
+}
+
+.form-small .addon,
+.form-small .addbtn {
+ padding: 5px 8px;
+ font-size: 12px;
+}
+
+
+/*列表组*/
+
+.list-group,
+.list-link {
+ border: solid 1px #ddd;
+ border-radius: 4px;
+ list-style: none;
+ padding: 0;
+}
+
+.list-group li,
+.list-link a {
+ padding: 10px 15px;
+ display: block;
+ border-bottom: solid 1px #ddd;
+ transition: all 1s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+}
+
+.list-group li:last-child,
+.list-link a:last-child {
+ border-bottom: 0 none;
+}
+
+.list-striped li:nth-child(odd) {
+ background-color: #f5f5f5;
+}
+
+.list-link a {
+ color: #333;
+}
+
+.list-link a:hover {
+ background-color: #f5f5f5;
+ transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+}
+
+.list-link a.active:link,
+.list-link a.active:visited {
+ background-color: #f5f5f5;
+}
+
+
+/*面板*/
+
+.panel {
+ border: solid 1px #ddd;
+ border-radius: 4px;
+}
+
+.panel-head {
+ background-color: #f5f5f5;
+ padding: 10px 15px;
+ border-radius: 4px 4px 0 0;
+ border-bottom: solid 1px #ddd;
+}
+
+.panel-foot {
+ background-color: #f5f5f5;
+ padding: 10px 15px;
+ border-radius: 0 0 4px 4px;
+ border-top: solid 1px #ddd;
+}
+
+.panel-body {
+ padding: 15px;
+}
+
+.panel .bg-main,
+.panel .bg-sub,
+.panel .bg-dot,
+.panel .bg-red,
+.panel .bg-yellow,
+.panel .bg-green {
+ color: #fff;
+}
+
+.panel .panel-body + .table,
+.panel .panel-body + .list-group {
+ border-top: solid 1px #ddd;
+}
+
+.panel .list-group {
+ border: none;
+ border-radius: 0;
+}
+
+
+/*面板组*/
+
+.panel-group {
+ border-top: solid 1px #ddd;
+ border-bottom: solid 1px #ddd;
+ border-left: none;
+ border-right: none;
+ list-style: none;
+ padding: 15px;
+}
+
+
+/*选项标签*/
+
+.tab .tab-head strong {
+ float: left;
+ padding: 8px 20px 0 0;
+ line-height: 20px;
+}
+
+.tab .tab-more {
+ float: right;
+ margin: 10px 0 0 10px;
+ font-size: 12px;
+}
+
+.tab .tab-nav {
+ list-style: none;
+}
+
+.tab .tab-nav li {
+ display: inline-block;
+}
+
+.tab .tab-nav li a {
+ color: #333;
+ padding: 8px 20px;
+ display: block;
+ border: solid 1px #ddd;
+ line-height: 20px;
+ border-bottom: none;
+ border-radius: 4px 4px 0 0;
+}
+
+.tab .tab-nav .active {
+ background-color: #fff;
+}
+
+.tab .tab-nav .active a {
+ cursor: default;
+}
+
+.tab .tab-body {
+ border-top: solid 1px #ddd;
+ margin-top: -1px;
+ padding-top: 15px;
+}
+
+.tab .tab-body-bordered {
+ border: solid 1px #ddd;
+ border-radius: 4px;
+ padding: 15px;
+}
+
+.tab .tab-body .tab-panel {
+ display: none;
+}
+
+.tab .tab-body .active {
+ display: block;
+}
+
+.tab.tab-small strong {
+ padding-top: 3px;
+}
+
+.tab.tab-small .tab-more {
+ margin: 5px 0 0 10px;
+}
+
+.tab.tab-small li a {
+ padding: 3px 10px;
+}
+
+
+/*对话框*/
+
+.dialog-mask {
+ position: fixed;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ background: #000;
+ z-index: 10;
+ filter: alpha(opacity=50);
+ opacity: .5;
+ display: block;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+.dialog {
+ border: 1px solid #ddd;
+ box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+ border-radius: 4px;
+ background-color: #fff;
+ display: none;
+}
+
+.dialog .dialog-head,
+.dialog .dialog-foot {
+ padding: 10px 20px;
+}
+
+.dialog .dialog-head {
+ border-bottom: solid 1px #ddd;
+ background-color: #f5f5f5;
+ border-radius: 4px 4px 0 0;
+}
+
+.dialog .dialog-head strong {
+ font-size: 16px;
+}
+
+.dialog .dialog-head .close {
+ float: right;
+ line-height: 24px;
+}
+
+.dialog .dialog-body {
+ padding: 15px 20px;
+}
+
+.dialog .dialog-foot {
+ text-align: right;
+ border-top: solid 1px #ddd;
+}
+
+.dialog.open {
+ display: block;
+}
+
+
+/*提示信息*/
+
+.tip {
+ display: inline-block;
+ background-color: #f5f5f5;
+ border: 1px solid #ddd;
+ border-radius: 3px;
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
+}
+
+.tip p {
+ margin: 0px;
+}
+
+.tip .tip-line {
+ margin: 0px;
+ padding: 2px 5px;
+ font-size: 12px;
+ line-height: 16px;
+}
+
+.tip .tip-title {
+ padding: 2px 8px;
+}
+
+.tip .tip-body {
+ padding: 8px;
+ background: #fff;
+ color: #666;
+ border-radius: 0 0 3px 3px;
+ font-size: 12px;
+ line-height: 20px;
+}
+
+.tip .image {
+ border-radius: 3px;
+}
+
+.tip-bottom.border-red .arrow {
+ border-bottom-color: #f00;
+}
+
+.tip.bg-main,
+.tip.bg-sub,
+.tip.bg-dot,
+.tip.bg-red,
+.tip.bg-yellow,
+.tip.bg-green {
+ color: #fff;
+}
+
+
+/*警告框*/
+
+.alert {
+ border-radius: 5px;
+ padding: 15px;
+ border: solid 1px #ddd;
+ background-color: #f5f5f5;
+}
+
+.alert .close {
+ float: right;
+ line-height: 18px;
+}
+
+
+/*多选单选*/
+
+.radio .icon,
+.checkbox .icon {
+ display: none;
+}
+
+.radio .active .icon,
+.checkbox .active .icon {
+ display: inline-block;
+}
+
+
+/*折叠*/
+
+.collapse .panel {
+ margin-bottom: 5px;
+}
+
+.collapse .panel:last-child {
+ margin-bottom: 0;
+}
+
+.collapse .panel .panel-head {
+ border-bottom-width: 0;
+}
+
+.collapse .panel .panel-body {
+ display: none;
+}
+
+.collapse .panel.active .panel-head {
+ border-bottom-width: 1px;
+}
+
+.collapse .panel.active .panel-body {
+ display: block;
+}
+
+.collapse .panel.toggle-actvie .panel-head {
+ border-bottom-width: 1px;
+}
+
+.collapse .panel.toggle-actvie .panel-body {
+ display: block;
+}
+
+
+/*banner*/
+
+.banner {
+ position: relative;
+ width: 100%;
+ overflow: hidden;
+}
+
+.carousel {
+ position: relative;
+ list-style: none;
+ padding: 0;
+}
+
+.carousel .item {
+ display: nones;
+ float: left;
+ position: relative;
+}
+
+.carousel .active {
+ display: block;
+}
+
+.carousel img {
+ display: block;
+ max-width: 100%;
+ height: auto;
+}
+
+.banner .pointer {
+ position: absolute;
+ bottom: 0;
+ padding: 15px;
+}
+
+.banner .pager-prev,
+.banner .pager-next {
+ position: absolute;
+ display: none;
+ top: 50%;
+ margin-top: -25px;
+}
+
+.banner .pager-prev {
+ left: 20px;
+}
+
+.banner .pager-next {
+ right: 20px;
+}
+
+.banner:hover .pager-prev,
+.banner:hover .pager-next {
+ display: block;
+}
+
+
+/*导航列表按钮*/
+
+.icon-navicon {
+ display: none;
+}
+
+@media (max-width: 760px) {
+ .icon-navicon {
+ display: block;
+ }
+ .nav-navicon,
+ .nav.nav-navicon,
+ .navbar-body.nav-navicon {
+ display: none;
+ }
+}
+
+
+/*默认导航*/
+
+.nav {
+ list-style: none;
+ padding: 5px 0 0 0;
+ margin: 0;
+}
+
+.nav li {
+ position: relative;
+}
+
+.nav a {
+ color: #333;
+ line-height: 20px;
+ padding: 5px 0;
+ transition: all 1s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+ display: block;
+}
+
+.nav a:hover {
+ transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+}
+
+.nav .arrow {
+ display: none;
+}
+
+.nav .active a {
+ font-weight: bold;
+}
+
+.nav-head {
+ font-size: 14px;
+ font-weight: bold;
+ height: 30px;
+ line-height: 30px;
+}
+
+@media (min-width: 760px) {
+ /*默认-内联*/
+ .nav {
+ padding: 0;
+ }
+ .nav-inline .nav-head {
+ padding-right: 20px;
+ }
+ .nav-inline li {
+ display: inline-block;
+ vertical-align: top;
+ }
+ .nav-inline li a {
+ padding: 5px 20px;
+ line-height: 20px;
+ display: block;
+ }
+ .nav-inline .nav-more {
+ float: right;
+ }
+ /*导航分隔线*/
+ .nav-split .nav-head {
+ height: 20px;
+ line-height: 20px;
+ }
+ .nav-split li {
+ border-right: solid 1px rgba(0, 0, 0, .20);
+ }
+ .nav-split li a {
+ padding: 0px 20px;
+ }
+ .nav-split .nav-head,
+ .nav-split ul li,
+ .nav-split li:last-child {
+ border-right-width: 0;
+ }
+ /*右对齐*/
+ .nav-right {
+ text-align: right;
+ }
+ .nav-right .nav-head {
+ float: left;
+ }
+ /*两端对齐*/
+ .nav.nav-justified {
+ display: table;
+ width: 100%;
+ }
+ .nav-justified .nav-head {
+ padding: 0 20px;
+ float: none;
+ }
+ .nav-justified .nav-more {
+ float: none;
+ }
+ .nav-justified li {
+ display: table-cell;
+ }
+ .nav-justified .nav-head,
+ .nav-justified li a {
+ text-align: center;
+ display: block;
+ }
+ .nav-justified.nav-split .nav-head {
+ padding: 0 20px;
+ border-right-width: 1px;
+ }
+ /*大号*/
+ .nav-big .nav-head {
+ font-size: 18px;
+ height: 30px;
+ line-height: 30px;
+ padding: 0 20px;
+ }
+ .nav-big a {
+ font-size: 18px;
+ line-height: 30px;
+ }
+ .nav-big.nav-split a {
+ line-height: 30px;
+ }
+}
+
+
+/*主要导航*/
+
+.nav-main .nav-head {
+ border: solid 1px #ddd;
+ background: #ddd;
+ padding: 0 20px;
+ line-height: 28px;
+}
+
+.nav-main li {
+ margin-top: -1px;
+}
+
+.nav-main a {
+ border: solid 1px #ddd;
+ padding: 4px 20px;
+}
+
+.nav-main a:hover {
+ background: #f5f5f5;
+ transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+}
+
+.nav-main .active {
+ background-color: #f5f5f5;
+}
+
+.nav-main li:first-child,
+.nav-main li:first-child a {
+ border-radius: 4px 4px 0 0;
+}
+
+.nav-main li:last-child a {
+ border-radius: 0 0 4px 4px;
+}
+
+.nav-main ul li:first-child a,
+.nav-main ul li:last-child a {
+ border-radius: 0;
+}
+
+@media (min-width: 760px) {
+ /*主要导航-内联*/
+ .nav-main.nav-inline {
+ padding: 0 0 0 1px;
+ }
+ .nav-main.nav-inline a {
+ padding: 4px 20px;
+ }
+ .nav-main.nav-inline li {
+ float: left;
+ margin: 0 0 0 -1px;
+ }
+ .nav-main.nav-inline li:first-child,
+ .nav-main.nav-inline li:first-child a {
+ border-radius: 4px 0 0 4px;
+ }
+ .nav-main.nav-inline li:last-child a {
+ border-radius: 0 4px 4px 0;
+ }
+ .nav-main.nav-inline ul li {
+ float: none;
+ margin: 0;
+ }
+ .nav-main.nav-justified .nav-head {
+ float: none;
+ }
+ .nav-main.nav-justified {
+ width: 100%;
+ display: table;
+ }
+ .nav-main.nav-justified li {
+ width: auto;
+ float: none;
+ margin-left: -1px;
+ }
+ .nav-main.nav-justified > li + li > a {
+ border-left: 0 none;
+ }
+ .nav-main.nav-big .nav-head {
+ height: 40px;
+ line-height: 38px;
+ }
+ .nav-main.nav-big.nav-inline a {
+ line-height: 30px;
+ }
+}
+
+.nav-main.border-main .nav-head,
+.nav-main.border-sub .nav-head,
+.nav-main.border-dot .nav-head,
+.nav-main.border-black .nav-head,
+.nav-main.border-gray .nav-head,
+.nav-main.border-red .nav-head,
+.nav-main.border-yellow .nav-head,
+.nav-main.border-blue .nav-head,
+.nav-main.border-green .nav-head {
+ color: #fff;
+}
+
+
+/*辅助导航*/
+
+.nav-sub .nav-head {
+ border-bottom: solid 2px #ddd;
+ margin-bottom: 2px;
+ padding: 0 20px;
+ height: 30px;
+ line-height: 28px;
+}
+
+.nav-sub a {
+ border-bottom: solid 2px #ddd;
+ display: block;
+ margin-bottom: 2px;
+ border-radius: 4px 4px 0 0;
+ padding: 4px 20px;
+}
+
+.nav-sub a:hover {
+ background: #f5f5f5;
+}
+
+.nav-sub .active a {
+ border-color: #333;
+}
+
+@media (min-width: 760px) {
+ .nav-sub.nav-inline li {
+ float: left;
+ margin: 0;
+ }
+ .nav-sub.nav-inline a {
+ padding: 4px 20px;
+ margin: 0;
+ }
+ .nav-sub.nav-justified {
+ width: 100%;
+ display: table;
+ }
+ .nav-sub.nav-justified li {
+ width: auto;
+ float: none;
+ }
+ .nav-sub.nav-big .nav-head {
+ line-height: 38px;
+ height: 40px;
+ }
+ .nav-sub.nav-big a {
+ line-height: 30px;
+ }
+}
+
+
+/*标签导航*/
+
+.nav-tabs .nav-head {
+ line-height: 30px;
+ padding: 0 20px;
+}
+
+.nav-tabs a {
+ display: block;
+ border-radius: 4px;
+ padding: 5px 20px;
+ margin-bottom: 2px;
+}
+
+.nav-tabs .active a {
+ border: solid 1px #ddd;
+ padding-top: 4px;
+ padding-bottom: 4px;
+}
+
+.nav-tabs a:hover {
+ background: #f5f5f5;
+}
+
+@media (min-width: 760px) {
+ .nav-tabs.nav-inline {
+ border-bottom: solid 1px #ddd;
+ position: relative;
+ }
+ .nav-tabs.nav-inline .nav-head {
+ height: 29px;
+ line-height: 29px;
+ }
+ .nav-tabs.nav-inline a {
+ border-radius: 4px 4px 0 0;
+ text-align: center;
+ margin: 0;
+ position: relative;
+ padding-bottom: 4px;
+ }
+ .nav-tabs.nav-inline .active a {
+ border-bottom: none;
+ background: #fff;
+ margin-bottom: -1px;
+ padding: 4px 20px 5px 20px;
+ }
+ .nav-tabs.nav-big .nav-head {
+ line-height: 39px;
+ height: 39px;
+ }
+ .nav-tabs.nav-big a {
+ padding: 10px 20px 9px 20px;
+ }
+ .nav-tabs.nav-big .active a {
+ padding: 9px 20px 10px 20px;
+ }
+}
+
+
+/*胶囊导航*/
+
+.nav-pills .nav-head {
+ line-height: 30px;
+ padding: 0 20px;
+}
+
+.nav-pills a {
+ display: block;
+ border-radius: 2em;
+ margin-bottom: 2px;
+ padding: 5px 20px;
+}
+
+.nav-pills .active a,
+.nav-pills a:hover {
+ background: #f5f5f5;
+}
+
+.nav-pills .active ul a {
+ background: #fff;
+}
+
+@media (min-width: 760px) {
+ .nav-pills.nav-inline a {
+ margin: 0;
+ }
+ .nav-pills.nav-justified {
+ width: 100%;
+ display: table;
+ }
+ .nav-pills.nav-justified li {
+ width: auto;
+ }
+ .nav-pills.nav-big .nav-head {
+ line-height: 40px;
+ height: 40px;
+ }
+ .nav-pills.nav-big.nav-inline a {
+ line-height: 30px;
+ }
+}
+
+.nav-pills.border-main .active a,
+.nav-pills.border-sub .active a,
+.nav-pills.border-dot .active a,
+.nav-pills.border-black .active a,
+.nav-pills.border-gray .active a,
+.nav-pills.border-red .active a,
+.nav-pills.border-yellow .active a,
+.nav-pills.border-blue .active a,
+.nav-pills.border-green .active a {
+ color: #fff;
+}
+
+
+/*站点地图*/
+
+.nav.nav-sitemap {
+ list-style: none;
+ display: table;
+ width: 100%;
+ margin-bottom: 15px;
+}
+
+.nav-sitemap ul {
+ padding-left: 0;
+}
+
+.nav-sitemap li {
+ font-weight: bold;
+ display: table-cell;
+ text-align: left;
+}
+
+.nav-sitemap ul li {
+ display: block;
+ float: none;
+ font-weight: normal;
+ line-height: 25px;
+}
+
+
+/*反色*/
+
+.bg-inverse .nav {
+ padding: 5px 0;
+}
+
+.bg-inverse .nav li a:hover,
+.bg-inverse .nav .active a {
+ background-color: rgba(0, 0, 0, .20);
+ color: #fff;
+}
+
+.bg-inverse .nav-inline .nav-head,
+.bg-inverse .nav-inline li a {
+ text-indent: 1em;
+}
+
+
+/*for mobile*/
+
+@media (min-width: 760px) {
+ .bg-inverse .nav {
+ padding: 0;
+ }
+ .bg-inverse .nav-inline .nav-head {
+ height: 40px;
+ line-height: 40px;
+ padding: 0 20px;
+ text-indent: 0;
+ }
+ .bg-inverse .nav-inline li {
+ float: left;
+ margin-right: 1px;
+ }
+ .bg-inverse .nav-inline li a {
+ line-height: 30px;
+ padding: 5px 20px;
+ text-indent: 0;
+ }
+ .bg-inverse .nav-split .nav-head {
+ border-right-width: 1px;
+ }
+ .bg-inverse .nav-split li {
+ margin: 0;
+ }
+ .bg-inverse .nav-justified li {
+ float: none;
+ }
+ .bg-inverse .nav-inline.nav-big li a {
+ line-height: 40px;
+ }
+ .bg-inverse .nav-inline.nav-big .nav-head {
+ height: 50px;
+ line-height: 50px;
+ padding: 0 20px;
+ }
+}
+
+.bg-inverse .nav-tabs {
+ padding: 5px;
+}
+
+.bg-inverse .nav-tabs .nav-head,
+.bg-inverse .nav-tabs li a {
+ text-indent: 0;
+}
+
+.bg-inverse .nav-tabs.nav-inline,
+.bg-inverse .nav-tabs li a {
+ border: none;
+}
+
+.bg-inverse .nav.nav-tabs .active a,
+.bg-inverse .nav.nav-tabs a:hover {
+ color: #333;
+ background-color: #fff;
+ padding-top: 5px;
+ padding-bottom: 5px;
+}
+
+@media (min-width: 760px) {
+ .bg-inverse .nav-tabs {
+ padding: 0;
+ }
+ .bg-inverse .nav-tabs li a {
+ margin: 5px 0;
+ padding: 5px 20px;
+ line-height: 20px;
+ border-radius: 4px;
+ }
+ .bg-inverse .nav.nav-tabs .active a {
+ margin: 5px 0 0 0;
+ border: none;
+ line-height: 25px;
+ border-radius: 4px 4px 0 0;
+ }
+ .bg-inverse .nav.nav-tabs.nav-big a {
+ margin: 5px 0;
+ padding: 0 20px;
+ }
+ .bg-inverse .nav.nav-tabs.nav-big .active a {
+ margin: 5px 0 0 0;
+ padding: 0 20px;
+ line-height: 45px;
+ }
+}
+
+.bg-inverse .nav-pills {
+ padding: 5px;
+}
+
+.bg-inverse .nav-pills .nav-head,
+.bg-inverse .nav-pills li a {
+ text-indent: 0;
+}
+
+@media (min-width: 760px) {
+ .bg-inverse .nav-pills {
+ padding: 0;
+ }
+ .bg-inverse .nav-pills li a {
+ line-height: 20px;
+ margin: 5px 0;
+ }
+ .bg-inverse .nav-pills.nav-big li a {
+ line-height: 30px;
+ margin: 5px 0;
+ padding: 5px 20px;
+ }
+}
+
+.bg-inverse .nav-sitemap li a {
+ text-indent: 0.5em;
+}
+
+.bg-inverse .nav.nav-pills .active a,
+.bg-inverse .nav.nav-pills.nav-inline a:hover {
+ color: #333;
+ background-color: #fff;
+}
+
+
+/*导航条*/
+
+.navbar {
+ position: relative;
+}
+
+.navbar-head {
+ padding: 5px;
+ line-height: 30px;
+}
+
+.navbar-head .logo {
+ padding: 3px 0;
+ display: block;
+}
+
+.navbar-head .icon-navicon {
+ padding: 4px 12px;
+ font-size: 16px;
+ float: right;
+}
+
+.navbar-big .navbar-head .icon-navicon {
+ margin-top: 5px;
+}
+
+.navbar-big .navbar-head .logo {
+ padding: 2px 0;
+ display: block;
+}
+
+.navbar p {
+ margin: 0;
+}
+
+.navbar-body {
+ border: solid 1px rgba(0, 0, 0, .2);
+ margin-top: 1px;
+ border-top: none;
+ display: block;
+ background: rgba(0, 0, 0, .05);
+ position: absolute-bak;
+ width: 100%;
+}
+
+.navbar-body .nav {
+ margin-top: -1px;
+ padding: 0;
+}
+
+.navbar-body .nav a {
+ text-indent: 1em;
+}
+
+.navbar-body .nav li {
+ border-top: solid 1px rgba(0, 0, 0, .2);
+}
+
+.navbar-form input {
+ vertical-align: bottom;
+}
+
+.navbar-form,
+.navbar-text {
+ border-top: solid 1px rgba(0, 0, 0, .2);
+ padding: 5px 14px;
+ margin-top: -1px;
+}
+
+.navbar-body .input,
+.navbar-body .button {
+ padding: 4px 10px;
+ height: 30px;
+}
+
+.navbar-body .nav-pills a {
+ text-indent: 0;
+}
+
+@media (max-width: 760px) {
+ .navbar-body .nav a {
+ border-radius: 0;
+ margin-bottom: 0px;
+ }
+ .navbar-body .nav a:hover {
+ background: #fff;
+ }
+}
+
+@media (min-width: 760px) {
+ .navbar-body,
+ .navbar-body .nav,
+ .navbar-form,
+ .navbar-text {
+ margin-top: 0;
+ border: 0;
+ }
+ .navbar-body .nav a {
+ text-indent: 0;
+ }
+ .navbar-head {
+ float: left;
+ padding: 0 5px 0 0;
+ }
+ .navbar-body {
+ background: transparent;
+ margin: 0;
+ position: relative;
+ }
+ .navbar-body .nav li {
+ float: left;
+ border: 0;
+ }
+ .navbar-body .nav ul li {
+ float: none;
+ }
+ .navbar-form {
+ padding: 0 10px;
+ }
+ .navbar-text {
+ padding: 0;
+ line-height: 30px;
+ }
+ .navbar-left {
+ float: left;
+ }
+ .navbar-right {
+ float: right;
+ }
+ .bg-inverse .navbar-head,
+ .bg-inverse .navbar-text {
+ padding: 5px;
+ }
+ .bg-inverse .navbar-form {
+ padding: 5px 10px;
+ }
+ .navbar-big .navbar-head {
+ line-height: 40px;
+ }
+ .navbar-big .navbar-text {
+ padding: 8px;
+ font-size: 18px;
+ }
+ .navbar-big .navbar-form {
+ padding: 8px 10px;
+ }
+ .navbar-big .navbar-body .input,
+ .navbar-big .navbar-body .button {
+ padding: 5px 10px;
+ height: 34px;
+ }
+ .navbar-big .nav-pills a {
+ margin: 5px 0;
+ }
+}
+
+
+/*子菜单*/
+
+.nav ul {
+ display: block;
+ list-style: none;
+ padding: 0;
+}
+
+.nav ul a {
+ font-weight: normal;
+ padding: 5px 20px;
+}
+
+.nav ul ul a {
+ padding-left: 40px;
+}
+
+.nav ul ul ul a {
+ padding-left: 60px;
+}
+
+.nav ul ul ul ul a {
+ padding-left: 80px;
+}
+
+.nav .active ul a {
+ font-weight: normal;
+}
+
+
+/*下拉菜单*/
+
+.nav-menu .drop-menu {
+ display: none;
+ margin-top: -1px;
+}
+
+.nav-menu ul {
+ padding: 5px 0;
+}
+
+.nav-menu .arrow {
+ display: inline-block;
+}
+
+.nav-menu ul .arrow {
+ display: none;
+}
+
+.nav-menu li:hover ul {
+ display: block;
+}
+
+.nav-menu.nav-big ul a {
+ line-height: 20px;
+}
+
+.nav-menu ul ul,
+.nav-menu.nav-main ul ul,
+.nav-menu.nav-sub ul ul,
+.nav-menu.nav-tabs ul ul,
+.nav-menu.nav-pills ul ul {
+ padding: 0;
+}
+
+
+/*去除三级菜单的间隙*/
+
+.nav-menu ul a,
+.nav-menu.nav-tabs ul a,
+.nav-menu.nav-pills .active ul a,
+.nav-menu.nav-big.nav-inline ul a,
+.bg-inverse .nav-menu.nav-inline ul a,
+.bg-inverse .nav-menu.nav-inline .active ul a,
+.bg-inverse .nav-menu.nav-inline.nav-big ul a,
+.bg-inverse .nav-menu.nav-inline.nav-big .active ul a,
+.navbar-body .nav ul a {
+ line-height: 20px;
+ background: #fff;
+ font-size: inherit;
+ border: none;
+ border-radius: 0;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ margin: 0;
+ text-indent: 0;
+}
+
+
+/*清除二级导航样式*/
+
+.nav-menu ul a,
+.nav-menu.nav-pills .active ul a,
+.bg-inverse .nav-menu ul a,
+.bg-inverse .nav-menu .active ul a {
+ color: #333;
+}
+
+.navbar-body .nav ul li {
+ border: 0;
+}
+
+@media (min-width: 760px) {
+ .nav-menu ul {
+ position: absolute;
+ display: none;
+ left: 100%;
+ top: -6px;
+ z-index: 1;
+ float: left;
+ min-width: 160px;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, .15);
+ border-radius: 4px;
+ -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+ box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+ }
+ .nav-menu .arrow {
+ display: inline-block;
+ float: right;
+ margin-top: 6px;
+ border-left: 4px solid;
+ border-top: 4px solid transparent;
+ border-bottom: 4px solid transparent;
+ }
+ .nav-menu ul .arrow {
+ margin: 6px -10px 0 0;
+ display: inline-block;
+ }
+ .nav-menu ul a,
+ .nav-menu ul ul a,
+ .nav-menu ul ul ul a,
+ .nav-menu ul ul ul ul a {
+ padding-left: 20px;
+ }
+ .nav-menu ul ul {
+ padding: 5px 0;
+ }
+ .nav-menu li:hover ul ul,
+ .nav-menu li:hover ul ul ul,
+ .nav-menu li:hover ul ul ul ul {
+ display: none;
+ }
+ .nav-menu li:hover ul,
+ .nav-menu li li:hover ul,
+ .nav-menu li li li:hover ul,
+ .nav-menu li li li li:hover ul {
+ display: block;
+ }
+ /*内联*/
+ .nav-inline.nav-menu ul {
+ top: 100%;
+ left: 0;
+ }
+ .nav-inline.nav-menu ul li {
+ display: block;
+ }
+ .nav-inline.nav-menu ul ul {
+ top: -6px;
+ left: 100%;
+ }
+ .nav-inline.nav-menu ul a {
+ display: block;
+ padding: 5px 20px;
+ text-align: left;
+ font-size: inherit;
+ }
+ .nav-inline.nav-menu ul a:hover {
+ background: #f5f5f5;
+ }
+ .nav-inline.nav-menu .arrow {
+ float: none;
+ border-top: 4px solid;
+ border-right: 4px solid transparent;
+ border-left: 4px solid transparent;
+ margin-top: 0;
+ }
+ .nav-inline.nav-menu ul .arrow {
+ float: right;
+ margin-top: 6px;
+ border-left: 4px solid;
+ border-top: 4px solid transparent;
+ border-bottom: 4px solid transparent;
+ }
+ .nav-main .arrow,
+ .nav-main.nav-inline ul .arrow,
+ .nav-sub .arrow,
+ .nav-sub.nav-inline ul .arrow,
+ .nav-tabs .arrow,
+ .nav-tabs.nav-inline ul .arrow,
+ .nav-pills .arrow,
+ .nav-pills.nav-inline ul .arrow {
+ margin-right: -10px;
+ }
+ .nav-main.nav-inline .arrow,
+ .nav-sub.nav-inline .arrow,
+ .nav-tabs.nav-inline .arrow,
+ .nav-pills.nav-inline .arrow {
+ margin-right: 0;
+ }
+ .nav-menu ul ul,
+ .nav-menu.nav-main ul ul,
+ .nav-menu.nav-sub ul ul,
+ .nav-menu.nav-tabs ul ul,
+ .nav-menu.nav-pills ul ul {
+ padding: 5px 0;
+ }
+ .nav-main.nav-inline ul li,
+ .nav-sub.nav-inline ul li,
+ .bg-inverse .nav-inline ul li {
+ float: none;
+ }
+}
+
+
+/*固定*/
+
+.fixed-top {
+ position: fixed;
+ top: 0;
+}
+
+.fixed-bottom {
+ position: fixed;
+ bottom: 0;
+}
+
+.fixed-left {
+ position: fixed;
+ left: 0;
+}
+
+.fixed-right {
+ position: fixed;
+ right: 0;
+}
+
+.fixed-top-left {
+ position: fixed;
+ top: 0;
+ left: 0;
+}
+
+.fixed-top-right {
+ position: fixed;
+ top: 0;
+ right: 0;
+}
+
+.fixed-bottom-left {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+}
+
+.fixed-bottom-right {
+ position: fixed;
+ bottom: 0;
+ right: 0;
+}
+
+
+/*路径导航*/
+
+.bread {
+ border-radius: 4px;
+ padding: 8px 15px;
+ font-size: 12px;
+ margin-bottom: 15px;
+ color: #999;
+}
+
+.bread li {
+ display: inline-block;
+}
+
+.bread li:after {
+ content: "\002f";
+ padding: 0 8px;
+ color: #ddd;
+}
+
+.bread li:last-child:after {
+ content: "";
+}
+
+.step {
+ position: relative;
+ height: 10px;
+ border-radius: 5px;
+ background-color: #f5f5f5;
+ margin-bottom: 30px;
+ border-radius: 5px;
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+}
+
+.step-bar {
+ position: relative;
+ height: 10px;
+ float: left;
+ display: inline-block;
+ text-align: center;
+ color: #aaa;
+}
+
+.step-bar:first-child {
+ border-radius: 5px 0 0 5px;
+}
+
+.step-bar:last-child {
+ border-radius: 0 5px 5px 0;
+}
+
+.step-point {
+ position: relative;
+ display: inline-block;
+ width: 20px;
+ height: 20px;
+ line-height: 20px;
+ top: -5px;
+ border-radius: 50%;
+ color: #fff;
+ background-color: #bbb;
+ -webkit-box-shadow: 1px 1px 1px rgba(0, 0, 0, .175);
+ box-shadow: 1px 1px 1px rgba(0, 0, 0, .175);
+}
+
+.step-text {
+ display: block;
+}
+
+.step .complete,
+.step .complete .step-point {
+ background: #cf9;
+}
+
+.step .active,
+.step .active .step-point {
+ background: #0a0;
+}
+
+
+/*列表*/
+
+.list-text {
+ list-style: inside;
+ padding: 0;
+}
+
+.list-text li {
+ line-height: 24px;
+}
+
+.list-text .date {
+ font-size: 12px;
+ float: right;
+}
+
+.list-text .divider {
+ list-style-type: none;
+ background-color: #ddd;
+ height: 1px;
+ overflow: hidden;
+ margin: 15px 0;
+}
+
+.list-text.list-underline {
+ list-style: outside;
+ padding-left: 15px;
+}
+
+.list-text.list-underline li {
+ border-bottom: solid 1px #ddd;
+ line-height: 36px;
+}
+
+.list-underline.list-striped li {
+ padding: 0 10px;
+}
+
+.list-text.list-striped {
+ list-style: none;
+ padding: 0;
+}
+
+.list-box a {
+ background-color: #f5f5f5;
+ display: block;
+ padding: 15px;
+ height: 150px;
+ text-align: justify;
+ font-size: 16px;
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+
+.list-box .date {
+ display: block;
+ font-size: 12px;
+}
+
+.list-media {
+ list-style: none;
+ padding: 0;
+}
+
+.list-media li {
+ margin-bottom: 10px;
+}
+
+.list-media.list-underline li {
+ padding-bottom: 15px;
+ border-bottom: solid 1px #ddd;
+ line-height: inherit;
+}
+
+
+/*分页*/
+
+.pagination {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: inline-block;
+ vertical-align: bottom;
+}
+
+.pagination li {
+ display: inline-block;
+ border: solid 1px #ddd;
+ border-radius: 4px;
+}
+
+.pagination a {
+ color: #333;
+ padding: 8px 12px;
+ line-height: 18px;
+ display: block;
+ transition: all 1s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+}
+
+.pagination .disabled a:link,
+.pagination .disabled a:visited,
+.pagination .disabled a:hover {
+ cursor: not-allowed;
+ pointer-events: none;
+ color: #ddd;
+}
+
+.pagination .active {
+ pointer-events: none;
+}
+
+.pagination .active,
+.pagination a:hover {
+ background: #f5f5f5;
+ border-radius: 4px;
+ transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+}
+
+.pagination-group {
+ border-right: solid 1px #ddd;
+ border-radius: 4px;
+}
+
+.pagination-group li {
+ float: left;
+ border-right: none;
+ border-radius: 0;
+}
+
+.pagination-group li:not(:first-child):not(:last-child) {
+ border-radius: 0;
+}
+
+.pagination-group li:first-child {
+ border-radius: 4px 0 0 4px;
+}
+
+.pagination-group li:last-child {
+ border-radius: 0 4px 4px 0;
+}
+
+.pagination-group .active,
+.pagination-group a:hover {
+ background: #f5f5f5;
+ border-radius: 0;
+}
+
+.pagination-big a {
+ padding: 10px 16px;
+ font-size: 16px;
+}
+
+.pagination-small a {
+ padding: 5px 10px;
+ font-size: 12px;
+}
+
+.pagination.border-main .active a,
+.pagination.border-sub .active a,
+.pagination.border-dot .active a,
+.pagination.border-black .active a,
+.pagination.border-gray .active a,
+.pagination.border-red .active a,
+.pagination.border-yellow .active a,
+.pagination.border-blue .active a,
+.pagination.border-green .active a {
+ color: #fff;
+}
+
+.pager {
+ list-style: none;
+ padding: 0;
+ text-align: center;
+ clear: both;
+}
+
+.pager li {
+ display: inline-block;
+}
+
+.pager li a {
+ color: #333;
+ border: solid 1px #ddd;
+ border-radius: 15px;
+ padding: 5px 15px;
+ transition: all 1s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+}
+
+.pager li a:hover {
+ background-color: #f5f5f5;
+ transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1) 0s;
+}
+
+.pager-prev,
+.pager .pager-prev,
+.pager-next,
+.pager .pager-next {
+ font-size: 36px;
+ padding: 0;
+ color: #ddd;
+ border: solid 1px #ddd;
+ background-color: rgba(255, 255, 255, .2);
+ width: 50px;
+ height: 50px;
+ line-height: 45px;
+ display: inline-block;
+ border-radius: 50%;
+ text-align: center;
+ cursor: pointer;
+}
+
+.pager-prev:hover,
+.pager-next:hover {
+ background-color: rgba(0, 0, 0, .2);
+}
+
+.pager-group li {
+ float: left;
+ display: inline-block;
+}
+
+.pager-group li:not(:first-child):not(:last-child) {
+ border-radius: 0;
+}
+
+.pager-group li a:first-child {
+ border-radius: 4px 0 0 4px;
+}
+
+.pager-group li a:last-child {
+ border-radius: 0 4px 4px 0;
+}
+
+.pointer {
+ padding: 0px;
+}
+
+.pointer li {
+ border: solid 1px #ddd;
+ width: 10px;
+ height: 10px;
+ margin: 1px;
+ display: inline-block;
+ border-radius: 10px;
+ cursor: pointer;
+}
+
+.pointer .active {
+ border: none;
+ background: #ddd;
+ width: 12px;
+ height: 12px;
+ margin: 0;
+}
+
+
+/*内容*/
+
+.keypoint {
+ padding: 50px;
+}
+
+.keypoint h1 {
+ font-size: 48px;
+ margin-bottom: 15px;
+}
+
+.keypoint p {
+ font-size: 18px;
+}
+
+.detail h1 {
+ text-align: center;
+}
+
+.detail p {
+ text-indent: 2em;
+}
+
+
+/*-----------------------CSS--------------------------*/
+
+
+/*文本*/
+
+
+/*标题*/
+
+h1,
+.h1 {
+ font-size: 24px;
+}
+
+h2,
+.h2 {
+ font-size: 20px;
+}
+
+h3,
+.h3 {
+ font-size: 18px;
+}
+
+h4,
+.h4 {
+ font-size: 16px;
+}
+
+h5,
+.h5 {
+ font-size: 14px;
+}
+
+h6,
+.h6 {
+ font-size: 12px;
+}
+
+h1 small,
+.h1 small,
+h2 small,
+.h2 small,
+h3 small,
+.h3 small {
+ font-size: 60%;
+ filter: alpha(opacity=60);
+ opacity: .6;
+}
+
+h4 small,
+.h4 small,
+h5 small,
+.h5 small,
+h6 small,
+.h6 small {
+ font-size: 12px;
+ filter: alpha(opacity=60);
+ opacity: .6;
+}
+
+
+/*段落*/
+
+p,
+.p {
+ margin-bottom: 15px;
+ line-height: 24px;
+}
+
+.text-indent,
+.text-indent p,
+.text-indent div {
+ text-indent: 2em;
+}
+
+
+/*对齐*/
+
+.text-left {
+ text-align: left;
+}
+
+.text-center {
+ text-align: center;
+}
+
+.text-right {
+ text-align: right;
+}
+
+.text-justify {
+ text-align: justify;
+}
+
+
+/*字号*/
+
+.text-large {
+ font-size: 24px;
+}
+
+.text-big {
+ font-size: 16px;
+}
+
+.text-default {
+ font-size: 14px;
+}
+
+.text-small {
+ font-size: 12px;
+}
+
+.text-little {
+ font-size: 10px;
+}
+
+
+/*行距*/
+
+.height-large {
+ line-height: 40px;
+}
+
+.height-big {
+ line-height: 30px;
+}
+
+.height {
+ line-height: 24px;
+}
+
+.height-small {
+ line-height: 20px;
+}
+
+.height-little {
+ line-height: 16px;
+}
+
+
+/*边框,全,上,下,左,右*/
+
+.border {
+ border: solid 1px #ddd;
+}
+
+.border-top {
+ border-top: solid 1px #ddd;
+}
+
+.border-right {
+ border-right: solid 1px #ddd;
+}
+
+.border-bottom {
+ border-bottom: solid 1px #ddd;
+}
+
+.border-left {
+ border-left: solid 1px #ddd;
+}
+
+.border-left-right {
+ border-left: solid 1px #ddd;
+ border-right: solid 1px #ddd;
+}
+
+.border-top-bottom {
+ border-top: solid 1px #ddd;
+ border-bottom: solid 1px #ddd;
+}
+
+.border-large {
+ border-width: 10px;
+}
+
+.border-big {
+ border-width: 5px;
+}
+
+.border-middle {
+ border-width: 3px;
+}
+
+.border-small {
+ border-width: 2px;
+}
+
+
+/*水平线*/
+
+hr {
+ background: #ddd;
+ color: #ddd;
+ clear: both;
+ float: none;
+ width: 100%;
+ height: 1px;
+ margin: 10px 0;
+ border: none;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+
+hr.space {
+ background: #fff;
+ color: #fff;
+ visibility: hidden;
+}
+
+
+/*图片*/
+
+
+/*图片样式*/
+
+.img-border {
+ border: solid 1px #ddd;
+ padding: 4px;
+}
+
+.img-responsive {
+ display: block;
+ max-width: 100%;
+ height: auto;
+}
+
+
+/*无序有序列表*/
+
+ul {
+ padding-left: 20px;
+}
+
+ol {
+ padding-left: 24px;
+}
+
+.list-cn {
+ list-style-type: cjk-ideographic;
+}
+
+.list-alpha {
+ list-style-type: upper-alpha;
+}
+
+.list-unstyle {
+ list-style: none;
+ padding-left: 0;
+}
+
+.list-unstyle ul {
+ list-style: disc;
+}
+
+.list-inline li {
+ display: inline-block;
+ padding: 0 10px;
+ width: auto;
+}
+
+
+/*描述*/
+
+dt {
+ font-weight: bold;
+}
+
+dd {
+ padding: 8px 0 15px 0;
+}
+
+@media (min-width: 760px) {
+ .dl-inline dt {
+ width: 15%;
+ display: inline-block;
+ float: left;
+ text-align: right;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ }
+ .dl-inline dd {
+ width: 85%;
+ display: inline-block;
+ float: left;
+ padding: 0 0 15px 15px;
+ }
+}
+
+
+/*表格*/
+
+.table {
+ width: 100%;
+ max-width: 100%;
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+.table th {
+ border-bottom: 2px solid #ddd;
+ vertical-align: bottom;
+ padding: 8px;
+ text-align: left;
+}
+
+.table td {
+ border-top: 1px solid #ddd;
+ padding: 8px;
+ vertical-align: top;
+}
+
+.table-striped > tbody > tr:nth-child(odd) > td,
+.table-striped > tbody > tr:nth-child(odd) > th {
+ background-color: #f9f9f9;
+}
+
+
+/*条纹-IE9以下无效果*/
+
+.table-bordered th,
+.table-bordered td {
+ border: solid 1px #ddd;
+}
+
+.table-bordered th {
+ border-bottom: 2px solid #ddd;
+}
+
+.table-hover > tbody > tr:hover > td,
+.table-hover > tbody > tr:hover > th {
+ background-color: #f5f5f5;
+}
+
+
+/*不支持IE6*/
+
+.table-condensed th,
+.table-condensed td {
+ padding: 5px;
+}
+
+@media (max-width: 800px) {
+ .table-responsive {
+ width: 100%;
+ overflow-x: scroll;
+ overflow-y: hidden;
+ -webkit-overflow-scrolling: touch;
+ -ms-overflow-style: -ms-autohiding-scrollbar;
+ }
+ .table-responsive .table tr th,
+ .table-responsive .table tr td {
+ white-space: nowrap;
+ }
+}
+
+
+/*大火兔2015-11-19 新增表格响应式纵方式排列*/
+
+
+/*表格响应式纵方式*/
+
+@media only screen and (max-width: 800px) {
+ .table-responsive-y table,
+ .table-responsive-y thead,
+ .table-responsive-y tbody,
+ .table-responsive-y th,
+ .table-responsive-y td,
+ .table-responsive-y tr {
+ display: block;
+ }
+ .table-responsive-y thead tr {
+ position: absolute;
+ top: -9999px;
+ left: -9999px;
+ }
+ .table-responsive-y tr {
+ border: 1px solid #ccc;
+ }
+ .table-responsive-y td {
+ border: none;
+ border-bottom: 1px solid #eee;
+ position: relative;
+ padding-left: 30%;
+ white-space: normal;
+ text-align: left;
+ }
+ .table-responsive-y td:before {
+ position: absolute;
+ top: 6px;
+ left: 6px;
+ width: 45%;
+ padding-right: 10px;
+ white-space: nowrap;
+ text-align: left;
+ font-weight: bold;
+ }
+ .table-responsive-y td:before {
+ content: attr(data-title);
+ }
+}
+
+
+/*引用*/
+
+blockquote {
+ border: solid 1px #ddd;
+ border-left-width: 6px;
+ padding: 20px;
+ border-radius: 4px;
+}
+
+blockquote strong {
+ display: block;
+ font-size: 16px;
+ margin-bottom: 10px;
+}
+
+blockquote p:last-child {
+ margin: 0;
+}
+
+.quote-floatright {
+ border-left-width: 1px;
+ border-right-width: 6px;
+ text-align: right;
+}
+
+
+/*快速设置浮动*/
+
+.float-left {
+ float: left !important;
+}
+
+.float-right {
+ float: right !important;
+}
+
+
+/*清除浮动*/
+
+.clearfix:after,
+.layout:after,
+.container:after,
+.container-layout:after,
+.line:after,
+.line-small:after,
+.line-middle:after,
+.line-big:after,
+.nav-main:after,
+.nav-sub:after,
+.navbar:after {
+ content: " ";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+ overflow: hidden;
+}
+
+.clearfix,
+.layout,
+.container,
+.container-layout,
+.line,
+.line-small,
+.line-middle,
+.line-big,
+.nav-main,
+.nav-sub,
+.navbar {
+ display: block;
+}
+
+.clear {
+ clear: both;
+}
+
+
+/*print*/
+
+.print-show {
+ display: none !important;
+}
+
+@media print {
+ .print-show {
+ display: block !important;
+ }
+ table.print-show {
+ display: table;
+ }
+ tr.print-show {
+ display: table-row !important;
+ }
+ th.print-show,
+ td.print-show {
+ display: table-cell !important;
+ }
+ .print-hidden {
+ display: none !important;
+ }
+}
+
+
+/*显示隐藏*/
+
+.show {
+ display: block !important;
+}
+
+.hidden {
+ display: none !important;
+ visibility: hidden !important;
+}
+
+
+/*内边距,全,上,下,左,右*/
+
+.padding-large {
+ padding: 30px;
+}
+
+.padding-large-top {
+ padding-top: 30px;
+}
+
+.padding-large-right {
+ padding-right: 30px;
+}
+
+.padding-large-bottom {
+ padding-bottom: 30px;
+}
+
+.padding-large-left {
+ padding-left: 30px;
+}
+
+.padding-big {
+ padding: 20px;
+}
+
+.padding-big-top {
+ padding-top: 20px;
+}
+
+.padding-big-right {
+ padding-right: 20px;
+}
+
+.padding-big-bottom {
+ padding-bottom: 20px;
+}
+
+.padding-big-left {
+ padding-left: 20px;
+}
+
+.padding {
+ padding: 10px;
+}
+
+.padding-top {
+ padding-top: 10px;
+}
+
+.padding-right {
+ padding-right: 10px;
+}
+
+.padding-bottom {
+ padding-bottom: 10px;
+}
+
+.padding-left {
+ padding-left: 10px;
+}
+
+.padding-small {
+ padding: 5px;
+}
+
+.padding-small-top {
+ padding-top: 5px;
+}
+
+.padding-small-right {
+ padding-right: 5px;
+}
+
+.padding-small-bottom {
+ padding-bottom: 5px;
+}
+
+.padding-small-left {
+ padding-left: 5px;
+}
+
+.padding-little {
+ padding: 2px;
+}
+
+.padding-little-top {
+ padding-top: 2px;
+}
+
+.padding-little-right {
+ padding-right: 2px;
+}
+
+.padding-little-bottom {
+ padding-bottom: 2px;
+}
+
+.padding-little-left {
+ padding-left: 2px;
+}
+
+
+/*外边距,全,上,下,左,右*/
+
+.margin-large {
+ margin: 30px;
+}
+
+.margin-large-top {
+ margin-top: 30px;
+}
+
+.margin-large-right {
+ margin-right: 30px;
+}
+
+.margin-large-bottom {
+ margin-bottom: 30px;
+}
+
+.margin-large-left {
+ margin-left: 30px;
+}
+
+.margin-big {
+ margin: 20px;
+}
+
+.margin-big-top {
+ margin-top: 20px;
+}
+
+.margin-big-right {
+ margin-right: 20px;
+}
+
+.margin-big-bottom {
+ margin-bottom: 20px;
+}
+
+.margin-big-left {
+ margin-left: 20px;
+}
+
+.margin {
+ margin: 10px !important;
+ clear: both;
+}
+
+.margin-top {
+ margin-top: 10px;
+}
+
+.margin-right {
+ margin-right: 10px;
+}
+
+.margin-bottom {
+ margin-bottom: 10px;
+}
+
+.margin-left {
+ margin-left: 10px;
+}
+
+.margin-small {
+ margin: 5px;
+}
+
+.margin-small-top {
+ margin-top: 5px;
+}
+
+.margin-small-right {
+ margin-right: 5px;
+}
+
+.margin-small-bottom {
+ margin-bottom: 5px;
+}
+
+.margin-small-left {
+ margin-left: 5px;
+}
+
+.margin-little {
+ margin: 2px;
+}
+
+.margin-little-top {
+ margin-top: 2px;
+}
+
+.margin-little-right {
+ margin-right: 2px;
+}
+
+.margin-little-bottom {
+ margin-bottom: 2px;
+}
+
+.margin-little-left {
+ margin-left: 2px;
+}
+
+
+/*圆角*/
+
+.radius-none {
+ border-radius: 0;
+}
+
+.radius-small {
+ border-radius: 2px;
+}
+
+.radius {
+ border-radius: 4px;
+}
+
+.radius-big {
+ border-radius: 6px;
+}
+
+.radius-rounded {
+ border-radius: 2em;
+ padding-left: 1em;
+ padding-right: 1em;
+}
+
+.radius-circle {
+ border-radius: 50%;
+}
+
+
+/*阴影 2015-12-15 新增*/
+
+.box-shadow-none {
+ box-shadow: 0 0px 0px rgba(0, 0, 0, 0.5);
+}
+
+.box-shadow-small {
+ box-shadow: 0 3px 5px rgba(0, 0, 0, 0.5);
+}
+
+.box-shadow {
+ box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);
+}
+
+.box-shadow-big {
+ box-shadow: 0 6px 9px rgba(0, 0, 0, 0.5);
+}
+
+
+/*动画*/
+
+.bounce,
+.bounce-hover,
+.flash,
+.flash-hover,
+.shake,
+.shake-hover,
+.swing,
+.swing-hover,
+.wobble,
+.wobble-hover,
+.ring,
+.ring-hover {
+ -webkit-animation: 1s ease;
+ -moz-animation: 1s ease;
+ -ms-animation: 1s ease;
+ animation: 1s ease;
+}
+
+.fadein,
+.fadein-top,
+.fadein-right,
+.fadein-bottom,
+.fadein-left,
+.bouncein,
+.rotatein {
+ -webkit-animation: 1s ease-out backwards;
+ -moz-animation: 1s ease-out backwards;
+ -ms-animation: 1s ease-out backwards;
+ animation: 1s ease-out backwards;
+}
+
+.fadeout,
+.fadeout-top,
+.fadeout-right,
+.fadeout-bottom,
+.fadeout-left,
+.bounceout,
+.rotateout {
+ -webkit-animation: 1s ease-in forwards;
+ -moz-animation: 1s ease-in forwards;
+ -ms-animation: 1s ease-in forwards;
+ animation: 1s ease-in forwards;
+}
+
+.rotate,
+.rotate-hover {
+ -webkit-animation: 2s infinite linear;
+ -moz-animation: 2s infinite linear;
+ -ms-animation: 2s infinite linear;
+ animation: 2s infinite linear;
+}
+
+
+/*渐变-淡入*/
+
+.fadein {
+ -webkit-animation-name: a-fadein;
+ -moz-animation-name: a-fadein;
+ -ms-animation-name: a-fadein;
+ animation-name: a-fadein;
+}
+
+@-webkit-keyframes a-fadein {
+ 0% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 1;
+ }
+}
+
+@-moz-keyframes a-fadein {
+ 0% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 1;
+ }
+}
+
+@-ms-keyframes a-fadein {
+ 0% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 1;
+ }
+}
+
+@keyframes a-fadein {
+ 0% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 1;
+ }
+}
+
+
+/*淡入-从上*/
+
+.fadein-top {
+ -webkit-animation-name: fadeinT;
+ -moz-animation-name: fadeinT;
+ -ms-animation-name: fadeinT;
+ animation-name: fadeinT;
+}
+
+@-webkit-keyframes fadeinT {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translateY(-50px);
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: translateY(0);
+ }
+}
+
+@-moz-keyframes fadeinT {
+ 0% {
+ opacity: 0;
+ -moz-transform: translateY(-50px);
+ }
+ 100% {
+ opacity: 1;
+ -moz-transform: translateY(0);
+ }
+}
+
+@-ms-keyframes fadeinT {
+ 0% {
+ opacity: 0;
+ -ms-transform: translateY(-50px);
+ }
+ 100% {
+ opacity: 1;
+ -ms-transform: translateY(0);
+ }
+}
+
+@keyframes fadeinT {
+ 0% {
+ opacity: 0;
+ transform: translateY(-50px);
+ }
+ 100% {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+
+/*淡入-从右*/
+
+.fadein-right {
+ -webkit-animation-name: fadeinR;
+ -moz-animation-name: fadeinR;
+ -ms-animation-name: fadeinR;
+ animation-name: fadeinR;
+}
+
+@-webkit-keyframes fadeinR {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translateX(50px);
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: translateX(0);
+ }
+}
+
+@-moz-keyframes fadeinR {
+ 0% {
+ opacity: 0;
+ -moz-transform: translateX(50px);
+ }
+ 100% {
+ opacity: 1;
+ -moz-transform: translateX(0);
+ }
+}
+
+@-ms-keyframes fadeinR {
+ 0% {
+ opacity: 0;
+ -ms-transform: translateX(50px);
+ }
+ 100% {
+ opacity: 1;
+ -ms-transform: translateX(0);
+ }
+}
+
+@keyframes fadeinR {
+ 0% {
+ opacity: 0;
+ transform: translateX(50px);
+ }
+ 100% {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+
+/*淡入-从下*/
+
+.fadein-bottom {
+ -webkit-animation-name: fadeinB;
+ -moz-animation-name: fadeinB;
+ -ms-animation-name: fadeinB;
+ animation-name: fadeinB;
+}
+
+@-webkit-keyframes fadeinB {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translateY(50px);
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: translateY(0);
+ }
+}
+
+@-moz-keyframes fadeinB {
+ 0% {
+ opacity: 0;
+ -moz-transform: translateY(50px);
+ }
+ 100% {
+ opacity: 1;
+ -moz-transform: translateY(0);
+ }
+}
+
+@-ms-keyframes fadeinB {
+ 0% {
+ opacity: 0;
+ -ms-transform: translateY(50px);
+ }
+ 100% {
+ opacity: 1;
+ -ms-transform: translateY(0);
+ }
+}
+
+@keyframes fadeinB {
+ 0% {
+ opacity: 0;
+ transform: translateY(50px);
+ }
+ 100% {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+
+/*淡入-从左*/
+
+.fadein-left {
+ -webkit-animation-name: fadeinL;
+ -moz-animation-name: fadeinL;
+ -ms-animation-name: fadeinL;
+ animation-name: fadeinL;
+}
+
+@-webkit-keyframes fadeinL {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translateX(-50px);
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: translateX(0);
+ }
+}
+
+@-moz-keyframes fadeinL {
+ 0% {
+ opacity: 0;
+ -moz-transform: translateX(-50px);
+ }
+ 100% {
+ opacity: 1;
+ -moz-transform: translateX(0);
+ }
+}
+
+@-ms-keyframes fadeinL {
+ 0% {
+ opacity: 0;
+ -ms-transform: translateX(-50px);
+ }
+ 100% {
+ opacity: 1;
+ -ms-transform: translateX(0);
+ }
+}
+
+@keyframes fadeinL {
+ 0% {
+ opacity: 0;
+ transform: translateX(-50px);
+ }
+ 100% {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+
+/*渐变-淡出*/
+
+.fadeout {
+ -webkit-animation-name: a-fadeout;
+ -moz-animation-name: a-fadeout;
+ -ms-animation-name: a-fadeout;
+ animation-name: a-fadeout;
+}
+
+@-webkit-keyframes a-fadeout {
+ 0% {
+ opacity: 1;
+ }
+ 100% {
+ opacity: 0;
+ }
+}
+
+@-moz-keyframes a-fadeout {
+ 0% {
+ opacity: 1;
+ }
+ 100% {
+ opacity: 0;
+ }
+}
+
+@-ms-keyframes a-fadeout {
+ 0% {
+ opacity: 1;
+ }
+ 100% {
+ opacity: 0;
+ }
+}
+
+@keyframes a-fadeout {
+ 0% {
+ opacity: 1;
+ }
+ 100% {
+ opacity: 0;
+ }
+}
+
+
+/*淡出-向上*/
+
+.fadeout-top {
+ -webkit-animation-name: fadeoutT;
+ -moz-animation-name: fadeoutT;
+ -ms-animation-name: fadeoutT;
+ animation-name: fadeoutT;
+}
+
+@-webkit-keyframes fadeoutT {
+ 0% {
+ opacity: 1;
+ -webkit-transform: translateY(0);
+ }
+ 100% {
+ opacity: 0;
+ -webkit-transform: translateY(-100px);
+ }
+}
+
+@-moz-keyframes fadeoutT {
+ 0% {
+ opacity: 1;
+ -moz-transform: translateY(0);
+ }
+ 100% {
+ opacity: 0;
+ -moz-transform: translateY(-100px);
+ }
+}
+
+@-ms-keyframes fadeoutT {
+ 0% {
+ opacity: 1;
+ -ms-transform: translateY(0);
+ }
+ 100% {
+ opacity: 0;
+ -ms-transform: translateY(-100px);
+ }
+}
+
+@keyframes fadeoutT {
+ 0% {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ 100% {
+ opacity: 0;
+ transform: translateY(-100px);
+ }
+}
+
+
+/*淡出-向右*/
+
+.fadeout-right {
+ -webkit-animation-name: fadeoutR;
+ -moz-animation-name: fadeoutR;
+ -ms-animation-name: fadeoutR;
+ animation-name: fadeoutR;
+}
+
+@-webkit-keyframes fadeoutR {
+ 0% {
+ opacity: 1;
+ -webkit-transform: translateX(0);
+ }
+ 100% {
+ opacity: 0;
+ -webkit-transform: translateX(100px);
+ }
+}
+
+@-moz-keyframes fadeoutR {
+ 0% {
+ opacity: 1;
+ -moz-transform: translateX(0);
+ }
+ 100% {
+ opacity: 0;
+ -moz-transform: translateX(100px);
+ }
+}
+
+@-ms-keyframes fadeoutR {
+ 0% {
+ opacity: 1;
+ -ms-transform: translateX(0);
+ }
+ 100% {
+ opacity: 0;
+ -ms-transform: translateX(100px);
+ }
+}
+
+@keyframes fadeoutR {
+ 0% {
+ opacity: 1;
+ transform: translateX(0);
+ }
+ 100% {
+ opacity: 0;
+ transform: translateX(100px);
+ }
+}
+
+
+/*淡出-向下*/
+
+.fadeout-bottom {
+ -webkit-animation-name: fadeoutB;
+ -moz-animation-name: fadeoutB;
+ -ms-animation-name: fadeoutB;
+ animation-name: fadeoutB;
+}
+
+@-webkit-keyframes fadeoutB {
+ 0% {
+ opacity: 1;
+ -webkit-transform: translateY(0);
+ }
+ 100% {
+ opacity: 0;
+ -webkit-transform: translateY(100px);
+ }
+}
+
+@-moz-keyframes fadeoutB {
+ 0% {
+ opacity: 1;
+ -moz-transform: translateY(0);
+ }
+ 100% {
+ opacity: 0;
+ -moz-transform: translateY(100px);
+ }
+}
+
+@-ms-keyframes fadeoutB {
+ 0% {
+ opacity: 1;
+ -ms-transform: translateY(0);
+ }
+ 100% {
+ opacity: 0;
+ -ms-transform: translateY(100px);
+ }
+}
+
+@keyframes fadeoutB {
+ 0% {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ 100% {
+ opacity: 0;
+ transform: translateY(100px);
+ }
+}
+
+
+/*淡出-向左*/
+
+.fadeout-left {
+ -webkit-animation-name: fadeoutL;
+ -moz-animation-name: fadeoutL;
+ -ms-animation-name: fadeoutL;
+ animation-name: fadeoutL;
+}
+
+@-webkit-keyframes fadeoutL {
+ 0% {
+ opacity: 1;
+ -webkit-transform: translateX(0);
+ }
+ 100% {
+ opacity: 0;
+ -webkit-transform: translateX(-100px);
+ }
+}
+
+@-moz-keyframes fadeoutL {
+ 0% {
+ opacity: 1;
+ -moz-transform: translateX(0);
+ }
+ 100% {
+ opacity: 0;
+ -moz-transform: translateX(-100px);
+ }
+}
+
+@-ms-keyframes fadeoutL {
+ 0% {
+ opacity: 1;
+ -ms-transform: translateX(0);
+ }
+ 100% {
+ opacity: 0;
+ -ms-transform: translateX(-100px);
+ }
+}
+
+@keyframes fadeoutL {
+ 0% {
+ opacity: 1;
+ transform: translateX(0);
+ }
+ 100% {
+ opacity: 0;
+ transform: translateX(-100px);
+ }
+}
+
+
+/*弹跳*/
+
+.bounce,
+.bounce-hover:hover {
+ -webkit-animation-name: a-bounce;
+ -moz-animation-name: a-bounce;
+ -ms-animation-name: a-bounce;
+ animation-name: a-bounce;
+}
+
+@-webkit-keyframes a-bounce {
+ 0%,
+ 20%,
+ 50%,
+ 80%,
+ 100% {
+ -webkit-transform: translateY(0);
+ }
+ 40% {
+ -webkit-transform: translateY(-30px);
+ }
+ 60% {
+ -webkit-transform: translateY(-15px);
+ }
+}
+
+@-moz-keyframes a-bounce {
+ 0%,
+ 20%,
+ 50%,
+ 80%,
+ 100% {
+ -moz-transform: translateY(0);
+ }
+ 40% {
+ -moz-transform: translateY(-30px);
+ }
+ 60% {
+ -moz-transform: translateY(-15px);
+ }
+}
+
+@-ms-keyframes a-bounce {
+ 0%,
+ 20%,
+ 50%,
+ 80%,
+ 100% {
+ -ms-transform: translateY(0);
+ }
+ 40% {
+ -ms-transform: translateY(-30px);
+ }
+ 60% {
+ -ms-transform: translateY(-15px);
+ }
+}
+
+@keyframes a-bounce {
+ 0%,
+ 20%,
+ 50%,
+ 80%,
+ 100% {
+ transform: translateY(0);
+ }
+ 40% {
+ transform: translateY(-30px);
+ }
+ 60% {
+ transform: translateY(-15px);
+ }
+}
+
+
+/*弹入*/
+
+.bouncein {
+ -webkit-animation-name: a-bouncein;
+ -moz-animation-name: a-bouncein;
+ -ms-animation-name: a-bouncein;
+ animation-name: a-bouncein;
+}
+
+@-webkit-keyframes a-bouncein {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale(0.3);
+ }
+ 50% {
+ opacity: 1;
+ -webkit-transform: scale(1.05);
+ }
+ 70% {
+ -webkit-transform: scale(0.9);
+ }
+ 100% {
+ -webkit-transform: scale(1);
+ }
+}
+
+@-moz-keyframes a-bouncein {
+ 0% {
+ opacity: 0;
+ -moz-transform: scale(0.3);
+ }
+ 50% {
+ opacity: 1;
+ -moz-transform: scale(1.05);
+ }
+ 70% {
+ -moz-transform: scale(0.9);
+ }
+ 100% {
+ -moz-transform: scale(1);
+ }
+}
+
+@-ms-keyframes a-bouncein {
+ 0% {
+ opacity: 0;
+ -ms-transform: scale(0.3);
+ }
+ 50% {
+ opacity: 1;
+ -ms-transform: scale(1.05);
+ }
+ 70% {
+ -ms-transform: scale(0.9);
+ }
+ 100% {
+ -ms-transform: scale(1);
+ }
+}
+
+@keyframes a-bouncein {
+ 0% {
+ opacity: 0;
+ transform: scale(0.3);
+ }
+ 50% {
+ opacity: 1;
+ transform: scale(1.05);
+ }
+ 70% {
+ transform: scale(0.9);
+ }
+ 100% {
+ transform: scale(1);
+ }
+}
+
+
+/*弹出*/
+
+.bounceout {
+ -webkit-animation-name: a-bounceout;
+ -moz-animation-name: a-bounceout;
+ -ms-animation-name: a-bounceout;
+ animation-name: a-bounceout;
+}
+
+@-webkit-keyframes a-bounceout {
+ 0% {
+ -webkit-transform: scale(1);
+ }
+ 25% {
+ -webkit-transform: scale(0.95);
+ }
+ 50% {
+ opacity: 1;
+ -webkit-transform: scale(1.1);
+ }
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale(0.3);
+ }
+}
+
+@-moz-keyframes a-bounceout {
+ 0% {
+ -moz-transform: scale(1);
+ }
+ 25% {
+ -moz-transform: scale(0.95);
+ }
+ 50% {
+ opacity: 1;
+ -moz-transform: scale(1.1);
+ }
+ 100% {
+ opacity: 0;
+ -moz-transform: scale(0.3);
+ }
+}
+
+@-ms-keyframes a-bounceout {
+ 0% {
+ -ms-transform: scale(1);
+ }
+ 25% {
+ -ms-transform: scale(0.95);
+ }
+ 50% {
+ opacity: 1;
+ -ms-transform: scale(1.1);
+ }
+ 100% {
+ opacity: 0;
+ -ms-transform: scale(0.3);
+ }
+}
+
+@keyframes a-bounceout {
+ 0% {
+ transform: scale(1);
+ }
+ 25% {
+ transform: scale(0.95);
+ }
+ 50% {
+ opacity: 1;
+ transform: scale(1.1);
+ }
+ 100% {
+ opacity: 0;
+ transform: scale(0.3);
+ }
+}
+
+
+/*转入*/
+
+.rotatein {
+ -webkit-animation-name: a-rotatein;
+ -moz-animation-name: a-rotatein;
+ -ms-animation-name: a-rotatein;
+ animation-name: a-rotatein;
+}
+
+@-webkit-keyframes a-rotatein {
+ 0% {
+ opacity: 0;
+ -webkit-transform: rotate(-200deg);
+ }
+ 100% {
+ opacity: 1;
+ -webkit-transform: rotate(0);
+ }
+}
+
+@-moz-keyframes a-rotatein {
+ 0% {
+ opacity: 0;
+ -moz-transform: rotate(-200deg);
+ }
+ 100% {
+ opacity: 1;
+ -moz-transform: rotate(0);
+ }
+}
+
+@-ms-keyframes a-rotatein {
+ 0% {
+ opacity: 0;
+ -ms-transform: rotate(-200deg);
+ }
+ 100% {
+ opacity: 1;
+ -ms-transform: rotate(0);
+ }
+}
+
+@keyframes a-rotatein {
+ 0% {
+ opacity: 0;
+ transform: rotate(-200deg);
+ }
+ 100% {
+ opacity: 1;
+ transform: rotate(0);
+ }
+}
+
+
+/*转出*/
+
+.rotateout {
+ -webkit-animation-name: a-rotateout;
+ -moz-animation-name: a-rotateout;
+ -ms-animation-name: a-rotateout;
+ animation-name: a-rotateout;
+}
+
+@-webkit-keyframes a-rotateout {
+ 0% {
+ -webkit-transform-origin: center center;
+ -webkit-transform: rotate(0);
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform-origin: center center;
+ -webkit-transform: rotate(200deg);
+ opacity: 0;
+ }
+}
+
+@-moz-keyframes a-rotateout {
+ 0% {
+ -moz-transform-origin: center center;
+ -moz-transform: rotate(0);
+ opacity: 1;
+ }
+ 100% {
+ -moz-transform-origin: center center;
+ -moz-transform: rotate(200deg);
+ opacity: 0;
+ }
+}
+
+@-ms-keyframes a-rotateout {
+ 0% {
+ -ms-transform-origin: center center;
+ -ms-transform: rotate(0);
+ opacity: 1;
+ }
+ 100% {
+ -ms-transform-origin: center center;
+ -ms-transform: rotate(200deg);
+ opacity: 0;
+ }
+}
+
+@keyframes a-rotateout {
+ 0% {
+ transform-origin: center center;
+ transform: rotate(0);
+ opacity: 1;
+ }
+ 100% {
+ transform-origin: center center;
+ transform: rotate(200deg);
+ opacity: 0;
+ }
+}
+
+
+/*闪烁*/
+
+.flash,
+.flash-hover:hover {
+ -webkit-animation-name: a-flash;
+ -moz-animation-name: a-flash;
+ -ms-animation-name: a-flash;
+ animation-name: a-flash;
+}
+
+@-webkit-keyframes a-flash {
+ 0%,
+ 50%,
+ 100% {
+ opacity: 1;
+ }
+ 25%,
+ 75% {
+ opacity: 0;
+ }
+}
+
+@-moz-keyframes a-flash {
+ 0%,
+ 50%,
+ 100% {
+ opacity: 1;
+ }
+ 25%,
+ 75% {
+ opacity: 0;
+ }
+}
+
+@-ms-keyframes a-flash {
+ 0%,
+ 50%,
+ 100% {
+ opacity: 1;
+ }
+ 25%,
+ 75% {
+ opacity: 0;
+ }
+}
+
+@keyframes a-flash {
+ 0%,
+ 50%,
+ 100% {
+ opacity: 1;
+ }
+ 25%,
+ 75% {
+ opacity: 0;
+ }
+}
+
+
+/*震颤*/
+
+.shake,
+.shake-hover:hover {
+ -webkit-animation-name: a-shake;
+ -moz-animation-name: a-shake;
+ -ms-animation-name: a-shake;
+ animation-name: a-shake;
+}
+
+@-webkit-keyframes a-shake {
+ 0%,
+ 100% {
+ -webkit-transform: translateX(0);
+ }
+ 10%,
+ 30%,
+ 50%,
+ 70%,
+ 90% {
+ -webkit-transform: translateX(-10px);
+ }
+ 20%,
+ 40%,
+ 60%,
+ 80% {
+ -webkit-transform: translateX(10px);
+ }
+}
+
+@-moz-keyframes a-shake {
+ 0%,
+ 100% {
+ -moz-transform: translateX(0);
+ }
+ 10%,
+ 30%,
+ 50%,
+ 70%,
+ 90% {
+ -moz-transform: translateX(-10px);
+ }
+ 20%,
+ 40%,
+ 60%,
+ 80% {
+ -moz-transform: translateX(10px);
+ }
+}
+
+@-ms-keyframes a-shake {
+ 0%,
+ 100% {
+ -ms-transform: translateX(0);
+ }
+ 10%,
+ 30%,
+ 50%,
+ 70%,
+ 90% {
+ -ms-transform: translateX(-10px);
+ }
+ 20%,
+ 40%,
+ 60%,
+ 80% {
+ -ms-transform: translateX(10px);
+ }
+}
+
+@keyframes a-shake {
+ 0%,
+ 100% {
+ transform: translateX(0);
+ }
+ 10%,
+ 30%,
+ 50%,
+ 70%,
+ 90% {
+ transform: translateX(-10px);
+ }
+ 20%,
+ 40%,
+ 60%,
+ 80% {
+ transform: translateX(10px);
+ }
+}
+
+
+/*摇摆*/
+
+.swing,
+.swing-hover:hover {
+ -webkit-animation-name: a-swing;
+ -moz-animation-name: a-swing;
+ -ms-animation-name: a-swing;
+ animation-name: a-swing;
+}
+
+@-webkit-keyframes a-swing {
+ 20% {
+ -webkit-transform: rotate(15deg);
+ }
+ 40% {
+ -webkit-transform: rotate(-10deg);
+ }
+ 60% {
+ -webkit-transform: rotate(5deg);
+ }
+ 80% {
+ -webkit-transform: rotate(-5deg);
+ }
+ 100% {
+ -webkit-transform: rotate(0);
+ }
+}
+
+@-moz-keyframes a-swing {
+ 20% {
+ -moz-transform: rotate(15deg);
+ }
+ 40% {
+ -moz-transform: rotate(-10deg);
+ }
+ 60% {
+ -moz-transform: rotate(5deg);
+ }
+ 80% {
+ -moz-transform: rotate(-5deg);
+ }
+ 100% {
+ -moz-transform: rotate(0);
+ }
+}
+
+@-ms-keyframes a-swing {
+ 20% {
+ -ms-transform: rotate(15deg);
+ }
+ 40% {
+ -ms-transform: rotate(-10deg);
+ }
+ 60% {
+ -ms-transform: rotate(5deg);
+ }
+ 80% {
+ -ms-transform: rotate(-5deg);
+ }
+ 100% {
+ -ms-transform: rotate(0);
+ }
+}
+
+@keyframes a-swing {
+ 20% {
+ transform: rotate(15deg);
+ }
+ 40% {
+ transform: rotate(-10deg);
+ }
+ 60% {
+ transform: rotate(5deg);
+ }
+ 80% {
+ transform: rotate(-5deg);
+ }
+ 100% {
+ transform: rotate(0);
+ }
+}
+
+
+/*摇晃*/
+
+.wobble,
+.wobble-hover:hover {
+ -webkit-animation-name: a-wobble;
+ -moz-animation-name: a-wobble;
+ -ms-animation-name: a-wobble;
+ animation-name: a-wobble;
+}
+
+@-webkit-keyframes a-wobble {
+ 0% {
+ -webkit-transform: translateX(0);
+ }
+ 15% {
+ -webkit-transform: translateX(-50px) rotate(-5deg);
+ }
+ 30% {
+ -webkit-transform: translateX(40px) rotate(3deg);
+ }
+ 45% {
+ -webkit-transform: translateX(-33px) rotate(-3deg);
+ }
+ 60% {
+ -webkit-transform: translateX(10px) rotate(2deg);
+ }
+ 75% {
+ -webkit-transform: translateX(-10px) rotate(-1deg);
+ }
+ 100% {
+ -webkit-transform: translateX(0);
+ }
+}
+
+@-moz-keyframes a-wobble {
+ 0% {
+ -moz-transform: translateX(0);
+ }
+ 15% {
+ -moz-transform: translateX(-50px) rotate(-5deg);
+ }
+ 30% {
+ -moz-transform: translateX(40px) rotate(3deg);
+ }
+ 45% {
+ -moz-transform: translateX(-33px) rotate(-3deg);
+ }
+ 60% {
+ -moz-transform: translateX(10px) rotate(2deg);
+ }
+ 75% {
+ -moz-transform: translateX(-10px) rotate(-1deg);
+ }
+ 100% {
+ -moz-transform: translateX(0);
+ }
+}
+
+@-ms-keyframes a-wobble {
+ 0% {
+ -ms-transform: translateX(0);
+ }
+ 15% {
+ -ms-transform: translateX(-50px) rotate(-5deg);
+ }
+ 30% {
+ -ms-transform: translateX(40px) rotate(3deg);
+ }
+ 45% {
+ -ms-transform: translateX(-33px) rotate(-3deg);
+ }
+ 60% {
+ -ms-transform: translateX(10px) rotate(2deg);
+ }
+ 75% {
+ -ms-transform: translateX(-10px) rotate(-1deg);
+ }
+ 100% {
+ -ms-transform: translateX(0);
+ }
+}
+
+@keyframes a-wobble {
+ 0% {
+ transform: translateX(0);
+ }
+ 15% {
+ transform: translateX(-50px) rotate(-5deg);
+ }
+ 30% {
+ transform: translateX(40px) rotate(3deg);
+ }
+ 45% {
+ transform: translateX(-33px) rotate(-3deg);
+ }
+ 60% {
+ transform: translateX(10px) rotate(2deg);
+ }
+ 75% {
+ transform: translateX(-10px) rotate(-1deg);
+ }
+ 100% {
+ transform: translateX(0);
+ }
+}
+
+
+/*震铃*/
+
+.ring,
+.ring-hover:hover {
+ -webkit-animation-name: a-ring;
+ -moz-animation-name: a-ring;
+ -ms-animation-name: a-ring;
+ animation-name: a-ring;
+}
+
+@-webkit-keyframes a-ring {
+ 0% {
+ -webkit-transform: scale(1);
+ }
+ 10%,
+ 20% {
+ -webkit-transform: scale(0.9) rotate(-3deg);
+ }
+ 30%,
+ 50%,
+ 70%,
+ 90% {
+ -webkit-transform: scale(1.1) rotate(3deg);
+ }
+ 40%,
+ 60%,
+ 80% {
+ -webkit-transform: scale(1.1) rotate(-3deg);
+ }
+ 100% {
+ -webkit-transform: scale(1) rotate(0);
+ }
+}
+
+@-moz-keyframes a-ring {
+ 0% {
+ -moz-transform: scale(1);
+ }
+ 10%,
+ 20% {
+ -moz-transform: scale(0.9) rotate(-3deg);
+ }
+ 30%,
+ 50%,
+ 70%,
+ 90% {
+ -moz-transform: scale(1.1) rotate(3deg);
+ }
+ 40%,
+ 60%,
+ 80% {
+ -moz-transform: scale(1.1) rotate(-3deg);
+ }
+ 100% {
+ -moz-transform: scale(1) rotate(0);
+ }
+}
+
+@-ms-keyframes a-ring {
+ 0% {
+ -ms-transform: scale(1);
+ }
+ 10%,
+ 20% {
+ -ms-transform: scale(0.9) rotate(-3deg);
+ }
+ 30%,
+ 50%,
+ 70%,
+ 90% {
+ -ms-transform: scale(1.1) rotate(3deg);
+ }
+ 40%,
+ 60%,
+ 80% {
+ -ms-transform: scale(1.1) rotate(-3deg);
+ }
+ 100% {
+ -ms-transform: scale(1) rotate(0);
+ }
+}
+
+@keyframes a-ring {
+ 0% {
+ transform: scale(1);
+ }
+ 10%,
+ 20% {
+ transform: scale(0.9) rotate(-3deg);
+ }
+ 30%,
+ 50%,
+ 70%,
+ 90% {
+ transform: scale(1.1) rotate(3deg);
+ }
+ 40%,
+ 60%,
+ 80% {
+ transform: scale(1.1) rotate(-3deg);
+ }
+ 100% {
+ transform: scale(1) rotate(0);
+ }
+}
+
+
+/*旋转*/
+
+.rotate,
+.rotate-hover:hover {
+ -webkit-animation-name: a-rotate;
+ -moz-animation-name: a-rotate;
+ -ms-animation-name: a-rotate;
+ animation-name: a-rotate;
+}
+
+@-webkit-keyframes a-rotate {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(359deg);
+ }
+}
+
+@-moz-keyframes a-rotate {
+ 0% {
+ -moz-transform: rotate(0deg);
+ }
+ 100% {
+ -moz-transform: rotate(359deg);
+ }
+}
+
+@-ms-keyframes a-rotate {
+ 0% {
+ -ms-transform: rotate(0deg);
+ }
+ 100% {
+ -ms-transform: rotate(359deg);
+ }
+}
+
+@keyframes a-rotate {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(359deg);
+ }
+}
+
+
+/*不变文本*/
+
+.text-black,
+a.text-black:link,
+a.text-black:visited,
+.button.border-black,
+blockquote.border-black strong,
+.pager.border-black a,
+.pager-prev.border-black,
+.pager-next.border-black {
+ color: #000;
+}
+
+a.text-black:hover {
+ color: #666;
+}
+
+.text-gray,
+a.text-gray:link,
+a.text-gray:visited,
+.button.border-gray,
+blockquote.border-gray strong,
+.pager.border-gray a,
+.pager-prev.border-gray,
+.pager-next.border-gray {
+ color: #999;
+}
+
+.text-white,
+a.text-white:link,
+a.text-white:visited,
+.button.border-white,
+blockquote.border-white,
+.pager.border-white a,
+.pager-prev.border-white,
+.pager-next.border-white {
+ color: #fff;
+}
+
+.text-red,
+a.text-red:link,
+a.text-red:visited,
+.button.border-red,
+.button.bg-red-light,
+blockquote.border-red strong,
+.pager.border-red a,
+.pager-prev.border-red,
+.pager-next.border-red,
+.badge.bg-red-light,
+.alert-red,
+.check-error {
+ color: #e33;
+}
+
+.text-yellow,
+a.text-yellow:link,
+a.text-yellow:visited,
+.button.border-yellow,
+.button.bg-yellow-light,
+blockquote.border-yellow strong,
+.pager.border-yellow a,
+.pager-prev.border-yellow,
+.pager-next.border-yellow,
+.badge.bg-yellow-light,
+.alert-yellow,
+.check-warning {
+ color: #f60;
+}
+
+.text-blue,
+a.text-blue:link,
+a.text-blue:visited,
+.button.border-blue,
+.button.bg-blue-light,
+blockquote.border-blue strong,
+.pager.border-blue a,
+.pager-prev.border-blue,
+.pager-next.border-blue,
+.badge.bg-blue-light,
+.alert-blue {
+ color: #0ae;
+}
+
+.text-green,
+a.text-green:link,
+a.text-green:visited,
+.button.border-green,
+.button.bg-green-light,
+blockquote.border-green strong,
+.pager.border-green a,
+.pager-prev.border-green,
+.pager-next.border-green,
+.badge.bg-green-light,
+.alert-green,
+.check-success {
+ color: #2c7;
+}
+
+.text-red-light,
+a.text-red-light:link,
+a.text-red-light:visited,
+.button.border-red-light,
+blockquote.border-red-light strong,
+.pager.border-red-light a {
+ color: #fdc;
+}
+
+.text-yellow-light,
+a.text-yellow-light:link,
+a.text-yellow-light:visited,
+.button.border-yellow-light,
+blockquote.border-yellow-light strong,
+.pager.border-yellow-light a,
+.pager-prev.border-yellow-light,
+.pager-next.border-yellow-light {
+ color: #fec;
+}
+
+.text-blue-light,
+a.text-blue-light:link,
+a.text-blue-light:visited,
+.button.border-blue-light,
+blockquote.border-blue-light strong,
+.pager.border-blue-light a,
+.pager-prev.border-blue-light,
+.pager-next.border-blue-light {
+ color: #def;
+}
+
+.text-green-light,
+a.text-green-light:link,
+a.text-green-light:visited,
+.button.border-green-light,
+blockquote.border-green-light strong,
+.pager.border-green-light a,
+.pager-prev.border-green-light,
+.pager-next.border-green-light {
+ color: #ded;
+}
+
+
+/*颜色重设*/
+
+.bg-inverse,
+.bg-inverse a {
+ color: #fff;
+}
+
+a.text-white:hover,
+.bg-inverse a:hover {
+ color: #ddd;
+}
+
+
+/*不变背景*/
+
+.bg,
+.table .current,
+.table .current td,
+.table .current th,
+.button.active,
+.pointer.border .active,
+.nav-menu ul a:hover,
+.nav-menu.nav-pills .active ul a:hover,
+.bg-inverse .nav.nav-menu ul a:hover,
+.bg-inverse .nav.nav-menu .active ul a:hover,
+.bg-inverse .nav.nav-menu.nav-tabs ul a:hover,
+.bg-inverse .nav.nav-menu.nav-pills ul a:hover,
+.bg-inverse .nav-menu.nav-inline.nav-big ul a:hover,
+.navbar-body .nav ul a:hover {
+ background-color: #f5f5f5;
+}
+
+.bg-black,
+.border-black .button.active,
+.pointer.border-black .active,
+.nav-pills.border-black .active a,
+.nav-main.border-black .nav-head,
+.pagination.border-black .active {
+ background-color: #000;
+}
+
+.bg-gray,
+.border-gray .button.active,
+.pointer.border-gray .active,
+.nav-pills.border-gray .active a,
+.nav-main.border-gray .nav-head,
+.pagination.border-gray .active {
+ background-color: #999;
+}
+
+.bg-white,
+.button.bg,
+.border-white .button.active,
+.pointer.border-white .active,
+.nav-pills.border-white .active a,
+.nav-main.border-white .nav-head,
+.pagination.border-white .active {
+ background-color: #fff;
+}
+
+
+/*红*/
+
+.bg-red,
+.border-red .button.active,
+.pointer.border-red .active,
+.nav-pills.border-red .active a,
+.nav-main.border-red .nav-head,
+.pagination.border-red .active {
+ background-color: #e33;
+}
+
+.bg-yellow,
+.border-yellow .button.active,
+.pointer.border-yellow .active,
+.nav-pills.border-yellow .active a,
+.nav-main.border-yellow .nav-head,
+.pagination.border-yellow .active {
+ background-color: #f60;
+}
+
+.bg-blue,
+.border-blue .button.active,
+.pointer.border-blue .active,
+.nav-pills.border-blue .active a,
+.nav-main.border-blue .nav-head,
+.pagination.border-blue .active {
+ background-color: #0ae;
+}
+
+.bg-green,
+.border-green .button.active,
+.pointer.border-green .active,
+.nav-pills.border-green .active a,
+.pagination.border-green .active {
+ background-color: #2c7;
+}
+
+.bg-red-light,
+.table .red,
+.table .red td,
+.table .red th,
+.alert-red,
+.border-red-light .button.active,
+.pointer.border-red-light .active,
+.nav-pills.border-red-light .active a,
+.nav-main.border-red-light .nav-head,
+.pagination.border-red-light .active {
+ background-color: #fee;
+}
+
+.bg-yellow-light,
+.table .yellow,
+.table .yellow td,
+.table .yellow th,
+.alert-yellow,
+.border-yellow-light .button.active,
+.pointer.border-yellow-light .active,
+.nav-pills.border-yellow-light .active a,
+.nav-main.border-yellow-light .nav-head,
+.pagination.border-yellow-light .active {
+ background-color: #ffd;
+}
+
+.bg-blue-light,
+.table .blue,
+.table .blue td,
+.table .blue th,
+.alert-blue,
+.border-blue-light .button.active,
+.pointer.border-blue-light .active,
+.nav-pills.border-blue-light .active a,
+.nav-main.border-blue-light .nav-head,
+.pagination.border-blue-light .active {
+ background-color: #eff;
+}
+
+.bg-green-light,
+.table .green,
+.table .green td,
+.table .green th,
+.alert-green,
+.border-green-light .button.active,
+.pointer.border-green-light .active,
+.nav-pills.border-green-light .active a,
+.nav-main.border-green-light .nav-head,
+.pagination.border-green-light .active {
+ background-color: #efd;
+}
+
+
+/*不变边框*/
+
+.border-dashed {
+ border-style: dashed;
+}
+
+.border-dotted {
+ border-style: dotted;
+}
+
+.border-double {
+ border-style: double;
+}
+
+.border-inset {
+ border-style: inset;
+}
+
+.border-outset {
+ border-style: outset;
+}
+
+.border-black,
+.border-black .button,
+.border-black .tab-nav li a,
+.border-black .tab-body,
+.button.bg-black,
+.selected.border-black,
+.pointer.border-black li,
+.nav.border-black .active a,
+.nav.nav-tabs.border-black,
+.nav-main.border-black a,
+.nav-main.border-black .nav-head,
+.pagination.border-black li,
+.pager.border-black a {
+ border-color: #000;
+}
+
+.border-gray,
+.border-gray .button,
+.border-gray .tab-nav li a,
+.border-gray .tab-body,
+.button.bg-gray,
+.selected.border-gray,
+.pointer.border-gray li,
+.nav.border-gray .active a,
+.nav.nav-tabs.border-gray,
+.nav-main.border-gray a,
+.nav-main.border-gray .nav-head,
+.pagination.border-gray li,
+.pager.border-gray a {
+ border-color: #999;
+}
+
+.border-white,
+.border-white .button,
+.border-white .tab-nav li a,
+.border-white .tab-body,
+.button.bg-white,
+.selected.border-white,
+.pointer.border-white li,
+.nav.border-white .active a,
+.nav.nav-tabs.border-white,
+.nav-main.border-white a,
+.nav-main.border-white .nav-head,
+.pagination.border-white li,
+.pager.border-white a {
+ border-color: #fff;
+}
+
+.border-red,
+.border-red .button,
+.border-red .tab-nav li a,
+.border-red .tab-body,
+.button.bg-red,
+.selected.border-red,
+.pointer.border-red li,
+.check-error .input,
+.nav.border-red .active a,
+.nav.nav-tabs.border-red,
+.nav-main.border-red a,
+.nav-main.border-red .nav-head,
+.pagination.border-red li,
+.pager.border-red a {
+ border-color: #e33;
+}
+
+.border-yellow,
+.border-yellow .button,
+.border-yellow .tab-nav li a,
+.border-yellow .tab-body,
+.button.bg-yellow,
+.selected.border-yellow,
+.pointer.border-yellow li,
+.check-warning .input,
+.nav.border-yellow .active a,
+.nav.nav-tabs.border-yellow,
+.nav-main.border-yellow a,
+.nav-main.border-yellow .nav-head,
+.pagination.border-yellow li,
+.pager.border-yellow a {
+ border-color: #f60;
+}
+
+.border-blue,
+.border-blue .button,
+.border-blue .tab-nav li a,
+.border-blue .tab-body,
+.button.bg-blue,
+.selected.border-blue,
+.pointer.border-blue li,
+.nav.border-blue .active a,
+.nav.nav-tabs.border-blue,
+.nav-main.border-blue a,
+.nav-main.border-blue .nav-head,
+.pagination.border-blue li,
+.pager.border-blue a {
+ border-color: #0ae;
+}
+
+.border-green,
+.border-green .button,
+.border-green .tab-nav li a,
+.border-green .tab-body,
+.button.bg-green,
+.selected.border-green,
+.pointer.border-green li,
+.check-success .input,
+.nav.border-green .active a,
+.nav.nav-tabs.border-green,
+.nav-main.border-green a,
+.nav-main.border-green .nav-head,
+.pagination.border-green li,
+.pager.border-green a {
+ border-color: #2c7;
+}
+
+.border-red-light,
+.border-red-light .button,
+.border-red-light .tab-nav li a,
+.border-red-light .tab-body,
+.button.bg-red-light,
+.selected.border-red-light,
+.alert-red,
+.pointer.border-red-light li,
+.nav.border-red-light .active a,
+.nav.nav-tabs.border-red-light,
+.nav-main.border-red-light a,
+.nav-main.border-red-light .nav-head,
+.pagination.border-red-light li,
+.pager.border-red-light a {
+ border-color: #fee;
+}
+
+.border-yellow-light,
+.border-yellow-light .button,
+.border-yellow-light .tab-nav li a,
+.border-yellow-light .tab-body,
+.button.bg-yellow-light,
+.selected.border-yellow-light,
+.alert-yellow,
+.pointer.border-yellow-light li,
+.nav.border-yellow-light .active a,
+.nav.nav-tabs.border-yellow-light,
+.nav-main.border-yellow-light a,
+.nav-main.border-yellow-light .nav-head,
+.pagination.border-yellow-light li,
+.pager.border-yellow-light a {
+ border-color: #ffd;
+}
+
+.border-blue-light,
+.border-blue-light .button,
+.border-blue-light .tab-nav li a,
+.border-blue-light .tab-body,
+.button.bg-blue-light,
+.selected.border-blue-light,
+.alert-blue,
+.pointer.border-blue-light li,
+.nav.border-blue-light .active a,
+.nav.nav-tabs.border-blue-light,
+.nav-main.border-blue-light a,
+.nav-main.border-blue-light .nav-head,
+.pagination.border-blue-light li,
+.pager.border-blue-light a {
+ border-color: #eff;
+}
+
+.border-green-light,
+.border-green-light .button,
+.border-green-light .tab-nav li a,
+.border-green-light .tab-body,
+.button.bg-green-light,
+.selected.border-green-light,
+.alert-green,
+.pointer.border-green-light li,
+.nav.border-green-light .active a,
+.nav.nav-tabs.border-green-light,
+.nav-main.border-green-light a,
+.nav-main.border-green-light .nav-head,
+.pagination.border-green-light li,
+.pager.border-green-light a {
+ border-color: #efd;
+}
+
+
+/*悬浮背景*/
+
+.button:hover,
+.button:focus,
+.button.bg:hover,
+.button.bg:focus {
+ background-color: #f5f5f5;
+}
+
+.button.border-black:hover,
+.button.border-black:focus,
+.button.bg-black:hover,
+.button.bg-black:focus {
+ color: #fff;
+ border-color: #666;
+ background-color: #666;
+}
+
+.button.border-gray:hover,
+.button.border-gray:focus,
+.button.bg-gray:hover,
+.button.bg-gray:focus {
+ color: #fff;
+ border-color: #aaa;
+ background-color: #aaa;
+}
+
+.button.border-white:hover,
+.button.border-white:focus,
+.button.bg-white:hover,
+.button.bg-white:focus {
+ color: #333;
+ border-color: #f5f5f5;
+ background-color: #f5f5f5;
+}
+
+.button.border-red:hover,
+.button.border-red:focus,
+.button.bg-red:hover,
+.button.bg-red:focus {
+ color: #fff;
+ border-color: #f00;
+ background-color: #f00;
+}
+
+.button.border-yellow:hover,
+.button.border-yellow:focus,
+.button.bg-yellow:hover,
+.button.bg-yellow:focus {
+ color: #fff;
+ border-color: #f90;
+ background-color: #f90;
+}
+
+.button.border-blue:hover,
+.button.border-blue:focus,
+.button.bg-blue:hover,
+.button.bg-blue:focus {
+ color: #fff;
+ border-color: #3bd;
+ background-color: #3bd;
+}
+
+.button.border-green:hover,
+.button.border-green:focus,
+.button.bg-green:hover,
+.button.bg-green:focus {
+ color: #fff;
+ border-color: #5d8;
+ background-color: #5d8;
+}
+
+.button.border-red-light:hover,
+.button.border-red-light:focus,
+.button.bg-red-light:hover,
+.button.bg-red-light:focus,
+.alert-red:hover {
+ color: #e33;
+ border-color: #fdc;
+ background-color: #fdc;
+}
+
+.button.border-yellow-light:hover,
+.button.border-yellow-light:focus,
+.button.bg-yellow-light:hover,
+.button.bg-yellow-light:focus,
+.alert-yellow:hover {
+ color: #f60;
+ border-color: #fec;
+ background-color: #fec;
+}
+
+.button.border-blue-light:hover,
+.button.border-blue-light:focus,
+.button.bg-blue-light:hover,
+.button.bg-blue-light:focus,
+.alert-blue:hover {
+ color: #0ae;
+ border-color: #def;
+ background-color: #def;
+}
+
+.button.border-green-light:hover,
+.button.border-green-light:focus,
+.button.bg-green-light:hover,
+.button.bg-green-light:focus,
+.alert-green:hover {
+ color: #2c7;
+ border-color: #cfa;
+ background-color: #cfa;
+}
+
+.sliders_left,
+.sliders_right {
+ opacity: 0;
+ -webkit-transition: opacity, background-color .2s ease;
+ width: 84px;
+ height: 100%;
+ position: fixed;
+ top: 0;
+ pointer-events: none
+}
+
+.sliders_left {
+ left: 1px;
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB8AAABOCAYAAADYfM1rAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABsJJREFUeNq8ml1oFFcUx2fu3Pnand0toYGAIAhCIU8+BQo+5UkQfLIYkAihxWDJgxgsFoOh4IMQIhZFibSkWAIG+1QQhIJQEAo+CYIgCIJPm93Z+div2Z2ZO9NzZ3e2s5Ok7iZzc8MSZrPZ39xz7v+c/727fM1qcEc1jFr1um2ZSwIS7IkvJ1f4o4JbprHUrFv3JUmKrj3PM/BRgLudzqlWw17XNI0TRZELw5Drdl0HsQaHQaAaemVLVVWJzhohxPE8zxVLpZ9xyBiu65V7GAvTFEyhdNaCgF8WiqW7TGfebNTPE8+9rCgKAIXouSAMjULpi4tBEBBmcN/zjtfN2sYQOAg4TSsuIAGVXZ9wbOBhKOiV8haAJ+gCi8MtSvIjRVX/9DwSXTOBm0btpoD40/ECiwbPv4M8L/uEcAQiQEfmcKfdPt1pN28lww0wF8BzsLgdD8Idj0zhhJAJsxbJSsAYD8KtqrllUZTeep4/9PpM4UZ1Z0OWpONJWSEkPM9rhQee79OVzgZet8zLYUDOy7I8yDPAyyCrBZpjnwS7/icTuNvtTkPdvpeWVb5QvAQ3UqWz3mugw6sqlCDcNM9qMs+SrKwpivoX1XO4TxnFXHjYPFfWBQGdSsqK59EbrVBc8QEc7BHuTGbeajXOem5nCSadDHdTo7IKOTcpq0zhvu9P2WZtMwXm1Fx+GcL/3vX8z74HOmj5rFWhfMryZLJ8YlHczuW1x77fK59M4JZlXEM8N5vMM6A+QRX7npC9ZZUJvNNxZpxW43ZKVgQW2EVYaMZ+sjo0HBglU688pa4kJas7sqS8onkOx1DPWHCwQ/dFEZ9I5hlm+w+Ee5V2qyAYT7cjwxt1a5743nwy3AC3Y1fyOVkdGO657smGbT1MywpW9iJcf3Q9ciDRoFHKZ02n5VPRknnGovQ7aHrbG1FWB4KbteptcCUzQ66E4z/EsiIjympseLvdmnW7zvW0K4lkxfHNUarY/w3M7dNZCPEnLXAl+Xyeo+Hup4CDTrUKUXjd9TyOO2RX2nfmemXnCRiDqaSsIOwvtUJhzTuArEaG050k4M4kXcl/Zj8kvk+4LAbaa1PXbtbXd5v9wgL4sfJh8zyU83CofAaaUas8BbA01K0k6ZEMZt91d5vAzGZu6tV1EeOvYveZNPvEDwZmP3M4bOouEH94UxfJqlicg0XtuL7PZT1QvKlr2uZGqm5zCjX7WHqbZZ6H4ZEr2dmClV0a6laR2dce0PKZZZ6H4Kah/0Q3dWmzXyyVFoLIlRCO1UBdp32Nhnug54HZF6quzw4cwWHGzbhb9Td7kS3quRK2hyZIyWlraUilXN4CazzJ+rAIqXntLrVC8Q3Q1Y6xMAVboM2B1lnBaaRFNXcJ4M3oCcg9XXwQ+bOturXEGk6Ppj4Ikrwc9CsYnT1dhHXbWgffNs0UTockq495hJ73HCkfnRTSGl+r7Dzjw1BlVGT6ngAekpL/Dlqm0SvpPNezTvw01IL15Ouyegw1FtoyRVldTIafOtZux7nS7bTPMQt7PERJ/gMJ+Lfk6qc3AEZyMwzIMabwKP9K7iqwP8Xhp/kHBUxAD3gC4hOYwkH3NoT/Eq10sfx65+ThbN02bzCFRxZHlP5GWLqTDD+VX7vVuOV73RmmcDpkJbcKcXgVy4/2gEh+1Z2nXBiUmMKj6qfkafWzk/mHmzgB8rvPM4bTcH/EkrKYrn6e252HFMwzhffkp2wjQfw1LT/bMh4GxD/BFB7LD369j8Pfz78W5R/+zBQOwCaWc3OwK3WT8oP7mKlbxi2m8Eh+WHyDJfnHPeR3A3azs0zh/e5HzceL+AZo+HO5nGDolSfw3ARTeLQAe/IrJ+UHKThm6OXNccwPCrnxf3jEV7GsLsTyG7gfQs61GvaVUd/nwGevUH5fICyupfM/jvs51KkzNJ8ViMPrlPxUo1p5xo8gv0PBAeiC/ucg/HZSftT92Ca4H5bw6A2g/Aqp8kurX8dxltzPuJ9MPmMB97PNC/jxbvej/xIGwRRTeKL8vku5n0n6+ct+7iczOAAdKL/fQPidtPtp1q1rTOFRuDF+J4jy1XT7bTbqt8ke7ifzz1JFWYHNB95Ouh96Pl/Tq1sQBY0pPMq/qi4C++OQ+xGEk6Zefcgc3ne/g/Ybh9/33PlOu3WBKTwCiuJrLEkru9yPWduI3Q/T70zA7Nfi9hvnnx480W+PwKXA/KsqWMkN2m/c/UD3Xzcs8yZisfsc2onyqCr29D/Y/fTcr3uG+cx7+hdfwe5nNQ5/vwDZR/L1pL79uuO7PBgO/1vYijuFYvGHfwUYAPcx+HTfYvXXAAAAAElFTkSuQmCC) center no-repeat;
+}
+
+.sliders_right {
+ right: 0px;
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB8AAABOCAYAAADYfM1rAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABrpJREFUeNq8Wl1oFFcUvvO7O/s7szu72fZBEAQhIPgkFISCUBCEPrVECJWGloiiVAwpPgglEqm0RHwIlUiLkCBE6pMg+JQnoZAnoRAoCIIgBAKpuzu7M3Pn3pmeM5tZZjdJmya5uSFC9iHf3O873znfGSNt/t061XFay5IkGbKi/qbq2XuEEE6O4KjND5s/ybI0qigK4YzOhlFE9Ixx9yjAZUppOQxDEgEo3J6EjM5wFpw9EnBN1196nkfwAeIPZFkJ/O7vYRTWiAQfCPyWi6Z1NyLkD9/3+w8ADDSY110UfnNgm1fs+jiANxljffqjKDwf+O60UPD4H0V9W7aql13XJZzz5PaEUTrLg+CMUHA82Vz+qarpS6h/8gCKIutw+2VgoSwUHI9l164yzt8EQRDT32OAHKeuuyAcHKCcql0bB/rpgP4hGwt8b1IwOFCtZVYLxdLtNP1gP8ID/wFnbFQoOJ5CybwPLKxAA0r732Dgf2DDEAoOavNKbQTtt5HWH84o9boPhILH6svyulW1vx22X8TZZED9MaHgePRs7nnWMObTDxDrT72FkPPjQsHxlC17KgyjtSH9y0A/+D/ShYKD2rRSq38J1e8m9oslINEZaECzQsFj+6naWqlsTqXt1xu/wTQL6Pl9g0tkb1/5YvmhrCjP09MP9We++zgKo9pef0/6S97rUyLbFbsxAdq/H2y/UiPwOovCaO/bT5I2Yfxe6na7HPXv2w/GL/Xdm0LBY/tljJVcvnhvWH9G/R8ZC04LBcdTMit3gPXVtP1w/EL7RfsVhILDodXayEW4vZO2H5yT/6f9yvu2CaYfs3J1uP2GPPgmoN6YUHA8oP2SpmeWhscvg/bL99B+DwSOZFsV+zpQ/3bIfuUt+ynCwLfGX3NL/4H0A4921ve6M2LBceeC9AMS3NnefuktaL+fCgWP7Ve27u2QfmD7cRd3S7+HBo7pB+i/BL1/cyj9HtvNfocG3pNfeW9VaxPb7ce+hvTzhVBwPBlIP5ms8XA4/QD9C2HIG4PgArZPsF8//ST0y7JUoV7n14EtVcQmEkmSW62PYPqhif695SO8ANNvUhjt/5Z+euHTn+OcnRAKjidfMufBbS+Gdv9C4Ma7vyIUHOmG5WOCMb4+kP2j8BO349wUCh53P1XdqDca40OJiHhdZ1ooOILomhp3OnzblbCBMwCkKAgF11UFtOa1Tru1iMWGB7XHIswYufvCwFW4qQwl1Wo2H2PCTYCx+HgYvYJe8IMQcBno1uDWHce5FoX8Qq/IIoKexxdPMAPGQRMuBBx1Dhg95bndud5sJ7HXke5C2bqsato7IT7XVRVbp+G0WsuKLOtpYEXVHxWKpadCOhyAAYBM2q3mHPA8mlQ39viAsb8suzY1UBfSIdvKd93PGaVXsLoTnbHHV+yRi/BwjpCRisA4Mh2n/TixVUJ3rlCaymSzr8VkOKhsGJlKu/nhCVR6JW0rmGcvy6Y1LyTJACjRwNNOuz0NgOeGbLVu10cu7frQvcl+kOrWsKDOeJ47o2zRje0Tk4xZrY8rirYhJL2izhGJCk679WTYVrDN/pzL5VeE5HbYSuNvsNUvYKgTic5oK2ifqxAkbwtZl6St9ul2O2OwFHyV6Nyj23Oq9sg4fEaFgOuagvQe73achbStUOdi2byq6fobIVuqFttKjm2FC+Fg+9SWiiVzSch+jrbCUQk6z2AUStsqCNjbil2/LuS1CA6nuH1S7yz1vVuDOrvUsusXgZCmEHANphXctoK2QtrTdBv54u1s1lgV8jZKTdkKCDiWtlUYkRXTrNwX8h4O6cXeDZU9yYJgLK2z5/sb1VojTiVCwFFn0PUkeHpu2FZlqzoB0XhdyItftBWOaafVXAbgQhpY07Pz+XzxxYGm4W5zBW+JdIPOs1Bop+M9O2mfPHxtN+pTB5xJO988thUAw6T6DGw1PWQrF///ZS/tc1/gaCu45UDY76fPknlDz2TWDiVi72grAIT2uS3sS7LyrGRajw4t328P+yqE/fa1MBX2UWef0ndA9+VDXS4G6MawH9BT7lbYT+nMrTiVKJtCwGNbEWJAdW8L+9lc4Y6Ry7069LUqCftb06of9lOpBJa6qpA/4JDjVALhwIOwH1D/ykD79LxNu77/9vmf4PEOzUMI+61tYb9kVftLnRDwJJUkYb+fSrR4qXsm9JUJ6HyTc3Yu2a1QZ8b4WuPjj25IROyRW83mdwiaFBimEvzrEUmWXeEvi6B/G3Dz+AcEh/a541In5OY4kz3P/7PT7b7LFYrfm1ZlnhzR+UeAAQCCZGgP21ZUhQAAAABJRU5ErkJggg==) center no-repeat;
+}
+
+.sliders_left.actived,
+.sliders_right.actived {
+ cursor: pointer;
+ opacity: 1;
+ pointer-events: auto
+}
+
+.sliders_left:hover {
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB8AAABOCAYAAADYfM1rAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAACWtJREFUeNq8WntQVNcZP/exC8vD1RWUlUAEFGWNE4Otaeqrj5GqUGPVDiiDFXVgpNqHhBQtkUoQH0iC1cTBWG3Z0mA1aSXVJOKQUYkmaFJtHIjRhooC4rLI3b17797n6Tl3WTWjUR57/Zb7z8LO75zv9/1+33fOQtx2MkDvMNAUoCiC+lfH7sLG3rdXUTCIz7buzqD1BiZJEoHT4OjNXYX/7N5RSpAAqDIAh69v3aErOEEAEGSgwRVX04z3nDs3kxR6E6IfGQJOdplpQOgHbjQagEdhLPvbflkDCJUiEBjeteyBwBYx+wNSV55Ryvd9vbamF3bGEiTaJSSA4gXgaSr53Ivj120h9eGZ0MDfb99b0OI9NZfA+Vd9wBQXxuRO3pVJEpQScHDMYpDBAL52X5r2nrO8FPOM34MKBDILQVZCWW5kSEyrtsiA84wKjFdY81vX82pVQjZinqFCIJ4B+E74QvvzY9IO3c1QIIFpCuuZAjXXC6sY0B6H008gnlWU7pFy3JUsW2neN+gJGM+IV6OBAqdv/y3n3/yxdFxgWnWLKOUeWsyeWLE8mA5hv7HYwMmKBh3cNdu7t1+txFWOQ5V9PKda1xfFj3i26YEFB4pnGYqmAzfWHlZJ0YSrG6LqlnkA4g3fa0iJW/naQ7M1VGCKIjWu37nxaqVD+a/NzzMU0KL4EY6Vkyo0WQUcnNB4psFnPcfSP+X+nkNSfTwjFxNRupfFl642B0Xe+tY6GQo49m2n92bcka5Xqii0YxIrGu1RQcDTzcv2PDv6x3WPLNLB2yeNTEsx2tvX18okZyZRuyIgCRSeABYloXlRYmH+YxUyKJ61NkmB452VpR3y5Wl+WSmarIx8dlLlz2nSIAYc3M9zC3NmbqP7QAEaErR0Q9ytWBWkjSnIt4YlNPfLlIgB9lTMs0e+E/nO7aKDuMrxx1UV6ZmDINH4w7pZMUv39tuYBmSfKNV4MjnUsaGaJ3ui7m+Twd6I9qUTSrMH5IoDbZOnHX9Z3yqdm4vtlMR6RszKbqBkxJctDzWYewa0mYG4WAf35ZQGZvdWbCw4FGSfkkcF04evKE+0PN8w4H7QX2BR5cMOdxXWIrMy4l0TeDjgIRit2prmxuUVD6oZ9cc+8XO8q7yyF7RN8PMsixBANphdmrg9g+qHrAYM7pfVF8yH6ZeFulV4EfgFZQJIbgjSojfkjTRFtw66DT8u3XfE9rj372ytomhS69l49MU824Ln2adGpdqHNAM8avpEfkkd7SquVrF9gj6ekZ5DvVGtC+JfXjfkAeTbThlY06e6qzbfgpdnECSGJjX7lNy0uCS+LCOYDmMCDk5o6abAdc/ns8/z9kLNPvFwoOA2iWQ1IrskZtikpoCMXg+kG/EsqB7zsZ6SagLNg76pBAFzKrDC5xpmxazYFrC572Gyqu+u2M2TjliqbypRBAhINqxnUcIflqPWqQQcXJMV6tEtroYlX0knski/byM9C4wKUqN/nz0sKLI9oCebe7KiACs7oxpcO6tov6xUn6yeMb24d+LImXWBPmBop1Qamwd6Tji275dp1oKzoOLjDbLPUDGmOSXpV/l6nGZJDIRHoku9R3NuKJ+k+owE84yKjCHFhWNLMgxkEK/LgVJzMenmuLOevRU43drZCnUrwa2AWRF5+aNDE77Q7daCQC5W7yyrVikhjOibPvHY+xSYduy71sV79Ly5oM/3HFrvAC0vaNWNjziIa1ow30pN2JgNdA7ygvPtAt/see81P+aVzBDDcIfu4KzHZVYkePcChzYgO6UgBZ5AkMnmjHIvKi58xMHOTiDJNfI7q3mFidQdfPqY7OJIdVKj6FG0qwtMvUj1Rp1xl1frDo52q6SOLcpU2GBG8qLRCGkcj0qdxOdzm7m6tTqDAxBmiGybY83P9bpkoEqqNq3gVvqZtL/CKbZO1hUcx/jhsw9NDE7dp/GvwL7fKsYz3PZaGQomXcFx/OCpNfkmr/WKyPkWgKvfTd6wnWf3V+jjcH3TC34MZDCb9nRxhsAQoiyoiH/0PlreVfXYmjbvJwvu/9tAPA9MMhGm+IszRua8zLsUoEi+BeAbh7PC6wc9cne0bmn3R/LoxbusxNQPvKwv/bgCRJK1nPZUVEOgUrqCQ7Td+WM3LifYYbcE3l+AEHSBSz+6xB4uCKTOH8qIiTI75sdsXM4xEpBEtAAt/xBclO2bu4Qr0wLB+iNPLLHhU+uTw9LLeaR/H/8o6YRsPMVtq5HQwVGXtN8fM6NXFw2XxjfxrAxkGS0AvVygY9wZ9x/f1B2cJGhxQdymTHRSYUUvyoCCFkCo4Kp8Iusq91G6ruA4hgdFX0uxvpTnYWSNf0WF2idPc69VMVJnnK7gOCaPTLFPCEqx8268e1yAKhAI1lzPlNZAODj59Rsci23e2PXrgvjIVi/bl3402KOD5AtnmT9t1hVcO1iQoczihC0ZXhcQBcy/qqLqV8EFwV7Y7r00Q1dwHGNCk5pmR+QUc0h+EpIf1j8qQOo4U1LDKy6LruA4pkdnlY8BzzXwbmRAEsoAOj+7YEdsfc+ON3UHR7OOkpFYlkl4wh3YfmXEPypB0CLWp190HV2lKziOUIPl1qKxxas1+xUQNOIfkio46a6o7Bb+N0FXcBxJlll104Zl7MHykyRFK0ABesLe7d5Qq0DJ+HjwIfaHn457Kd+ijLvo9dxLf6fy5ZSTzjdKH/fZoX/Hguw3a+KOTMlF8SIv+9KP5Pcxe6DgGntujm5p98eokPjmn8Vu/A2H7FdE/PsMCILDtzdUs3JPpK7gOL4fvWTfMyEpR/D0I/Wl3w0cUUc6iw7qDo7td1lSSW6IMKpN5Hz2i18twkepHztr1uoKjsNEm3tW2l7PFF1o9vDLD/Ff5yyr6OCvTNYVHEe8ObnxJ9a8LV63qtmvguxXJiSjveO3tZLqNekKjiMtYV1JLJXcKHiUu+nvlL+y/aNza4Xu4Gg0VPB/B9BceI/IK3enn0a3fc1/ek8u0BUcx4hga9svErflCi4VyLj7qbj7QfDXzoKDjOiI0hUcx9SoeUdmWpbtExH/+PsYPP1y4I7lYNuva1SoUISz163rBYCsCqais/MvOIOu2ugQQjv74RvshZaifN3BcdxwN0/ZdD7tU2qYZKSDfbfYofyodhI8gYgJt11cFrcpX7gDgdCrahfJIgcBDZ5QzIlbsYcXOdOHrX9eG0KHM+m23xX9X4ABAA2gdiKdt/lhAAAAAElFTkSuQmCC);
+ background-color: rgba(0, 0, 0, .06);
+}
+
+.sliders_right:hover {
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB8AAABOCAYAAADYfM1rAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAACUlJREFUeNq8mntQVNcdx8+55z727t7d5SHyilgSlcBoNQ9pVDQTRjTRFqeJVhK6tForo9WGBImKBGNClIZAk2pwdFRSGQxM1UYrasgkra+m0kq0mlVRQCEIBnks7929j55zdyFm1ILC8cfAXwuf+/t9f887wM/s++JL7H/I6pY7rLPDf70lPmJ5DnhIhpSZZ79o46+PkYUO64XmE3Fmxq/5Md9J5Q8DzvBGCAQrAwQf/O0LwZ6at3PrOuyTHgp89qjkPIaBgEEQcCIDWLPMf3RuZZGsOkXq8JnBiz8cZ5j2JQSeB2DxAzQxV6IK7W99oOEP0PzGTiNlUdiHiUbg2wIhBIiFgDcz4ETLnqVnGo/Mp+o5+WHlAxp/GZyzCGqQPA1gOay/hQF/rlyzrbW3IYwqnNiPfWYejDHbtkKNAQgxgBcRkI0dftvOv1qkARVRhRP7efDa1GB2nJ0BngcQTAjUKhUxh6o2Z1KHc4yhxxbyxwRW41wI68/h8Buw/p815K+rdlTEUIUTCxEjzsf7p6eS8DMMAzgBAd4C0C77a0U9ssOPKpzYNP/ELZHCc6V94eeNLOgWvgvbczFzG6QNJzY/OGuRGQQ0IvwRDj+AQULgQnfZ/H/W711KHS6xfk0LRm5KIs1H9x6H32hlwV9rN37wXXd1FFU4sTHSlM+nSYtz+vTnRRZwFkUsvPRGkaLJ/NDhA/TAmf6/ywhGj58l4WdJ+HH5taCrk/529f3cofZXZsCZCznXiyM2JQjQ1IlI9nMIiGYWlLcXr7jYcjyeWtj7bITwo8szzakpUP2+/IxWDuy/tmFHl7sliCqc2CTLvJ2RfFxJX/gF3H41U0dAcWU6br8aogonFuf3xnILDKlFEOHwszj8HLgBvo49VV+YRh0uIkvLHGtmIs5+hfG2X6OFBcdubd9wo+tiNFU4sVDDxJNPC7Zshkw/rL9gYIHBAvh9VeuKXWqXlSqc2FTrb9YHwfFfQW/7NUgscIpN4Ueu5W2GtOEQMkqcNSNR0CQHA8kDeMrvsrPMdr65zEYVrm8/XHDNDOPryUDFvQBvPxyPgAm337KG9/PbnPVjqMKJjTU+VzKWnVXYv/1g/TmzLB2sebtIHUT7ZYban6ebf7/cAkKukgHEsgwQsf5t3JXoE/U7sqjDOUbsfNa4JpHRWJe+/eLyE3H5VXSWpNV2nIkbAD70DTxQiCifxNrWAxXnP/ToT9rv4bqNu3sUR8C9fm/InvfZRGlBTiCY+CXwHh96+5Xagw5f27ibRIRK2PvLDzDKDFNqEq9KLQRFHoBsPw3amecrbu57lSqcmIkdUT9VeG2RqmiAOOvRH4GTzdvfu9VTfcfxyQz3/RVmeObgWGbuVk0F+gOwAm7BVo0/dH1DsVvtlX5wq9E4BiZLS1LN6ii7pnnCzxsR6DE0RPzj26251MLeZywUeqYbVyfgK8sF+vQ3I3Cpt3TplbZjC6nCifnz4eef4pakKlh/nI2AIdcPrv/PG3K3dbqbwqjCiUUZ47cEa08e1VSSgBrgDLgJSb3W0mtZRVh1BJta26m+fSBN5kD7sv86UVsQSUDFrYGuVjd4QnzlXaqee7Yfa1OMuCpJU1RPV2OBrn+FoziNOpyYqkBFxh6T7NfXcQ4CyWRxUId3u9sCDte9QzbcH3w97f9yDnV4afXGAllwBDF4udaw6ypOvgAQ+dVkv4V5VOH/bti34ltQPpeXSK8FuseMInTG+acnaRpUqMFvdlVNOH4rP1fAyQVZqINlWQVTTctSfblHrrrcMp06d6tO8dNrmcW8VeWRQEYeDjcO+Sj0TOlEn3nb3bKsS8ACbfjhZTV/yu3i66JEfFJDxqM1K5tbZgWuXqLikiMRoNLhLjWfiL/Qc2AZZ2L0v048JrBYy6pkifVvdLkVOoOl3dkUWlr/bgF5kYx46Ak3zu5x3KzCSEvsXpc33MMOVzUV7a96a7cqdfohAScYBisYLKoBtXEjUlcqONyKotLZZI7XfbymAX4dyxuZfp01BShz/TKTBMbkcOPsprJG1bV/E32qtSCTlzAYeXQmo3SyaMsebXryGNFZo7HD9cqd1r3V6cX4UuERTxqJCjRVBfiQPPnsiOT1sqxg3VU62+vB6vc2dxkaw5ER68zoaMCoRse8wA1JWHjFLSt0LpYzjaU2e+8Rm15W0BtuXFYv+K5N9uVDa1x30XlY4M099eGH6jflc2Z8pbHEY082jxfid06wzi4h4NvLatjgiurmP6lcXQylXon11jNZlXxA2OU5gWkpdyurYYMfrcnfcJOxRyPRq7NeVsi1IDA7gceH40DhfmB4Zcvp2FNtH6dxJhxuRMAeL2OtK9eGGB8/O1jwfcO73A6/4ur03awZIIjLSvVOq3BuytEZAb/Kc+tlpdGBf3I5o6DXcCsUGUC/zqLq17gwZFMSqWX5/5TVXY8LbZAz9URd8bJK19/jDT6ofz6Tg/CloKxFJta3qdflBtp9zudBed7QWRV16EZOLkvaJ159SSMh7TPGvDgn0jr96GDK6oHgMi6rgospf4Eml+hpn55wh7Djy+cEp2QQnRVVfaBeMSB8f2V2bguqikIihkJVz24Wt09baF4CoyEXWYmovHU+d/OL+FOOPSuQd/vUw429nh/4TrK/4ZEap1se0ly4J9zhbAraU52xg6y95MQh4SYJ9hPjL7Y/5Te35EF1HhCu4na165vUIpfYGgDx9ql516EA9Jj9pVFvpsiKMqj2+UDwsppdr1e7/xXLiriqGE33kFH5nsWjtixgId/jGmK47wmvbj0XXdqQl8VKni6gTyuczS+OfDMlxDjG7nIND/gOeK/cLRVcSt0NTTLP3FZWT4hzS2aMfGU7WYdUTaMDL7Rn5DezNRGM4XudrSC0JnF0drKCdSZaD6f1w0/fOLTwPx2f2lgT0KeVftRprOu3o/MTRCQ5hkvnO+BN3XXhhVXp21iJjEmod2gVO/kz/7SMR80Ty51uN42rCicxLivy3wGKsdOqTytvdkcanj36QuiynPsdk/cFP3Bl87rrSsWU28ekDwyuXfrolkSS5W5ZAbSMtXcce17X2TtcoYaUJWEfJZqQtaXX5QJAo8YGjNFgcXiO9z6dV62PsESfdOrtk+4rE1hRe3pCQcPKYgU6xRifl3f+NGRlNp7VCs1w99n/BBgAmexvSku9uBQAAAAASUVORK5CYII=);
+ background-color: rgba(0, 0, 0, .06);
+}
+
+
+/*左右悬浮*/
+
+
+/*气泡对话*/
+
+.popo {
+ width: 100%;
+}
+
+.popo .ico-left {
+ float: left;
+ margin-top: 10px;
+}
+
+.popo .ico-right {
+ float: right;
+ margin-top: 10px;
+}
+
+.popo .popo-left {
+ clear: both;
+ float: left;
+}
+
+.popo .popo-right {
+ clear: both;
+ float: right;
+}
+
+.popo .popo-body {
+ margin: 10px 0;
+ padding: 8px;
+ table-layout: fixed;
+ word-break: break-all;
+ position: relative;
+ background: -webkit-gradient( linear, 50% 0%, 50% 100%, from(#ffffff), color-stop(0.1, #ececec), color-stop(0.5, #dbdbdb), color-stop(0.9, #dcdcdc), to(#8c8c8c));
+ border: solid 1px #ddd;
+ background-color: #f5f5f5;
+}
+
+.popo .popo-body:before {
+ border: 10px solid;
+}
+
+.popo .popo-body:after {
+ border: 8px solid;
+}
+
+.popo .popo-body.left {
+ margin-left: 10px;
+ width: 75%;
+ float: left;
+ background: -webkit-gradient( linear, 50% 0%, 50% 100%, from(#ffffff), color-stop(0.1, #eae8e8), color-stop(0.4, #E3E3E3), color-stop(0.8, #DFDFDF), to(#D9D9D9));
+}
+
+.popo .popo-body.left:before {
+ content: '';
+ position: absolute;
+ width: 0;
+ height: 0;
+ top: 9px;
+ bottom: auto;
+ left: -10px;
+ border-width: 9px 10px 9px 0;
+ border-color: transparent #ddd;
+}
+
+.popo .popo-body.left:after {
+ content: '';
+ position: absolute;
+ width: 0;
+ height: 0;
+ top: 10px;
+ bottom: auto;
+ left: -8px;
+ border-width: 8px 9px 8px 0;
+ border-color: transparent #F5F5F5;
+}
+
+.popo .popo-body.right {
+ margin-right: 10px;
+ width: 75%;
+ float: right;
+ background: -webkit-gradient( linear, 50% 0%, 50% 100%, from(#e4ffa7), color-stop(0.1, #bced50), color-stop(0.4, #aed943), color-stop(0.8, #a7d143), to(#99BF40));
+}
+
+.popo .popo-body.right:before {
+ content: '';
+ position: absolute;
+ width: 0;
+ height: 0;
+ top: 9px;
+ bottom: auto;
+ left: auto;
+ right: -10px;
+ border-width: 9px 0 9px 10px;
+ border-color: transparent #ddd;
+}
+
+.popo .popo-body.right:after {
+ content: '';
+ position: absolute;
+ width: 0;
+ height: 0;
+ top: 10px;
+ bottom: auto;
+ left: auto;
+ right: -8px;
+ border-width: 8px 0 8px 9px;
+ border-color: transparent #F5F5F5;
+}
+
+
+/*--------自定义气泡风格--------*/
+
+
+/*橙色*/
+
+.popo .popo-yellow {
+ border: solid 1px #ffd;
+ background-color: #ffd;
+ color: #f60;
+}
+
+.popo .popo-yellow.left:before {
+ border-color: transparent #ffd;
+}
+
+.popo .popo-yellow.left:after {
+ border-color: transparent #ffd;
+}
+
+.popo .popo-yellow.right:before {
+ border-color: transparent #ffd;
+}
+
+.popo .popo-yellow.right:after {
+ border-color: transparent #ffd;
+}
+
+
+/*蓝色*/
+
+.popo .popo-blue {
+ border: solid 1px #eff;
+ background-color: #eff;
+ color: #0ae;
+}
+
+.popo .popo-blue.left:before {
+ border-color: transparent #eff;
+}
+
+.popo .popo-blue.left:after {
+ border-color: transparent #eff;
+}
+
+.popo .popo-blue.right:before {
+ border-color: transparent #eff;
+}
+
+.popo .popo-blue.right:after {
+ border-color: transparent #eff;
+}
+
+
+/*蓝色*/
+
+.popo .popo-green {
+ border: solid 1px #efd;
+ background-color: #efd;
+ color: #2c7;
+}
+
+.popo .popo-green.left:before {
+ border-color: transparent #efd;
+}
+
+.popo .popo-green.left:after {
+ border-color: transparent #efd;
+}
+
+.popo .popo-green.right:before {
+ border-color: transparent #efd;
+}
+
+.popo .popo-green.right:after {
+ border-color: transparent #efd;
+}
+
+
+/*--------自定义链接颜色(可选)--------*/
+
+a {
+ color: #333;
+ text-decoration: none;
+}
+
+
+/*链接-颜色*/
+
+a:focus,
+a:hover {
+ color: #0a8;
+}
+
+
+/*链接-悬浮颜色*/
+
+
+/*--------自定义文本颜色--------*/
+
+.text-main,
+a.text-main:link,
+a.text-main:visited,
+.button.border-main,
+blockquote.border-main strong,
+.pager.border-main a,
+.pager-prev.border-main,
+.pager-next.border-main,
+.nav a:hover,
+.nav-menu.nav-pills .active ul a:hover,
+.bg-inverse .nav-menu ul a:hover,
+.bg-inverse .nav.nav-menu.nav-tabs ul a:hover,
+.bg-inverse .nav.nav-menu.nav-tabs .active ul a:hover,
+.bg-inverse .nav.nav-menu.nav-pills ul a:hover,
+.bg-inverse .nav.nav-menu.nav-pills .active ul a:hover {
+ color: #0a8;
+}
+
+
+/*文本-主色*/
+
+.text-sub,
+a.text-sub:link,
+a.text-sub:visited,
+.button.border-sub,
+blockquote.border-sub strong,
+.pager.border-sub a,
+.pager-prev.border-sub,
+.pager-next.border-sub {
+ color: #0ae;
+}
+
+
+/*文本-辅色*/
+
+.text-back,
+a.text-back:link,
+a.text-back:visited,
+.button.border-back,
+blockquote.border-back,
+.pager.border-back a,
+.pager-prev.border-back,
+.pager-next.border-back {
+ color: #efe;
+}
+
+
+/*文本-背景色*/
+
+.text-mix,
+a.text-mix:link,
+a.text-mix:visited,
+.button.border-mix,
+blockquote.border-mix,
+.pager.border-mix a,
+.pager-prev.border-mix,
+.pager-next.border-mix {
+ color: #aed;
+}
+
+
+/*文本-融合色*/
+
+.text-dot,
+a.text-dot:link,
+a.text-dot:visited,
+.button.border-dot,
+blockquote.border-dot strong,
+.pager.border-dot a,
+.pager-prev.border-dot,
+.pager-next.border-dot {
+ color: #e33;
+}
+
+
+/*文本-点缀色*/
+
+
+/*--------自定义背景色--------*/
+
+.bg-main,
+.border-main .button.active,
+.pointer.border-main .active,
+.nav-pills.border-main .active a,
+.nav-main.border-main .nav-head,
+.pagination.border-main .active {
+ background-color: #0a8;
+}
+
+
+/*背景-主色*/
+
+.bg-sub,
+.border-sub .button.active,
+.pointer.border-sub .active,
+.nav-pills.border-sub .active a,
+.nav-main.border-sub .nav-head,
+.pagination.border-sub .active {
+ background-color: #0ae;
+}
+
+
+/*背景-辅色*/
+
+.bg-back,
+.border-back .button.active,
+.pointer.border-back .active,
+.nav-pills.border-back .active a,
+.nav-main.border-back .nav-head,
+.pagination.border-back .active {
+ background-color: #efe;
+}
+
+
+/*背景-背景色*/
+
+.bg-mix,
+.border-mix .button.active,
+.pointer.border-mix .active,
+.nav-pills.border-mix .active a,
+.pagination.border-mix .active {
+ background-color: #aed;
+}
+
+
+/*背景-融合色*/
+
+.bg-dot,
+.border-dot .button.active,
+.pointer.border-dot .active,
+.nav-pills.border-dot .active a,
+.nav-main.border-dot .nav-head,
+.pagination.border-dot .active {
+ background-color: #e33;
+}
+
+
+/*背景-点缀色*/
+
+
+/*--------自定义边框色--------*/
+
+.border-main,
+.border-main .button,
+.border-main .tab-nav li a,
+.border-main .tab-body,
+.button.bg-main,
+.selected.border-main,
+.pointer.border-main li,
+.nav.border-main .active a,
+.nav.nav-tabs.border-main,
+.nav-main.border-main a,
+.nav-main.border-main .nav-head,
+.pagination.border-main li,
+.pager.border-main a {
+ border-color: #0a8;
+}
+
+
+/*边框-主色*/
+
+.border-sub,
+.border-sub .button,
+.border-sub .tab-nav li a,
+.border-sub .tab-body,
+.button.bg-sub,
+.selected.border-sub,
+.pointer.border-sub li,
+.nav.border-sub .active a,
+.nav.nav-tabs.border-sub,
+.nav-main.border-sub a,
+.nav-main.border-sub .nav-head,
+.pagination.border-sub li,
+.pager.border-sub a {
+ border-color: #0ae;
+}
+
+
+/*边框-辅色*/
+
+.border-back,
+.border-back .button,
+.border-back .tab-nav li a,
+.border-back .tab-body,
+.button.bg-back,
+.selected.border-back,
+.pointer.border-back li,
+.nav.border-back .active a,
+.nav.nav-tabs.border-back,
+.nav-main.border-back a,
+.nav-main.border-back .nav-head,
+.pagination.border-back li,
+.pager.border-back a {
+ border-color: #efe;
+}
+
+
+/*边框-背景色*/
+
+.border-mix,
+.border-mix .button,
+.border-mix .tab-nav li a,
+.border-mix .tab-body,
+.button.bg-mix,
+.selected.border-mix,
+.pointer.border-mix li,
+.nav.border-mix .active a,
+.nav.nav-tabs.border-mix,
+.nav-main.border-mix a,
+.nav-main.border-mix .nav-head,
+.pagination.border-mix li,
+.pager.border-mix a {
+ border-color: #aed;
+}
+
+
+/*边框-融合色*/
+
+.border-dot,
+.border-dot .button,
+.border-dot .tab-nav li a,
+.border-dot .tab-body,
+.button.bg-dot,
+.selected.border-dot,
+.pointer.border-dot li,
+.nav.border-dot .active a,
+.nav.nav-tabs.border-dot,
+.nav-main.border-dot a,
+.nav-main.border-dot .nav-head,
+.pagination.border-dot li,
+.pager.border-dot a {
+ border-color: #e33;
+}
+
+
+/*边框-点缀色*/
+
+
+/*--------自定义按钮悬浮文本、边框及背景色--------*/
+
+.button.border-main:hover,
+.button.border-main:focus,
+.button.bg-main:hover,
+.button.bg-main:focus {
+ color: #fff;
+ border-color: #0ab;
+ background-color: #0ab;
+}
+
+
+/*主色-文本-边框-背景*/
+
+.button.border-sub:hover,
+.button.border-sub:focus,
+.button.bg-sub:hover,
+.button.bg-sub:focus {
+ color: #fff;
+ border-color: #09f;
+ background-color: #09f;
+}
+
+
+/*配色-文本-边框-背景*/
+
+.button.border-back:hover,
+.button.border-back:focus,
+.button.bg-back:hover,
+.button.bg-back:focus {
+ color: #333;
+ border-color: #cec;
+ background-color: #cec;
+}
+
+
+/*背景色-文本-边框-背景*/
+
+.button.border-mix:hover,
+.button.border-mix:focus,
+.button.bg-mix:hover,
+.button.bg-mix:focus {
+ color: #333;
+ border-color: #cec;
+ background-color: #cec;
+}
+
+
+/*融合-文本色-边框-背景*/
+
+.button.border-dot:hover,
+.button.border-dot:focus,
+.button.bg-dot:hover,
+.button.bg-dot:focus {
+ color: #fff;
+ border-color: #f00;
+ background-color: #f00;
+}
+
+
+/*点缀色-文本-边框-背景*/
+
+.waterfall {}
+
+.waterfall ul {
+ -webkit-column-width: 160px;
+ -moz-column-width: 160px;
+ -o-colum-width: 160px;
+ column-width: 160px;
+ -webkit-column-gap: 1px;
+ -moz-column-gap: 1px;
+ -o-column-gap: 1px;
+ column-gap: 1px;
+}
+
+.waterfall li {
+ display: inline-block;
+ margin: 5px 0;
+}
+
+.waterfall li img {
+ display: inline-block;
+ width: 100%;
+}
+
+
+/*瀑布流,使用到的需要调整宽度*/
\ No newline at end of file
diff --git a/ewomail-admin/public/pintuer.js b/ewomail-admin/public/pintuer.js
new file mode 100644
index 0000000..ce0b4ea
--- /dev/null
+++ b/ewomail-admin/public/pintuer.js
@@ -0,0 +1,743 @@
+$(function() {
+ $(".win-homepage").click(function() {
+ if (document.all) {
+ document.body.style.behavior = 'url(#default#homepage)';
+ document.body.setHomePage(document.URL);
+ } else {
+ alert("设置首页失败,请手动设置!");
+ }
+ });
+ $(".win-favorite").click(function() {
+ var sURL = document.URL;
+ var sTitle = document.title;
+ try {
+ window.external.addFavorite(sURL, sTitle);
+ } catch (e) {
+ try {
+ window.sidebar.addPanel(sTitle, sURL, "");
+ } catch (e) {
+ alert("加入收藏失败,请使用Ctrl+D进行添加");
+ }
+ }
+ });
+ $(".win-forward").click(function() {
+ window.history.forward(1);
+ });
+ $(".win-back").click(function() {
+ window.history.back(-1);
+ });
+ $(".win-backtop").click(function() {
+ $('body,html').animate({
+ scrollTop: 0
+ }, 1000);
+ return false;
+ });
+ $(".win-refresh").click(function() {
+ window.location.reload();
+ });
+ $(".win-print").click(function() {
+ window.print();
+ });
+ $(".win-close").click(function() {
+ window.close();
+ });
+ $('.checkall').click(function() {
+ var e = $(this);
+ var name = e.attr("name");
+ var checkfor = e.attr("checkfor");
+ var type;
+ if (checkfor != '' && checkfor != null && checkfor != undefined) {
+ type = e.closest('form').find("input[name='" + checkfor + "']");
+ } else {
+ type = e.closest('form').find("input[type='checkbox']");
+ };
+ if (name == "checkall") {
+ $(type).each(function(index, element) {
+ element.checked = true;
+ });
+ e.attr("name", "ok");
+ } else {
+ $(type).each(function(index, element) {
+ element.checked = false;
+ });
+ e.attr("name", "checkall");
+ }
+ });
+ $('.dropdown-toggle').click(function() {
+ $(this).closest('.button-group, .drop').addClass("open");
+ });
+ //新增下拉列表移入/移除
+ $(".dropdown-hover").hover(function() {
+ $(".button-group, .drop").removeClass("open");
+ $(this).closest('.button-group, .drop').addClass("open");
+ }, function() {
+
+ });
+ $(document).bind("click", function(e) {
+ if ($(e.target).closest(".button-group.open, .drop.open").length == 0) {
+ $(".button-group, .drop").removeClass("open");
+ }
+ });
+ $checkplaceholder = function() {
+ var input = document.createElement('input');
+ return 'placeholder' in input;
+ };
+ if (!$checkplaceholder()) {
+ $("textarea[placeholder], input[placeholder]").each(function(index, element) {
+ if ($(element).attr("placeholder") || $emptyplaceholder(element)) {
+ $(element).val($(element).attr("placeholder"));
+ $(element).data("pintuerholder", $(element).css("color"));
+ $(element).css("color", "rgb(169,169,169)");
+ $(element).focus(function() {
+ $hideplaceholder($(this));
+ });
+ $(element).blur(function() {
+ $showplaceholder($(this));
+ });
+ }
+ })
+ };
+ $emptyplaceholder = function(element) {
+ var $content = $(element).val();
+ return ($content.length === 0) || $content == $(element).attr("placeholder");
+ };
+ $showplaceholder = function(element) {
+ //不为空及密码框
+ if (($(element).val().length === 0 || $(element).val() == $(element).attr("placeholder")) && $(element).attr("type") != "password") {
+ $(element).val($(element).attr("placeholder"));
+ $(element).data("pintuerholder", $(element).css("color"));
+ $(element).css("color", "rgb(169,169,169)");
+ }
+ };
+ var $hideplaceholder = function(element) {
+ if ($(element).data("pintuerholder")) {
+ $(element).val("");
+ $(element).css("color", $(element).data("pintuerholder"));
+ $(element).removeData("pintuerholder");
+ }
+ };
+ $('textarea, input, select').blur(function() {
+ var e = $(this);
+ if (e.attr("data-validate")) {
+ e.closest('.field').find(".input-help").remove();
+ var $checkdata = e.attr("data-validate").split(',');
+ var $checkvalue = e.val();
+ var $checkstate = true;
+ var $checktext = "";
+ if (e.attr("placeholder") == $checkvalue) {
+ $checkvalue = "";
+ }
+ if ($checkvalue != "" || e.attr("data-validate").indexOf("required") >= 0) {
+ for (var i = 0; i < $checkdata.length; i++) {
+ var $checktype = $checkdata[i].split(':');
+ if (!$pintuercheck(e, $checktype[0], $checkvalue)) {
+ $checkstate = false;
+ $checktext = $checktext + "" + $checktype[1] + " ";
+ }
+ }
+ };
+ if ($checkstate) {
+ e.closest('.form-group').removeClass("check-error");
+ e.parent().find(".input-help").remove();
+ e.closest('.form-group').addClass("check-success");
+ } else {
+ e.closest('.form-group').removeClass("check-success");
+ e.closest('.form-group').addClass("check-error");
+ e.closest('.field').append('');
+ }
+ }
+ });
+ $pintuercheck = function(element, type, value) {
+ $pintu = value.replace(/(^\s*)|(\s*$)/g, "");
+ switch (type) {
+ case "required":
+ return /[^(^\s*)|(\s*$)]/.test($pintu);
+ break;
+ case "chinese":
+ return /^[\u0391-\uFFE5]+$/.test($pintu);
+ break;
+ case "number":
+ return /^([+-]?)\d*\.?\d+$/.test($pintu);
+ break;
+ case "integer":
+ return /^-?[1-9]\d*$/.test($pintu);
+ break;
+ case "plusinteger":
+ return /^[1-9]\d*$/.test($pintu);
+ break;
+ case "unplusinteger":
+ return /^-[1-9]\d*$/.test($pintu);
+ break;
+ case "znumber":
+ return /^[1-9]\d*|0$/.test($pintu);
+ break;
+ case "fnumber":
+ return /^-[1-9]\d*|0$/.test($pintu);
+ break;
+ case "double":
+ return /^[-\+]?\d+(\.\d+)?$/.test($pintu);
+ break;
+ case "plusdouble":
+ return /^[+]?\d+(\.\d+)?$/.test($pintu);
+ break;
+ case "unplusdouble":
+ return /^-[1-9]\d*\.\d*|-0\.\d*[1-9]\d*$/.test($pintu);
+ break;
+ case "english":
+ return /^[A-Za-z]+$/.test($pintu);
+ break;
+ case "username":
+ return /^[a-z]\w{3,}$/i.test($pintu);
+ break;
+ case "mobile":
+ return /^\s*(15\d{9}|13\d{9}|14\d{9}|17\d{9}|18\d{9})\s*$/.test($pintu);
+ break;
+ case "phone":
+ return /^((\(\d{2,3}\))|(\d{3}\-))?(\(0\d{2,3}\)|0\d{2,3}-)?[1-9]\d{6,7}(\-\d{1,4})?$/.test($pintu);
+ break;
+ case "tel":
+ return /^((\(\d{3}\))|(\d{3}\-))?13[0-9]\d{8}?$|15[89]\d{8}?$|170\d{8}?$|147\d{8}?$/.test($pintu) || /^((\(\d{2,3}\))|(\d{3}\-))?(\(0\d{2,3}\)|0\d{2,3}-)?[1-9]\d{6,7}(\-\d{1,4})?$/.test($pintu);
+ break;
+ case "email":
+ return /^[^@]+@[^@]+\.[^@]+$/.test($pintu);
+ break;
+ case "url":
+ return /^http:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$/.test($pintu);
+ break;
+ case "ip":
+ return /^[\d\.]{7,15}$/.test($pintu);
+ break;
+ case "qq":
+ return /^[1-9]\d{4,10}$/.test($pintu);
+ break;
+ case "currency":
+ return /^\d+(\.\d+)?$/.test($pintu);
+ break;
+ case "zipcode":
+ return /^[1-9]\d{5}$/.test($pintu);
+ break;
+ case "chinesename":
+ return /^[\u0391-\uFFE5]{2,15}$/.test($pintu);
+ break;
+ case "englishname":
+ return /^[A-Za-z]{1,161}$/.test($pintu);
+ break;
+ case "age":
+ return /^[1-99]?\d*$/.test($pintu);
+ break;
+ case "date":
+ return /^((((1[6-9]|[2-9]\d)\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\d|3[01]))|(((1[6-9]|[2-9]\d)\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\d|30))|(((1[6-9]|[2-9]\d)\d{2})-0?2-(0?[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))$/.test($pintu);
+ break;
+ case "datetime":
+ return /^((((1[6-9]|[2-9]\d)\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\d|3[01]))|(((1[6-9]|[2-9]\d)\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\d|30))|(((1[6-9]|[2-9]\d)\d{2})-0?2-(0?[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-)) (20|21|22|23|[0-1]?\d):[0-5]?\d:[0-5]?\d$/.test($pintu);
+ break;
+ case "idcard":
+ return /^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/.test($pintu);
+ break;
+ case "bigenglish":
+ return /^[A-Z]+$/.test($pintu);
+ break;
+ case "smallenglish":
+ return /^[a-z]+$/.test($pintu);
+ break;
+ case "color":
+ return /^#[0-9a-fA-F]{6}$/.test($pintu);
+ break;
+ case "ascii":
+ return /^[\x00-\xFF]+$/.test($pintu);
+ break;
+ case "md5":
+ return /^([a-fA-F0-9]{32})$/.test($pintu);
+ break;
+ case "zip":
+ return /(.*)\.(rar|zip|7zip|tgz)$/.test($pintu);
+ break;
+ case "img":
+ return /(.*)\.(jpg|gif|ico|jpeg|png)$/.test($pintu);
+ break;
+ case "doc":
+ return /(.*)\.(doc|xls|docx|xlsx|pdf)$/.test($pintu);
+ break;
+ case "mp3":
+ return /(.*)\.(mp3)$/.test($pintu);
+ break;
+ case "video":
+ return /(.*)\.(rm|rmvb|wmv|avi|mp4|3gp|mkv)$/.test($pintu);
+ break;
+ case "flash":
+ return /(.*)\.(swf|fla|flv)$/.test($pintu);
+ break;
+ case "radio":
+ var radio = element.closest('form').find('input[name="' + element.attr("name") + '"]:checked').length;
+ return eval(radio == 1);
+ break;
+ default:
+ var $test = type.split('#');
+ if ($test.length > 1) {
+ switch ($test[0]) {
+ case "compare":
+ return eval(Number($pintu) + $test[1]);
+ break;
+ case "regexp":
+ return new RegExp($test[1], "gi").test($pintu);
+ break;
+ case "length":
+ var $length;
+ if (element.attr("type") == "checkbox") {
+ $length = element.closest('form').find('input[name="' + element.attr("name") + '"]:checked').length;
+ } else {
+ $length = $pintu.replace(/[\u4e00-\u9fa5]/g, "***").length;
+ }
+ return eval($length + $test[1]);
+ break;
+ case "ajax":
+ var $getdata;
+ var $url = $test[1] + $pintu;
+ $.ajaxSetup({
+ async: false
+ });
+ $.getJSON($url, function(data) {
+ $getdata = data.getdata;
+ });
+ if ($getdata == "true") {
+ return true;
+ }
+ break;
+ case "repeat":
+ return $pintu == jQuery('input[name="' + $test[1] + '"]').eq(0).val();
+ break;
+ default:
+ return true;
+ break;
+ }
+ break;
+ } else {
+ return true;
+ }
+ }
+ };
+ $('form').submit(function() {
+ $(this).find('input[data-validate],textarea[data-validate],select[data-validate]').trigger("blur");
+ $(this).find('input[placeholder],textarea[placeholder]').each(function() {
+ $hideplaceholder($(this));
+ });
+ var numError = $(this).find('.check-error').length;
+ if (numError) {
+ $(this).find('.check-error').first().find('input[data-validate],textarea[data-validate],select[data-validate]').first().focus().select();
+ return false;
+ }
+ });
+ $('.form-reset').click(function() {
+ $(this).closest('form').find(".input-help").remove();
+ $(this).closest('form').find('.form-submit').removeAttr('disabled');
+ $(this).closest('form').find('.form-group').removeClass("check-error");
+ $(this).closest('form').find('.form-group').removeClass("check-success");
+ });
+ $('.tab .tab-nav li').each(function() {
+ var e = $(this);
+ var trigger = e.closest('.tab').attr("data-toggle");
+ if (trigger == "hover") {
+ e.mouseover(function() {
+ $showtabs(e);
+ });
+ e.click(function() {
+ return false;
+ });
+ } else {
+ e.click(function() {
+ $showtabs(e);
+ return false;
+ });
+ }
+ });
+ //2015-05-27 新增,ajax提交表单扩展
+ $.fn.ajaxSubmit = function(fn) {
+ $(this).find('input[data-validate],textarea[data-validate],select[data-validate]').trigger("blur");
+ $(this).find('input[placeholder],textarea[placeholder]').each(function() {
+ $hideplaceholder($(this));
+ });
+ var numError = $(this).find('.check-error').length;
+ if (numError) {
+ $(this).find('.check-error').first().find('input[data-validate],textarea[data-validate],select[data-validate]').first().focus().select();
+ return false;
+ }
+ if (fn && typeof fn == "function") {
+ fn()
+ }
+ };
+ $showtabs = function(e) {
+ var detail = e.children("a").attr("href");
+ e.closest('.tab .tab-nav').find("li").removeClass("active");
+ e.closest('.tab').find(".tab-body .tab-panel").removeClass("active");
+ e.addClass("active");
+ $(detail).addClass("active");
+ };
+ $('.dialogs').each(function() {
+ var e = $(this);
+ var trigger = e.attr("data-toggle");
+ if (trigger == "hover") {
+ e.mouseover(function() {
+ $showdialogs(e);
+ });
+ } else if (trigger == "click") {
+ e.click(function() {
+ $showdialogs(e);
+ });
+ }
+ });
+ //这里目前还存在问题
+ $showdialogs = function(e) {
+ var trigger = e.attr("data-toggle");
+ var getid = e.attr("data-target");
+ var data = e.attr("data-url");
+ var mask = e.attr("data-mask");
+ var width = e.attr("data-width");
+ var detail = "";
+ var masklayout = $('
');
+ if (width == null) {
+ width = "80%";
+ }
+
+ if (mask == "1") {
+ $("body").append(masklayout);
+ }
+ detail = '';
+ if (getid != null) {
+ detail = detail + $(getid).html();
+ }
+ if (data != null) {
+ detail = detail + $.ajax({
+ url: data,
+ async: false
+ }).responseText;
+ }
+ detail = detail + '
';
+
+ var win = $(detail);
+ win.find(".dialog").addClass("open");
+ $("body").append(win);
+ var x = parseInt($(window).width() - win.outerWidth()) / 2;
+ var y = parseInt($(window).height() - win.outerHeight()) / 2;
+ if (y <= 10) {
+ y = 10
+ }
+ win.css({
+ "left": x,
+ "top": y
+ });
+ win.find(".dialog-close,.close").each(function() {
+ $(this).click(function() {
+ win.remove();
+ $('.dialog-mask').remove();
+ });
+ });
+ masklayout.click(function() {
+ win.remove();
+ $(this).remove();
+ });
+ };
+ $('.tips').each(function() {
+ var e = $(this);
+ var title = e.attr("title");
+ var trigger = e.attr("data-toggle");
+ e.attr("title", "");
+ if (trigger == "" || trigger == null) {
+ trigger = "hover";
+ }
+ if (trigger == "hover") {
+ e.mouseover(function() {
+ $showtips(e, title);
+ });
+ } else if (trigger == "click") {
+ e.click(function() {
+ $showtips(e, title);
+ });
+ } else if (trigger == "show") {
+ e.ready(function() {
+ $showtips(e, title);
+ });
+ }
+ });
+ //2015-11-04 修复tips title 重叠
+ $showtips = function(e, title) {
+ var trigger = e.attr("data-toggle");
+ var place = e.attr("data-place");
+ var width = e.attr("data-width");
+ var css = e.attr("data-style");
+ var image = e.attr("data-image");
+ var content = e.attr("content");
+ var getid = e.attr("data-target");
+ var data = e.attr("data-url");
+ var x = 0;
+ var y = 0;
+ var html = "";
+ var detail = "";
+
+ if (image != null) {
+ detail = detail + ' ';
+ }
+ if (content != null) {
+ detail = detail + '' + content + '
';
+ }
+ if (getid != null) {
+ detail = detail + $(getid).html();
+ }
+ if (data != null) {
+ detail = detail + $.ajax({
+ url: data,
+ async: false
+ }).responseText;
+ }
+ if (title != null && title != "") {
+ if (detail != null && detail != "") {
+ detail = '' + title + '
' + detail;
+ } else {
+ detail = '' + title + '
';
+ }
+ e.attr("title", "");
+ }
+ detail = '' + detail + '
';
+ html = $(detail);
+
+ $("body").append(html);
+ if (width != null) {
+ html.css("width", width);
+ }
+ if (place == "" || place == null) {
+ place = "top";
+ }
+ if (place == "left") {
+ x = e.offset().left - html.outerWidth() - 5;
+ y = e.offset().top - html.outerHeight() / 2 + e.outerHeight() / 2;
+ } else if (place == "top") {
+ x = e.offset().left - html.outerWidth() / 2 + e.outerWidth() / 2;
+ y = e.offset().top - html.outerHeight() - 5;
+ } else if (place == "right") {
+ x = e.offset().left + e.outerWidth() + 5;
+ y = e.offset().top - html.outerHeight() / 2 + e.outerHeight() / 2;
+ } else if (place == "bottom") {
+ x = e.offset().left - html.outerWidth() / 2 + e.outerWidth() / 2;
+ y = e.offset().top + e.outerHeight() + 5;
+ }
+ if (css != "") {
+ html.addClass(css);
+ }
+ html.css({
+ "left": x + "px",
+ "top": y + "px",
+ "position": "absolute"
+ });
+ if (trigger == "hover" || trigger == "click" || trigger == null) {
+ e.mouseout(function() {
+ html.remove();
+ e.attr("title", title)
+ });
+ }
+ };
+ $('.alert .close').each(function() {
+ $(this).click(function() {
+ $(this).closest('.alert').remove();
+ });
+ });
+ $('.radio label').each(function() {
+ var e = $(this);
+ e.click(function() {
+ e.closest('.radio').find("label").removeClass("active");
+ e.addClass("active");
+ });
+ });
+ $('.checkbox label').each(function() {
+ var e = $(this);
+ e.click(function() {
+ if (e.find('input').is(':checked')) {
+ e.addClass("active");
+ } else {
+ e.removeClass("active");
+ };
+ });
+ });
+ $('.collapse .panel-head').each(function() {
+ var e = $(this);
+ e.click(function() {
+ //增加反复折叠判断
+ if (e.closest('.collapse').find(".toggle-actvie").html() != '' && e.closest('.collapse').find(".toggle-actvie").html() != undefined) {
+ e.closest('.panel').toggleClass("active");
+ } else {
+ e.closest('.collapse').find(".panel").removeClass("active");
+ e.closest('.panel').addClass("active");
+ }
+ });
+ });
+ $('.icon-navicon').each(function() {
+ var e = $(this);
+ var target = e.attr("data-target");
+ e.click(function() {
+ $(target).toggleClass("nav-navicon");
+ });
+ });
+ $('.banner').each(function() {
+ var e = $(this);
+ var pointer = e.attr("data-pointer");
+ var interval = e.attr("data-interval");
+ var style = e.attr("data-style");
+ var items = e.attr("data-item");
+ var items_s = e.attr("data-small");
+ var items_m = e.attr("data-middle");
+ var items_b = e.attr("data-big");
+ var num = e.find(".carousel .item").length;
+ var win = $(window).width();
+ var i = 1;
+
+ if (interval == null) {
+ interval = 5
+ };
+ if (items == null || items < 1) {
+ items = 1
+ };
+ if (items_s != null && win > 760) {
+ items = items_s
+ };
+ if (items_m != null && win > 1000) {
+ items = items_m
+ };
+ if (items_b != null && win > 1200) {
+ items = items_b
+ };
+
+ var itemWidth = Math.ceil(e.outerWidth() / items);
+ var page = Math.ceil(num / items);
+ e.find(".carousel .item").css("width", itemWidth + "px");
+ e.find(".carousel").css("width", itemWidth * num + "px");
+
+ var carousel = function() {
+ i++;
+ if (i > page) {
+ i = 1;
+ }
+ $showbanner(e, i, items, num);
+ };
+ var play = setInterval(carousel, interval * 600);
+
+ e.mouseover(function() {
+ clearInterval(play);
+ });
+ e.mouseout(function() {
+ play = setInterval(carousel, interval * 600);
+ });
+
+ if (pointer != 0 && page > 1) {
+ var point = ' ';
+ for (var j = 1; j < page; j++) {
+ point = point + ' ';
+ };
+ point = point + ' ';
+ var pager = $(point);
+ if (style != null) {
+ pager.addClass(style);
+ };
+ e.append(pager);
+ pager.css("left", e.outerWidth() * 0.5 - pager.outerWidth() * 0.5 + "px");
+ pager.find("li").click(function() {
+ $showbanner(e, $(this).val(), items, num);
+ });
+ var lefter = $('');
+ var righter = $('');
+ if (style != null) {
+ lefter.addClass(style);
+ righter.addClass(style);
+ };
+ e.append(lefter);
+ e.append(righter);
+
+ lefter.click(function() {
+ i--;
+ if (i < 1) {
+ i = page;
+ }
+ $showbanner(e, i, items, num);
+ });
+ righter.click(function() {
+ i++;
+ if (i > page) {
+ i = 1;
+ }
+ $showbanner(e, i, items, num);
+ });
+ };
+ });
+ $showbanner = function(e, i, items, num) {
+ var after = 0,
+ leftx = 0;
+ leftx = -Math.ceil(e.outerWidth() / items) * (items) * (i - 1);
+ if (i * items > num) {
+ after = i * items - num;
+ leftx = -Math.ceil(e.outerWidth() / items) * (num - items);
+ };
+ e.find(".carousel").stop(true, true).animate({
+ "left": leftx + "px"
+ }, 800);
+ e.find(".pointer li").removeClass("active");
+ e.find(".pointer li").eq(i - 1).addClass("active");
+ };
+ $(".spy a").each(function() {
+ var e = $(this);
+ var t = e.closest(".spy");
+ var target = t.attr("data-target");
+ var top = t.attr("data-offset-spy");
+ var thistarget = "";
+ var thistop = "";
+ if (top == null) {
+ top = 0;
+ };
+ if (target == null) {
+ thistarget = $(window);
+ } else {
+ thistarget = $(target);
+ };
+
+ thistarget.bind("scroll", function() {
+ if (target == null) {
+ thistop = $(e.attr("href")).offset().top - $(window).scrollTop() - parseInt(top);
+ } else {
+ thistop = $(e.attr("href")).offset().top - thistarget.offset().top - parseInt(top);
+ };
+
+ if (thistop < 0) {
+ t.find('li').removeClass("active");
+ e.parents('li').addClass("active");
+ };
+
+ });
+ });
+ $(".fixed").each(function() {
+ var e = $(this);
+ var style = e.attr("data-style");
+ var top = e.attr("data-offset-fixed");
+ if (top == null) {
+ top = e.offset().top;
+ } else {
+ top = e.offset().top - parseInt(top);
+ };
+ if (style == null) {
+ style = "fixed-top";
+ };
+
+ $(window).bind("scroll", function() {
+ var thistop = top - $(window).scrollTop();
+ if (style == "fixed-top" && thistop < 0) {
+ e.addClass("fixed-top");
+ } else {
+ e.removeClass("fixed-top");
+ };
+
+ var thisbottom = top - $(window).scrollTop() - $(window).height();
+ if (style == "fixed-bottom" && thisbottom > 0) {
+ e.addClass("fixed-bottom");
+ } else {
+ e.removeClass("fixed-bottom");
+ };
+ });
+
+ });
+
+})
\ No newline at end of file
diff --git a/ewomail-admin/templates/.htaccess b/ewomail-admin/templates/.htaccess
new file mode 100644
index 0000000..c59c358
--- /dev/null
+++ b/ewomail-admin/templates/.htaccess
@@ -0,0 +1,4 @@
+Deny from all
+
+Options -Indexes
+
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Admin/edit.html b/ewomail-admin/templates/Center/Admin/edit.html
new file mode 100644
index 0000000..f895be3
--- /dev/null
+++ b/ewomail-admin/templates/Center/Admin/edit.html
@@ -0,0 +1,166 @@
+{include file="$HOME/header.html"}
+
+{include file="$HOME/footer.html"}
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Admin/index.html b/ewomail-admin/templates/Center/Admin/index.html
new file mode 100644
index 0000000..deafe82
--- /dev/null
+++ b/ewomail-admin/templates/Center/Admin/index.html
@@ -0,0 +1,44 @@
+{include file="$HOME/header.html"}
+
+{include file="$HOME/footer.html"}
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Admin/user.html b/ewomail-admin/templates/Center/Admin/user.html
new file mode 100644
index 0000000..7278ef5
--- /dev/null
+++ b/ewomail-admin/templates/Center/Admin/user.html
@@ -0,0 +1,113 @@
+{include file="$HOME/header.html"}
+
+{include file="$HOME/footer.html"}
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Domain/dkim.html b/ewomail-admin/templates/Center/Domain/dkim.html
new file mode 100644
index 0000000..5016eef
--- /dev/null
+++ b/ewomail-admin/templates/Center/Domain/dkim.html
@@ -0,0 +1,46 @@
+
+
+
+
+ {$L.3047}
+
+
+
+ {$L.3048}
+ {$L.3049}
+ {$L.3050}
+
+
+
+ TXT
+ dkim._domainkey
+
+
+
+
+
+
+
+
+ {$L.3051}
+
+
+
+ {$L.1208}
+ {$L.3052}
+
+
+
+ {if $keysok}{$L.1206}{else}{$L.1207}{/if}
+ {$data.testkeys}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Domain/edit.html b/ewomail-admin/templates/Center/Domain/edit.html
new file mode 100644
index 0000000..aee6a5b
--- /dev/null
+++ b/ewomail-admin/templates/Center/Domain/edit.html
@@ -0,0 +1,59 @@
+{include file="$HOME/header.html"}
+
+{include file="$HOME/footer.html"}
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Domain/index.html b/ewomail-admin/templates/Center/Domain/index.html
new file mode 100644
index 0000000..577629b
--- /dev/null
+++ b/ewomail-admin/templates/Center/Domain/index.html
@@ -0,0 +1,61 @@
+{include file="$HOME/header.html"}
+
+
+{include file="$HOME/footer.html"}
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Group/edit.html b/ewomail-admin/templates/Center/Group/edit.html
new file mode 100644
index 0000000..2744117
--- /dev/null
+++ b/ewomail-admin/templates/Center/Group/edit.html
@@ -0,0 +1,90 @@
+{include file="$HOME/header.html"}
+
+
+{include file="$HOME/footer.html"}
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Group/index.html b/ewomail-admin/templates/Center/Group/index.html
new file mode 100644
index 0000000..28ce043
--- /dev/null
+++ b/ewomail-admin/templates/Center/Group/index.html
@@ -0,0 +1,32 @@
+{include file="$HOME/header.html"}
+
+{include file="$HOME/footer.html"}
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Index/footer.html b/ewomail-admin/templates/Center/Index/footer.html
new file mode 100644
index 0000000..691287b
--- /dev/null
+++ b/ewomail-admin/templates/Center/Index/footer.html
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Index/header.html b/ewomail-admin/templates/Center/Index/header.html
new file mode 100644
index 0000000..e98aece
--- /dev/null
+++ b/ewomail-admin/templates/Center/Index/header.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+ 拼图后台管理-后台管理
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Index/index.html b/ewomail-admin/templates/Center/Index/index.html
new file mode 100644
index 0000000..e69de29
diff --git a/ewomail-admin/templates/Center/Index/login.html b/ewomail-admin/templates/Center/Index/login.html
new file mode 100644
index 0000000..734b18b
--- /dev/null
+++ b/ewomail-admin/templates/Center/Index/login.html
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+ {$WEB_TITLE}-{$L.2035}
+
+
+
+
+
+
+
+
+
+
+
+
{$L.2035}
+
{$WEB_TITLE}
+
+
+
+
+
+
{$WEB_COPYRIGHT}
+ {if $WEB_ICP}
{$WEB_ICP}
{/if}
+
+
+
+
+
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Log/index.html b/ewomail-admin/templates/Center/Log/index.html
new file mode 100644
index 0000000..98fcbda
--- /dev/null
+++ b/ewomail-admin/templates/Center/Log/index.html
@@ -0,0 +1,43 @@
+{include file="$HOME/header.html"}
+
+
+{include file="$HOME/footer.html"}
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/System/config.html b/ewomail-admin/templates/Center/System/config.html
new file mode 100644
index 0000000..db8dbd7
--- /dev/null
+++ b/ewomail-admin/templates/Center/System/config.html
@@ -0,0 +1,61 @@
+{include file="$HOME/header.html"}
+
+{include file="$HOME/footer.html"}
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/System/index.html b/ewomail-admin/templates/Center/System/index.html
new file mode 100644
index 0000000..284a47c
--- /dev/null
+++ b/ewomail-admin/templates/Center/System/index.html
@@ -0,0 +1,93 @@
+{include file="$HOME/header.html"}
+
+
+ {if $default_password}
+
+ {$L.2037}
+
+ {/if}
+
+
+ {$L.90103}:{$data.domain_count}
+ {$L.3075}:{$data.users_count}
+ {$L.3076}:{$data.bytes_count}GB
+
+
+
+
+
+
+ {$L.3061}
+
+
+
+ {$L.3062}:
+ {$data.hostname}
+ {$L.3063}:
+ {$data.ip}
+
+
+ {$L.3064}:
+ {$data.uname}
+ {$L.3065}:
+ {$data.web}
+
+
+ php:
+ {$data.php}
+ mysql:
+ {$data.mysql}
+
+
+ {$L.3066}:
+ {$data.upload_max_filesize}
+ {$L.3067}:
+ {$data.post_max_size}
+
+
+
+ {$L.3069}:
+ {$data.version}
+ {$L.3071}:
+ www.ewomail.com
+
+
+
+
+
+
+
{$L.90206}
+
+
+
+ {$L.2044}
+ {$L.2045}
+ {$L.2046}
+ {$L.1114}
+
+ {foreach $log_list as $v}
+
+ {$v.username}
+ {$v.ip}
+ {$v.explain}
+ {$v.ctime}
+
+ {/foreach}
+
+
+
+
{$page}
+
+
+
+
+
+{include file="$HOME/footer.html"}
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Users/config.html b/ewomail-admin/templates/Center/Users/config.html
new file mode 100644
index 0000000..567f66f
--- /dev/null
+++ b/ewomail-admin/templates/Center/Users/config.html
@@ -0,0 +1,72 @@
+{include file="$HOME/header.html"}
+
+{include file="$HOME/footer.html"}
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Users/edit.html b/ewomail-admin/templates/Center/Users/edit.html
new file mode 100644
index 0000000..c8046cc
--- /dev/null
+++ b/ewomail-admin/templates/Center/Users/edit.html
@@ -0,0 +1,126 @@
+{include file="$HOME/header.html"}
+
+{include file="$HOME/footer.html"}
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Users/index.html b/ewomail-admin/templates/Center/Users/index.html
new file mode 100644
index 0000000..1ec6ce7
--- /dev/null
+++ b/ewomail-admin/templates/Center/Users/index.html
@@ -0,0 +1,117 @@
+{include file="$HOME/header.html"}
+
+
+
+
+{include file="$HOME/footer.html"}
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/Users/rec.html b/ewomail-admin/templates/Center/Users/rec.html
new file mode 100644
index 0000000..9c4bd4d
--- /dev/null
+++ b/ewomail-admin/templates/Center/Users/rec.html
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+ {$L.1101}
+
+
+
+ {$L.1119}
+ {$L.3020}
+ {$L.3021}
+
+ {foreach $list as $v}
+
+
+ {$v.day}
+ {$v.s_num} {$L.1200}
+ {$v.c_num} {$L.1200}
+
+ {/foreach}
+
+
{$page}
+
+
+
+
+
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/footer.html b/ewomail-admin/templates/Center/footer.html
new file mode 100644
index 0000000..17da918
--- /dev/null
+++ b/ewomail-admin/templates/Center/footer.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/header.html b/ewomail-admin/templates/Center/header.html
new file mode 100644
index 0000000..eaf6f22
--- /dev/null
+++ b/ewomail-admin/templates/Center/header.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+ {$WEB_TITLE}-{$L.2035}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {foreach $admin_menu as $v}
+
+
+
+ {$v.title}
+
+
+ {foreach $v.child as $d}
+
+
+
+ {$d.title}
+
+
+ {/foreach}
+
+
+ {/foreach}
+
+
+
+
+
+
+ {if $admin_bar}
+
+ {$admin_bar}
+
+ {/if}
\ No newline at end of file
diff --git a/ewomail-admin/templates/Center/jump.html b/ewomail-admin/templates/Center/jump.html
new file mode 100644
index 0000000..d3ce44d
--- /dev/null
+++ b/ewomail-admin/templates/Center/jump.html
@@ -0,0 +1,15 @@
+{include file="$HOME/header.html"}
+
+{include file="$HOME/footer.html"}
\ No newline at end of file
diff --git a/ewomail-admin/upload/install.sql b/ewomail-admin/upload/install.sql
new file mode 100644
index 0000000..51a7020
--- /dev/null
+++ b/ewomail-admin/upload/install.sql
@@ -0,0 +1,239 @@
+/*
+Navicat MySQL Data Transfer
+
+Source Server : localhost
+Source Server Version : 50540
+Source Host : 127.0.0.1:3306
+Source Database : ewomail
+
+Target Server Type : MYSQL
+Target Server Version : 50540
+File Encoding : 65001
+
+Date: 2017-03-03 16:04:47
+*/
+
+SET FOREIGN_KEY_CHECKS=0;
+
+-- ----------------------------
+-- Table structure for i_admin
+-- ----------------------------
+DROP TABLE IF EXISTS `i_admin`;
+CREATE TABLE `i_admin` (
+ `aid` int(11) NOT NULL AUTO_INCREMENT,
+ `username` varchar(30) NOT NULL COMMENT '账号',
+ `password` varchar(32) NOT NULL COMMENT '密码',
+ `name` varchar(30) NOT NULL COMMENT '真实名称',
+ `super` int(1) NOT NULL DEFAULT '0' COMMENT '是否为超级管理员',
+ `gid` int(11) NOT NULL DEFAULT '0' COMMENT '管理组id',
+ `active` int(1) NOT NULL DEFAULT '1' COMMENT '是否正常:1是,0否',
+ `is_webmail` int(1) NOT NULL DEFAULT '0' COMMENT '是否有web控制面板权限:0否:1是',
+ `ctime` datetime NOT NULL COMMENT '创建时间',
+ PRIMARY KEY (`aid`),
+ UNIQUE KEY `username` (`username`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='管理员账号';
+
+-- ----------------------------
+-- Records of i_admin
+-- ----------------------------
+INSERT INTO `i_admin` VALUES ('1', 'admin', '3bb3733de472b226208307ec1e689347', 'admin', '1', '0', '1', '1', '2016-03-25 21:45:46');
+
+-- ----------------------------
+-- Table structure for i_admin_group
+-- ----------------------------
+DROP TABLE IF EXISTS `i_admin_group`;
+CREATE TABLE `i_admin_group` (
+ `gid` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(30) NOT NULL COMMENT '标题',
+ `auth` text,
+ PRIMARY KEY (`gid`)
+) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COMMENT='管理组';
+
+-- ----------------------------
+-- Records of i_admin_group
+-- ----------------------------
+INSERT INTO `i_admin_group` VALUES ('8', '客服', 'a:7:{i:101;a:3:{s:4:\"view\";s:1:\"1\";s:4:\"edit\";s:1:\"1\";s:7:\"menu_id\";s:3:\"101\";}i:103;a:2:{s:4:\"view\";s:1:\"1\";s:7:\"menu_id\";s:3:\"103\";}i:105;a:2:{s:4:\"view\";s:1:\"1\";s:7:\"menu_id\";s:3:\"105\";}i:201;a:2:{s:4:\"view\";s:1:\"1\";s:7:\"menu_id\";s:3:\"201\";}i:203;a:2:{s:4:\"view\";s:1:\"1\";s:7:\"menu_id\";s:3:\"203\";}i:205;a:2:{s:4:\"view\";s:1:\"1\";s:7:\"menu_id\";s:3:\"205\";}i:206;a:2:{s:4:\"view\";s:1:\"1\";s:7:\"menu_id\";s:3:\"206\";}}');
+
+-- ----------------------------
+-- Table structure for i_admin_log
+-- ----------------------------
+DROP TABLE IF EXISTS `i_admin_log`;
+CREATE TABLE `i_admin_log` (
+ `log_id` int(11) NOT NULL AUTO_INCREMENT,
+ `username` varchar(255) NOT NULL COMMENT '管理员账号',
+ `ip` varchar(255) NOT NULL,
+ `explain` text COMMENT '说明',
+ `ctime` datetime NOT NULL COMMENT '创建时间',
+ PRIMARY KEY (`log_id`),
+ KEY `username` (`username`)
+) ENGINE=MyISAM AUTO_INCREMENT=207 DEFAULT CHARSET=utf8 COMMENT='管理员操作日志';
+
+-- ----------------------------
+-- Records of i_admin_log
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for i_admin_menu
+-- ----------------------------
+DROP TABLE IF EXISTS `i_admin_menu`;
+CREATE TABLE `i_admin_menu` (
+ `menu_id` int(11) NOT NULL,
+ `mark` varchar(30) NOT NULL DEFAULT '' COMMENT '备注',
+ `lang` varchar(255) NOT NULL,
+ `url` varchar(255) NOT NULL DEFAULT '',
+ `top_id` int(11) NOT NULL DEFAULT '0' COMMENT '上级id',
+ `edit` int(1) NOT NULL DEFAULT '0' COMMENT '添加和编辑权限',
+ `del` int(1) NOT NULL DEFAULT '0' COMMENT '删除权限',
+ `edit_id` int(11) NOT NULL DEFAULT '0' COMMENT '关联编辑id',
+ `sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序',
+ PRIMARY KEY (`menu_id`),
+ KEY `top_id` (`top_id`) USING BTREE,
+ KEY `edit_id` (`edit_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='后台菜单栏目';
+
+-- ----------------------------
+-- Records of i_admin_menu
+-- ----------------------------
+INSERT INTO `i_admin_menu` VALUES ('100', '邮件管理', '90100', '', '0', '0', '0', '0', '0');
+INSERT INTO `i_admin_menu` VALUES ('101', '邮件列表', '90101', '/Users', '100', '1', '1', '0', '0');
+INSERT INTO `i_admin_menu` VALUES ('102', '邮件添加', '90102', '/Users/edit', '100', '0', '0', '101', '0');
+INSERT INTO `i_admin_menu` VALUES ('103', '邮件域名', '90103', '/Domain', '100', '1', '1', '0', '0');
+INSERT INTO `i_admin_menu` VALUES ('105', '邮件系统设置', '90105', '/Users/config', '100', '1', '0', '0', '0');
+INSERT INTO `i_admin_menu` VALUES ('200', '系统管理', '90200', '', '0', '0', '0', '0', '0');
+INSERT INTO `i_admin_menu` VALUES ('201', '管理员列表', '90201', '/Admin', '200', '1', '1', '0', '0');
+INSERT INTO `i_admin_menu` VALUES ('202', '管理员添加', '90202', '/Admin/edit', '200', '0', '0', '201', '0');
+INSERT INTO `i_admin_menu` VALUES ('203', '角色列表', '90203', '/Group', '200', '1', '1', '0', '0');
+INSERT INTO `i_admin_menu` VALUES ('204', '角色添加', '90204', '/Group/edit', '200', '0', '0', '203', '0');
+INSERT INTO `i_admin_menu` VALUES ('205', '系统设置', '90205', '/System/config', '200', '1', '0', '0', '0');
+INSERT INTO `i_admin_menu` VALUES ('206', '操作日志', '90206', '/Log', '200', '0', '1', '0', '0');
+
+-- ----------------------------
+-- Table structure for i_aliases
+-- ----------------------------
+DROP TABLE IF EXISTS `i_aliases`;
+CREATE TABLE `i_aliases` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `source` varchar(100) NOT NULL,
+ `destination` varchar(100) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `source` (`source`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='邮箱别名转发';
+
+-- ----------------------------
+-- Records of i_aliases
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for i_bcc_user
+-- ----------------------------
+DROP TABLE IF EXISTS `i_bcc_user`;
+CREATE TABLE `i_bcc_user` (
+ `source` varchar(255) NOT NULL COMMENT '接收邮件的email',
+ `to_email` varchar(255) NOT NULL COMMENT '目标用户的邮件',
+ KEY `source` (`source`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='邮件转发';
+
+-- ----------------------------
+-- Records of i_bcc_user
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for i_domains
+-- ----------------------------
+DROP TABLE IF EXISTS `i_domains`;
+CREATE TABLE `i_domains` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` varchar(255) NOT NULL,
+ `active` int(1) NOT NULL DEFAULT '0',
+ `s_num` int(11) NOT NULL DEFAULT '0' COMMENT '邮件每天的发送量,0不受限制',
+ `c_num` int(11) NOT NULL DEFAULT '0' COMMENT '邮件每天的接收量,0不受限制',
+ `c_ip` int(11) NOT NULL DEFAULT '0' COMMENT '限制IP每天发送到邮件的数量,0不受限制',
+ `g` int(11) NOT NULL DEFAULT '0' COMMENT '容量限制,单位G',
+ `g_boundary` int(11) NOT NULL DEFAULT '0' COMMENT '容量达到边界发送通知(百分比)',
+ `ctime` datetime NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `name` (`name`) USING BTREE,
+ KEY `active` (`active`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Records of i_domains
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for i_mail_config
+-- ----------------------------
+DROP TABLE IF EXISTS `i_mail_config`;
+CREATE TABLE `i_mail_config` (
+ `name` varchar(255) NOT NULL,
+ `value` varchar(255) DEFAULT NULL,
+ UNIQUE KEY `key` (`name`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Records of i_mail_config
+-- ----------------------------
+INSERT INTO `i_mail_config` VALUES ('imap', 'imap.ewomail.cn');
+INSERT INTO `i_mail_config` VALUES ('mydomain', 'ewomail.cn');
+INSERT INTO `i_mail_config` VALUES ('myhostname', 'mail.ewomail.cn');
+INSERT INTO `i_mail_config` VALUES ('smtp', 'smtp.ewomail.cn');
+
+-- ----------------------------
+-- Table structure for i_quota
+-- ----------------------------
+DROP TABLE IF EXISTS `i_quota`;
+CREATE TABLE `i_quota` (
+ `email` varchar(100) NOT NULL,
+ `bytes` bigint(20) NOT NULL DEFAULT '0',
+ `messages` int(11) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`email`),
+ UNIQUE KEY `email` (`email`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Records of i_quota
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for i_system_config
+-- ----------------------------
+DROP TABLE IF EXISTS `i_system_config`;
+CREATE TABLE `i_system_config` (
+ `name` varchar(255) NOT NULL,
+ `value` varchar(255) DEFAULT NULL,
+ UNIQUE KEY `name` (`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='系统配置表';
+
+-- ----------------------------
+-- Records of i_system_config
+-- ----------------------------
+INSERT INTO `i_system_config` VALUES ('copyright', 'Copyright © 2016-2017 | ewomail.com 版权所有');
+INSERT INTO `i_system_config` VALUES ('icp', 'ICP证:粤ICP备**********号');
+INSERT INTO `i_system_config` VALUES ('lang', 'zh-cn');
+INSERT INTO `i_system_config` VALUES ('title', 'ewomail.com');
+
+-- ----------------------------
+-- Table structure for i_users
+-- ----------------------------
+DROP TABLE IF EXISTS `i_users`;
+CREATE TABLE `i_users` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `domain_id` int(11) NOT NULL,
+ `password` varchar(106) NOT NULL,
+ `email` varchar(100) NOT NULL,
+ `maildir` varchar(255) NOT NULL,
+ `uname` varchar(255) DEFAULT NULL COMMENT '姓名',
+ `tel` varchar(255) DEFAULT NULL COMMENT '联系电话',
+ `active` int(1) NOT NULL DEFAULT '1' COMMENT '是否正常:1是,0否',
+ `limits` int(1) NOT NULL DEFAULT '1' COMMENT '收发限制',
+ `limitg` int(1) NOT NULL DEFAULT '1' COMMENT '容量限制',
+ `ctime` datetime NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `email` (`email`) USING BTREE,
+ KEY `domain_id` (`domain_id`) USING BTREE,
+ KEY `active` (`active`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='邮箱用户表';
+
+-- ----------------------------
+-- Records of i_users
+-- ----------------------------
diff --git a/install/config/clamav/clamd.amavisd b/install/config/clamav/clamd.amavisd
new file mode 100644
index 0000000..27dcc9d
--- /dev/null
+++ b/install/config/clamav/clamd.amavisd
@@ -0,0 +1,5 @@
+#CLAMD_CONFIGFILE=/etc/clamd.d/
.conf
+#CLAMD_SOCKET=/var/run/clamd./clamd.sock
+#CLAMD_OPTIONS=
+CLAMD_CONFIGFILE=/etc/clamd.d/amavisd.conf
+CLAMD_SOCKET=/var/run/clamd.amavisd/clamd.sock
\ No newline at end of file
diff --git a/install/config/clamav/clamd.amavisd.conf b/install/config/clamav/clamd.amavisd.conf
new file mode 100644
index 0000000..766fa69
--- /dev/null
+++ b/install/config/clamav/clamd.amavisd.conf
@@ -0,0 +1 @@
+d /var/run/clamd.amavisd 0755 amavis amavis -
\ No newline at end of file
diff --git a/install/config/clamav/clamd@.service b/install/config/clamav/clamd@.service
new file mode 100644
index 0000000..2150199
--- /dev/null
+++ b/install/config/clamav/clamd@.service
@@ -0,0 +1,12 @@
+[Unit]
+Description = clamd scanner (%i) daemon
+After = syslog.target nss-lookup.target network.target
+
+[Service]
+Type = simple
+ExecStart = /usr/sbin/clamd -c /etc/clamd.d/%i.conf --foreground=yes
+Restart = on-failure
+PrivateTmp = true
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
diff --git a/install/config/dovecot/README b/install/config/dovecot/README
new file mode 100644
index 0000000..3e7027a
--- /dev/null
+++ b/install/config/dovecot/README
@@ -0,0 +1,2 @@
+Configuration files go to this directory. See example configuration files in
+/usr/local/dovecot/share/doc/dovecot/example-config/
diff --git a/install/config/dovecot/conf.d/10-auth.conf b/install/config/dovecot/conf.d/10-auth.conf
new file mode 100644
index 0000000..70686d0
--- /dev/null
+++ b/install/config/dovecot/conf.d/10-auth.conf
@@ -0,0 +1,128 @@
+##
+## Authentication processes
+##
+
+# Disable LOGIN command and all other plaintext authentications unless
+# SSL/TLS is used (LOGINDISABLED capability). Note that if the remote IP
+# matches the local IP (ie. you're connecting from the same computer), the
+# connection is considered secure and plaintext authentication is allowed.
+# See also ssl=required setting.
+disable_plaintext_auth = no
+
+# Authentication cache size (e.g. 10M). 0 means it's disabled. Note that
+# bsdauth, PAM and vpopmail require cache_key to be set for caching to be used.
+#auth_cache_size = 0
+# Time to live for cached data. After TTL expires the cached record is no
+# longer used, *except* if the main database lookup returns internal failure.
+# We also try to handle password changes automatically: If user's previous
+# authentication was successful, but this one wasn't, the cache isn't used.
+# For now this works only with plaintext authentication.
+#auth_cache_ttl = 1 hour
+# TTL for negative hits (user not found, password mismatch).
+# 0 disables caching them completely.
+#auth_cache_negative_ttl = 1 hour
+
+# Space separated list of realms for SASL authentication mechanisms that need
+# them. You can leave it empty if you don't want to support multiple realms.
+# Many clients simply use the first one listed here, so keep the default realm
+# first.
+#auth_realms =
+
+# Default realm/domain to use if none was specified. This is used for both
+# SASL realms and appending @domain to username in plaintext logins.
+#auth_default_realm =
+
+# List of allowed characters in username. If the user-given username contains
+# a character not listed in here, the login automatically fails. This is just
+# an extra check to make sure user can't exploit any potential quote escaping
+# vulnerabilities with SQL/LDAP databases. If you want to allow all characters,
+# set this value to empty.
+#auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@
+
+# Username character translations before it's looked up from databases. The
+# value contains series of from -> to characters. For example "#@/@" means
+# that '#' and '/' characters are translated to '@'.
+#auth_username_translation =
+
+# Username formatting before it's looked up from databases. You can use
+# the standard variables here, eg. %Lu would lowercase the username, %n would
+# drop away the domain if it was given, or "%n-AT-%d" would change the '@' into
+# "-AT-". This translation is done after auth_username_translation changes.
+#auth_username_format = %Lu
+
+# If you want to allow master users to log in by specifying the master
+# username within the normal username string (ie. not using SASL mechanism's
+# support for it), you can specify the separator character here. The format
+# is then . UW-IMAP uses "*" as the
+# separator, so that could be a good choice.
+#auth_master_user_separator =
+
+# Username to use for users logging in with ANONYMOUS SASL mechanism
+#auth_anonymous_username = anonymous
+
+# Maximum number of dovecot-auth worker processes. They're used to execute
+# blocking passdb and userdb queries (eg. MySQL and PAM). They're
+# automatically created and destroyed as needed.
+#auth_worker_max_count = 30
+
+# Host name to use in GSSAPI principal names. The default is to use the
+# name returned by gethostname(). Use "$ALL" (with quotes) to allow all keytab
+# entries.
+#auth_gssapi_hostname =
+
+# Kerberos keytab to use for the GSSAPI mechanism. Will use the system
+# default (usually /etc/krb5.keytab) if not specified. You may need to change
+# the auth service to run as root to be able to read this file.
+#auth_krb5_keytab =
+
+# Do NTLM and GSS-SPNEGO authentication using Samba's winbind daemon and
+# ntlm_auth helper.
+#auth_use_winbind = no
+
+# Path for Samba's ntlm_auth helper binary.
+#auth_winbind_helper_path = /usr/bin/ntlm_auth
+
+# Time to delay before replying to failed authentications.
+#auth_failure_delay = 2 secs
+
+# Require a valid SSL client certificate or the authentication fails.
+#auth_ssl_require_client_cert = no
+
+# Take the username from client's SSL certificate, using
+# X509_NAME_get_text_by_NID() which returns the subject's DN's
+# CommonName.
+#auth_ssl_username_from_cert = no
+
+# Space separated list of wanted authentication mechanisms:
+# plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp skey
+# gss-spnego
+# NOTE: See also disable_plaintext_auth setting.
+auth_mechanisms = plain login
+
+##
+## Password and user databases
+##
+
+#
+# Password database is used to verify user's password (and nothing more).
+# You can have multiple passdbs and userdbs. This is useful if you want to
+# allow both system users (/etc/passwd) and virtual users to login without
+# duplicating the system users into virtual database.
+#
+#
+#
+# User database specifies where mails are located and what user/group IDs
+# own them. For single-UID configuration use "static" userdb.
+#
+#
+
+#!include auth-deny.conf.ext
+#!include auth-master.conf.ext
+
+#!include auth-system.conf.ext
+!include auth-sql.conf.ext
+#!include auth-ldap.conf.ext
+#!include auth-passwdfile.conf.ext
+#!include auth-checkpassword.conf.ext
+#!include auth-vpopmail.conf.ext
+#!include auth-static.conf.ext
diff --git a/install/config/dovecot/conf.d/10-director.conf b/install/config/dovecot/conf.d/10-director.conf
new file mode 100644
index 0000000..31e97e9
--- /dev/null
+++ b/install/config/dovecot/conf.d/10-director.conf
@@ -0,0 +1,61 @@
+##
+## Director-specific settings.
+##
+
+# Director can be used by Dovecot proxy to keep a temporary user -> mail server
+# mapping. As long as user has simultaneous connections, the user is always
+# redirected to the same server. Each proxy server is running its own director
+# process, and the directors are communicating the state to each others.
+# Directors are mainly useful with NFS-like setups.
+
+# List of IPs or hostnames to all director servers, including ourself.
+# Ports can be specified as ip:port. The default port is the same as
+# what director service's inet_listener is using.
+#director_servers =
+
+# List of IPs or hostnames to all backend mail servers. Ranges are allowed
+# too, like 10.0.0.10-10.0.0.30.
+#director_mail_servers =
+
+# How long to redirect users to a specific server after it no longer has
+# any connections.
+#director_user_expire = 15 min
+
+# TCP/IP port that accepts doveadm connections (instead of director connections)
+# If you enable this, you'll also need to add inet_listener for the port.
+#director_doveadm_port = 0
+
+# How the username is translated before being hashed. Useful values include
+# %Ln if user can log in with or without @domain, %Ld if mailboxes are shared
+# within domain.
+#director_username_hash = %Lu
+
+# To enable director service, uncomment the modes and assign a port.
+service director {
+ unix_listener login/director {
+ #mode = 0666
+ }
+ fifo_listener login/proxy-notify {
+ #mode = 0666
+ }
+ unix_listener director-userdb {
+ #mode = 0600
+ }
+ inet_listener {
+ #port =
+ }
+}
+
+# Enable director for the wanted login services by telling them to
+# connect to director socket instead of the default login socket:
+service imap-login {
+ #executable = imap-login director
+}
+service pop3-login {
+ #executable = pop3-login director
+}
+
+# Enable director for LMTP proxying:
+protocol lmtp {
+ #auth_socket_path = director-userdb
+}
diff --git a/install/config/dovecot/conf.d/10-logging.conf b/install/config/dovecot/conf.d/10-logging.conf
new file mode 100644
index 0000000..14798f1
--- /dev/null
+++ b/install/config/dovecot/conf.d/10-logging.conf
@@ -0,0 +1,85 @@
+##
+## Log destination.
+##
+
+# Log file to use for error messages. "syslog" logs to syslog,
+# /dev/stderr logs to stderr.
+#log_path = syslog
+
+# Log file to use for informational messages. Defaults to log_path.
+#info_log_path =
+# Log file to use for debug messages. Defaults to info_log_path.
+#debug_log_path =
+
+# Syslog facility to use if you're logging to syslog. Usually if you don't
+# want to use "mail", you'll use local0..local7. Also other standard
+# facilities are supported.
+#syslog_facility = mail
+
+##
+## Logging verbosity and debugging.
+##
+
+# Log unsuccessful authentication attempts and the reasons why they failed.
+#auth_verbose = no
+
+# In case of password mismatches, log the attempted password. Valid values are
+# no, plain and sha1. sha1 can be useful for detecting brute force password
+# attempts vs. user simply trying the same password over and over again.
+# You can also truncate the value to n chars by appending ":n" (e.g. sha1:6).
+#auth_verbose_passwords = no
+
+# Even more verbose logging for debugging purposes. Shows for example SQL
+# queries.
+#auth_debug = no
+
+# In case of password mismatches, log the passwords and used scheme so the
+# problem can be debugged. Enabling this also enables auth_debug.
+#auth_debug_passwords = no
+
+# Enable mail process debugging. This can help you figure out why Dovecot
+# isn't finding your mails.
+#mail_debug = no
+
+# Show protocol level SSL errors.
+#verbose_ssl = no
+
+# mail_log plugin provides more event logging for mail processes.
+plugin {
+ # Events to log. Also available: flag_change append
+ #mail_log_events = delete undelete expunge copy mailbox_delete mailbox_rename
+ # Available fields: uid, box, msgid, from, subject, size, vsize, flags
+ # size and vsize are available only for expunge and copy events.
+ #mail_log_fields = uid box msgid size
+}
+
+##
+## Log formatting.
+##
+
+# Prefix for each line written to log file. % codes are in strftime(3)
+# format.
+#log_timestamp = "%b %d %H:%M:%S "
+
+# Space-separated list of elements we want to log. The elements which have
+# a non-empty variable value are joined together to form a comma-separated
+# string.
+#login_log_format_elements = user=<%u> method=%m rip=%r lip=%l mpid=%e %c
+
+# Login log format. %s contains login_log_format_elements string, %$ contains
+# the data we want to log.
+#login_log_format = %$: %s
+
+# Log prefix for mail processes. See doc/wiki/Variables.txt for list of
+# possible variables you can use.
+#mail_log_prefix = "%s(%u): "
+
+# Format to use for logging mail deliveries. See doc/wiki/Variables.txt for
+# list of all variables you can use. Some of the common ones include:
+# %$ - Delivery status message (e.g. "saved to INBOX")
+# %m - Message-ID
+# %s - Subject
+# %f - From address
+# %p - Physical size
+# %w - Virtual size
+#deliver_log_format = msgid=%m: %$
diff --git a/install/config/dovecot/conf.d/10-mail.conf b/install/config/dovecot/conf.d/10-mail.conf
new file mode 100644
index 0000000..8bba09b
--- /dev/null
+++ b/install/config/dovecot/conf.d/10-mail.conf
@@ -0,0 +1,379 @@
+##
+## Mailbox locations and namespaces
+##
+
+# Location for users' mailboxes. The default is empty, which means that Dovecot
+# tries to find the mailboxes automatically. This won't work if the user
+# doesn't yet have any mail, so you should explicitly tell Dovecot the full
+# location.
+#
+# If you're using mbox, giving a path to the INBOX file (eg. /var/mail/%u)
+# isn't enough. You'll also need to tell Dovecot where the other mailboxes are
+# kept. This is called the "root mail directory", and it must be the first
+# path given in the mail_location setting.
+#
+# There are a few special variables you can use, eg.:
+#
+# %u - username
+# %n - user part in user@domain, same as %u if there's no domain
+# %d - domain part in user@domain, empty if there's no domain
+# %h - home directory
+#
+# See doc/wiki/Variables.txt for full list. Some examples:
+#
+# mail_location = maildir:~/Maildir
+# mail_location = mbox:~/mail:INBOX=/var/mail/%u
+# mail_location = mbox:/var/mail/%d/%1n/%n:INDEX=/var/indexes/%d/%1n/%n
+#
+#
+#
+mail_location = maildir:/ewomail/mail/vhosts/%d/%n
+
+# If you need to set multiple mailbox locations or want to change default
+# namespace settings, you can do it by defining namespace sections.
+#
+# You can have private, shared and public namespaces. Private namespaces
+# are for user's personal mails. Shared namespaces are for accessing other
+# users' mailboxes that have been shared. Public namespaces are for shared
+# mailboxes that are managed by sysadmin. If you create any shared or public
+# namespaces you'll typically want to enable ACL plugin also, otherwise all
+# users can access all the shared mailboxes, assuming they have permissions
+# on filesystem level to do so.
+namespace inbox {
+ # Namespace type: private, shared or public
+ #type = private
+
+ # Hierarchy separator to use. You should use the same separator for all
+ # namespaces or some clients get confused. '/' is usually a good one.
+ # The default however depends on the underlying mail storage format.
+ #separator =
+
+ # Prefix required to access this namespace. This needs to be different for
+ # all namespaces. For example "Public/".
+ #prefix =
+
+ # Physical location of the mailbox. This is in same format as
+ # mail_location, which is also the default for it.
+ #location =
+
+ # There can be only one INBOX, and this setting defines which namespace
+ # has it.
+ inbox = yes
+
+ # If namespace is hidden, it's not advertised to clients via NAMESPACE
+ # extension. You'll most likely also want to set list=no. This is mostly
+ # useful when converting from another server with different namespaces which
+ # you want to deprecate but still keep working. For example you can create
+ # hidden namespaces with prefixes "~/mail/", "~%u/mail/" and "mail/".
+ #hidden = no
+
+ # Show the mailboxes under this namespace with LIST command. This makes the
+ # namespace visible for clients that don't support NAMESPACE extension.
+ # "children" value lists child mailboxes, but hides the namespace prefix.
+ #list = yes
+
+ # Namespace handles its own subscriptions. If set to "no", the parent
+ # namespace handles them (empty prefix should always have this as "yes")
+ #subscriptions = yes
+
+ # See 15-mailboxes.conf for definitions of special mailboxes.
+}
+
+# Example shared namespace configuration
+#namespace {
+ #type = shared
+ #separator = /
+
+ # Mailboxes are visible under "shared/user@domain/"
+ # %%n, %%d and %%u are expanded to the destination user.
+ #prefix = shared/%%u/
+
+ # Mail location for other users' mailboxes. Note that %variables and ~/
+ # expands to the logged in user's data. %%n, %%d, %%u and %%h expand to the
+ # destination user's data.
+ #location = maildir:%%h/Maildir:INDEX=~/Maildir/shared/%%u
+
+ # Use the default namespace for saving subscriptions.
+ #subscriptions = no
+
+ # List the shared/ namespace only if there are visible shared mailboxes.
+ #list = children
+#}
+# Should shared INBOX be visible as "shared/user" or "shared/user/INBOX"?
+#mail_shared_explicit_inbox = no
+
+# System user and group used to access mails. If you use multiple, userdb
+# can override these by returning uid or gid fields. You can use either numbers
+# or names.
+#mail_uid =
+#mail_gid =
+
+# Group to enable temporarily for privileged operations. Currently this is
+# used only with INBOX when either its initial creation or dotlocking fails.
+# Typically this is set to "mail" to give access to /var/mail.
+mail_privileged_group = mail
+
+# Grant access to these supplementary groups for mail processes. Typically
+# these are used to set up access to shared mailboxes. Note that it may be
+# dangerous to set these if users can create symlinks (e.g. if "mail" group is
+# set here, ln -s /var/mail ~/mail/var could allow a user to delete others'
+# mailboxes, or ln -s /secret/shared/box ~/mail/mybox would allow reading it).
+#mail_access_groups =
+
+# Allow full filesystem access to clients. There's no access checks other than
+# what the operating system does for the active UID/GID. It works with both
+# maildir and mboxes, allowing you to prefix mailboxes names with eg. /path/
+# or ~user/.
+#mail_full_filesystem_access = no
+
+# Dictionary for key=value mailbox attributes. This is used for example by
+# URLAUTH and METADATA extensions.
+#mail_attribute_dict =
+
+# A comment or note that is associated with the server. This value is
+# accessible for authenticated users through the IMAP METADATA server
+# entry "/shared/comment".
+#mail_server_comment = ""
+
+# Indicates a method for contacting the server administrator. According to
+# RFC 5464, this value MUST be a URI (e.g., a mailto: or tel: URL), but that
+# is currently not enforced. Use for example mailto:admin@example.com. This
+# value is accessible for authenticated users through the IMAP METADATA server
+# entry "/shared/admin".
+#mail_server_admin =
+
+##
+## Mail processes
+##
+
+# Don't use mmap() at all. This is required if you store indexes to shared
+# filesystems (NFS or clustered filesystem).
+#mmap_disable = no
+
+# Rely on O_EXCL to work when creating dotlock files. NFS supports O_EXCL
+# since version 3, so this should be safe to use nowadays by default.
+#dotlock_use_excl = yes
+
+# When to use fsync() or fdatasync() calls:
+# optimized (default): Whenever necessary to avoid losing important data
+# always: Useful with e.g. NFS when write()s are delayed
+# never: Never use it (best performance, but crashes can lose data)
+#mail_fsync = optimized
+
+# Locking method for index files. Alternatives are fcntl, flock and dotlock.
+# Dotlocking uses some tricks which may create more disk I/O than other locking
+# methods. NFS users: flock doesn't work, remember to change mmap_disable.
+#lock_method = fcntl
+
+# Directory in which LDA/LMTP temporarily stores incoming mails >128 kB.
+#mail_temp_dir = /tmp
+
+# Valid UID range for users, defaults to 500 and above. This is mostly
+# to make sure that users can't log in as daemons or other system users.
+# Note that denying root logins is hardcoded to dovecot binary and can't
+# be done even if first_valid_uid is set to 0.
+#first_valid_uid = 500
+#last_valid_uid = 0
+
+# Valid GID range for users, defaults to non-root/wheel. Users having
+# non-valid GID as primary group ID aren't allowed to log in. If user
+# belongs to supplementary groups with non-valid GIDs, those groups are
+# not set.
+#first_valid_gid = 1
+#last_valid_gid = 0
+
+# Maximum allowed length for mail keyword name. It's only forced when trying
+# to create new keywords.
+#mail_max_keyword_length = 50
+
+# ':' separated list of directories under which chrooting is allowed for mail
+# processes (ie. /var/mail will allow chrooting to /var/mail/foo/bar too).
+# This setting doesn't affect login_chroot, mail_chroot or auth chroot
+# settings. If this setting is empty, "/./" in home dirs are ignored.
+# WARNING: Never add directories here which local users can modify, that
+# may lead to root exploit. Usually this should be done only if you don't
+# allow shell access for users.
+#valid_chroot_dirs =
+
+# Default chroot directory for mail processes. This can be overridden for
+# specific users in user database by giving /./ in user's home directory
+# (eg. /home/./user chroots into /home). Note that usually there is no real
+# need to do chrooting, Dovecot doesn't allow users to access files outside
+# their mail directory anyway. If your home directories are prefixed with
+# the chroot directory, append "/." to mail_chroot.
+#mail_chroot =
+
+# UNIX socket path to master authentication server to find users.
+# This is used by imap (for shared users) and lda.
+#auth_socket_path = /var/run/dovecot/auth-userdb
+
+# Directory where to look up mail plugins.
+#mail_plugin_dir = /usr/lib/dovecot
+
+# Space separated list of plugins to load for all services. Plugins specific to
+# IMAP, LDA, etc. are added to this list in their own .conf files.
+#mail_plugins =
+
+##
+## Mailbox handling optimizations
+##
+
+# Mailbox list indexes can be used to optimize IMAP STATUS commands. They are
+# also required for IMAP NOTIFY extension to be enabled.
+#mailbox_list_index = no
+
+# The minimum number of mails in a mailbox before updates are done to cache
+# file. This allows optimizing Dovecot's behavior to do less disk writes at
+# the cost of more disk reads.
+#mail_cache_min_mail_count = 0
+
+# When IDLE command is running, mailbox is checked once in a while to see if
+# there are any new mails or other changes. This setting defines the minimum
+# time to wait between those checks. Dovecot can also use inotify and
+# kqueue to find out immediately when changes occur.
+#mailbox_idle_check_interval = 30 secs
+
+# Save mails with CR+LF instead of plain LF. This makes sending those mails
+# take less CPU, especially with sendfile() syscall with Linux and FreeBSD.
+# But it also creates a bit more disk I/O which may just make it slower.
+# Also note that if other software reads the mboxes/maildirs, they may handle
+# the extra CRs wrong and cause problems.
+#mail_save_crlf = no
+
+# Max number of mails to keep open and prefetch to memory. This only works with
+# some mailbox formats and/or operating systems.
+#mail_prefetch_count = 0
+
+# How often to scan for stale temporary files and delete them (0 = never).
+# These should exist only after Dovecot dies in the middle of saving mails.
+#mail_temp_scan_interval = 1w
+
+##
+## Maildir-specific settings
+##
+
+# By default LIST command returns all entries in maildir beginning with a dot.
+# Enabling this option makes Dovecot return only entries which are directories.
+# This is done by stat()ing each entry, so it causes more disk I/O.
+# (For systems setting struct dirent->d_type, this check is free and it's
+# done always regardless of this setting)
+#maildir_stat_dirs = no
+
+# When copying a message, do it with hard links whenever possible. This makes
+# the performance much better, and it's unlikely to have any side effects.
+#maildir_copy_with_hardlinks = yes
+
+# Assume Dovecot is the only MUA accessing Maildir: Scan cur/ directory only
+# when its mtime changes unexpectedly or when we can't find the mail otherwise.
+#maildir_very_dirty_syncs = no
+
+# If enabled, Dovecot doesn't use the S= in the Maildir filenames for
+# getting the mail's physical size, except when recalculating Maildir++ quota.
+# This can be useful in systems where a lot of the Maildir filenames have a
+# broken size. The performance hit for enabling this is very small.
+#maildir_broken_filename_sizes = no
+
+# Always move mails from new/ directory to cur/, even when the \Recent flags
+# aren't being reset.
+#maildir_empty_new = no
+
+##
+## mbox-specific settings
+##
+
+# Which locking methods to use for locking mbox. There are four available:
+# dotlock: Create .lock file. This is the oldest and most NFS-safe
+# solution. If you want to use /var/mail/ like directory, the users
+# will need write access to that directory.
+# dotlock_try: Same as dotlock, but if it fails because of permissions or
+# because there isn't enough disk space, just skip it.
+# fcntl : Use this if possible. Works with NFS too if lockd is used.
+# flock : May not exist in all systems. Doesn't work with NFS.
+# lockf : May not exist in all systems. Doesn't work with NFS.
+#
+# You can use multiple locking methods; if you do the order they're declared
+# in is important to avoid deadlocks if other MTAs/MUAs are using multiple
+# locking methods as well. Some operating systems don't allow using some of
+# them simultaneously.
+#mbox_read_locks = fcntl
+#mbox_write_locks = dotlock fcntl
+
+# Maximum time to wait for lock (all of them) before aborting.
+#mbox_lock_timeout = 5 mins
+
+# If dotlock exists but the mailbox isn't modified in any way, override the
+# lock file after this much time.
+#mbox_dotlock_change_timeout = 2 mins
+
+# When mbox changes unexpectedly we have to fully read it to find out what
+# changed. If the mbox is large this can take a long time. Since the change
+# is usually just a newly appended mail, it'd be faster to simply read the
+# new mails. If this setting is enabled, Dovecot does this but still safely
+# fallbacks to re-reading the whole mbox file whenever something in mbox isn't
+# how it's expected to be. The only real downside to this setting is that if
+# some other MUA changes message flags, Dovecot doesn't notice it immediately.
+# Note that a full sync is done with SELECT, EXAMINE, EXPUNGE and CHECK
+# commands.
+#mbox_dirty_syncs = yes
+
+# Like mbox_dirty_syncs, but don't do full syncs even with SELECT, EXAMINE,
+# EXPUNGE or CHECK commands. If this is set, mbox_dirty_syncs is ignored.
+#mbox_very_dirty_syncs = no
+
+# Delay writing mbox headers until doing a full write sync (EXPUNGE and CHECK
+# commands and when closing the mailbox). This is especially useful for POP3
+# where clients often delete all mails. The downside is that our changes
+# aren't immediately visible to other MUAs.
+#mbox_lazy_writes = yes
+
+# If mbox size is smaller than this (e.g. 100k), don't write index files.
+# If an index file already exists it's still read, just not updated.
+#mbox_min_index_size = 0
+
+# Mail header selection algorithm to use for MD5 POP3 UIDLs when
+# pop3_uidl_format=%m. For backwards compatibility we use apop3d inspired
+# algorithm, but it fails if the first Received: header isn't unique in all
+# mails. An alternative algorithm is "all" that selects all headers.
+#mbox_md5 = apop3d
+
+##
+## mdbox-specific settings
+##
+
+# Maximum dbox file size until it's rotated.
+#mdbox_rotate_size = 2M
+
+# Maximum dbox file age until it's rotated. Typically in days. Day begins
+# from midnight, so 1d = today, 2d = yesterday, etc. 0 = check disabled.
+#mdbox_rotate_interval = 0
+
+# When creating new mdbox files, immediately preallocate their size to
+# mdbox_rotate_size. This setting currently works only in Linux with some
+# filesystems (ext4, xfs).
+#mdbox_preallocate_space = no
+
+##
+## Mail attachments
+##
+
+# sdbox and mdbox support saving mail attachments to external files, which
+# also allows single instance storage for them. Other backends don't support
+# this for now.
+
+# Directory root where to store mail attachments. Disabled, if empty.
+#mail_attachment_dir =
+
+# Attachments smaller than this aren't saved externally. It's also possible to
+# write a plugin to disable saving specific attachments externally.
+#mail_attachment_min_size = 128k
+
+# Filesystem backend to use for saving attachments:
+# posix : No SiS done by Dovecot (but this might help FS's own deduplication)
+# sis posix : SiS with immediate byte-by-byte comparison during saving
+# sis-queue posix : SiS with delayed comparison and deduplication
+#mail_attachment_fs = sis posix
+
+# Hash format to use in attachment filenames. You can add any text and
+# variables: %{md4}, %{md5}, %{sha1}, %{sha256}, %{sha512}, %{size}.
+# Variables can be truncated, e.g. %{sha256:80} returns only first 80 bits
+#mail_attachment_hash = %{sha1}
diff --git a/install/config/dovecot/conf.d/10-master.conf b/install/config/dovecot/conf.d/10-master.conf
new file mode 100644
index 0000000..e281814
--- /dev/null
+++ b/install/config/dovecot/conf.d/10-master.conf
@@ -0,0 +1,133 @@
+#default_process_limit = 100
+#default_client_limit = 1000
+
+# Default VSZ (virtual memory size) limit for service processes. This is mainly
+# intended to catch and kill processes that leak memory before they eat up
+# everything.
+#default_vsz_limit = 256M
+
+# Login user is internally used by login processes. This is the most untrusted
+# user in Dovecot system. It shouldn't have access to anything at all.
+#default_login_user = dovenull
+
+# Internal user is used by unprivileged processes. It should be separate from
+# login user, so that login processes can't disturb other processes.
+#default_internal_user = dovecot
+
+service imap-login {
+ inet_listener imap {
+ #port=0
+ port = 143
+ }
+ inet_listener imaps {
+ #port = 993
+ #ssl = yes
+ }
+
+ # Number of connections to handle before starting a new process. Typically
+ # the only useful values are 0 (unlimited) or 1. 1 is more secure, but 0
+ # is faster.
+ #service_count = 1
+
+ # Number of processes to always keep waiting for more connections.
+ #process_min_avail = 0
+
+ # If you set service_count=0, you probably need to grow this.
+ #vsz_limit = $default_vsz_limit
+}
+
+service pop3-login {
+ inet_listener pop3 {
+ #port=0
+ port = 110
+ }
+ inet_listener pop3s {
+ #port = 995
+ #ssl = yes
+ }
+}
+
+service lmtp {
+ unix_listener /var/spool/postfix/private/dovecot-lmtp {
+ #mode = 0666
+ mode = 0600
+ user = postfix
+ group = postfix
+ }
+
+ # Create inet listener only if you can't use the above UNIX socket
+ #inet_listener lmtp {
+ # Avoid making LMTP visible for the entire internet
+ #address =
+ #port =
+ #}
+}
+
+service imap {
+ # Most of the memory goes to mmap()ing files. You may need to increase this
+ # limit if you have huge mailboxes.
+ #vsz_limit = $default_vsz_limit
+
+ # Max. number of IMAP processes (connections)
+ #process_limit = 1024
+}
+
+service pop3 {
+ # Max. number of POP3 processes (connections)
+ #process_limit = 1024
+}
+
+service auth {
+ # auth_socket_path points to this userdb socket by default. It's typically
+ # used by dovecot-lda, doveadm, possibly imap process, etc. Users that have
+ # full permissions to this socket are able to get a list of all usernames and
+ # get the results of everyone's userdb lookups.
+ #
+ # The default 0666 mode allows anyone to connect to the socket, but the
+ # userdb lookups will succeed only if the userdb returns an "uid" field that
+ # matches the caller process's UID. Also if caller's uid or gid matches the
+ # socket's uid or gid the lookup succeeds. Anything else causes a failure.
+ #
+ # To give the caller full permissions to lookup all users, set the mode to
+ # something else than 0666 and Dovecot lets the kernel enforce the
+ # permissions (e.g. 0777 allows everyone full permissions).
+ unix_listener auth-userdb {
+ mode = 0600
+ user = vmail
+ #group =
+ }
+
+ unix_listener /var/spool/postfix/private/auth {
+ mode = 0666
+ user = postfix
+ group = postfix
+ }
+
+
+ # Postfix smtp-auth
+ #unix_listener /var/spool/postfix/private/auth {
+ # mode = 0666
+ #}
+
+ # Auth process is run as this user.
+ #user = $default_internal_user
+ user = dovecot
+}
+
+service auth-worker {
+ # Auth worker process is run as root by default, so that it can access
+ # /etc/shadow. If this isn't necessary, the user should be changed to
+ # $default_internal_user.
+ #user = root
+ user = vmail
+}
+
+service dict {
+ # If dict proxy is used, mail processes should have access to its socket.
+ # For example: mode=0660, group=vmail and global mail_access_groups=vmail
+ unix_listener dict {
+ mode = 0666
+ user = vmail
+ group = vmail
+ }
+}
diff --git a/install/config/dovecot/conf.d/10-ssl.conf b/install/config/dovecot/conf.d/10-ssl.conf
new file mode 100644
index 0000000..984f5e8
--- /dev/null
+++ b/install/config/dovecot/conf.d/10-ssl.conf
@@ -0,0 +1,64 @@
+##
+## SSL settings
+##
+
+# SSL/TLS support: yes, no, required.
+ssl = yes
+#ssl = required
+
+# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before
+# dropping root privileges, so keep the key file unreadable by anyone but
+# root. Included doc/mkcert.sh can be used to easily generate self-signed
+# certificate, just make sure to update the domains in dovecot-openssl.cnf
+ssl_cert = . %d expands to recipient domain.
+#postmaster_address =
+
+# Hostname to use in various parts of sent mails (e.g. in Message-Id) and
+# in LMTP replies. Default is the system's real hostname@domain.
+#hostname =
+
+# If user is over quota, return with temporary failure instead of
+# bouncing the mail.
+#quota_full_tempfail = no
+
+# Binary to use for sending mails.
+#sendmail_path = /usr/sbin/sendmail
+
+# If non-empty, send mails via this SMTP host[:port] instead of sendmail.
+#submission_host =
+
+# Subject: header to use for rejection mails. You can use the same variables
+# as for rejection_reason below.
+#rejection_subject = Rejected: %s
+
+# Human readable error message for rejection mails. You can use variables:
+# %n = CRLF, %r = reason, %s = original subject, %t = recipient
+#rejection_reason = Your message to <%t> was automatically rejected:%n%r
+
+# Delimiter character between local-part and detail in email address.
+#recipient_delimiter = +
+
+# Header where the original recipient address (SMTP's RCPT TO: address) is taken
+# from if not available elsewhere. With dovecot-lda -a parameter overrides this.
+# A commonly used header for this is X-Original-To.
+#lda_original_recipient_header =
+
+# Should saving a mail to a nonexistent mailbox automatically create it?
+#lda_mailbox_autocreate = no
+
+# Should automatically created mailboxes be also automatically subscribed?
+#lda_mailbox_autosubscribe = no
+
+protocol lda {
+ # Space separated list of plugins to load (default is global mail_plugins).
+ #mail_plugins = $mail_plugins
+ mail_plugins = sieve
+}
diff --git a/install/config/dovecot/conf.d/15-mailboxes.conf b/install/config/dovecot/conf.d/15-mailboxes.conf
new file mode 100644
index 0000000..cd5b21b
--- /dev/null
+++ b/install/config/dovecot/conf.d/15-mailboxes.conf
@@ -0,0 +1,78 @@
+##
+## Mailbox definitions
+##
+
+# Each mailbox is specified in a separate mailbox section. The section name
+# specifies the mailbox name. If it has spaces, you can put the name
+# "in quotes". These sections can contain the following mailbox settings:
+#
+# auto:
+# Indicates whether the mailbox with this name is automatically created
+# implicitly when it is first accessed. The user can also be automatically
+# subscribed to the mailbox after creation. The following values are
+# defined for this setting:
+#
+# no - Never created automatically.
+# create - Automatically created, but no automatic subscription.
+# subscribe - Automatically created and subscribed.
+#
+# special_use:
+# A space-separated list of SPECIAL-USE flags (RFC 6154) to use for the
+# mailbox. There are no validity checks, so you could specify anything
+# you want in here, but it's not a good idea to use flags other than the
+# standard ones specified in the RFC:
+#
+# \All - This (virtual) mailbox presents all messages in the
+# user's message store.
+# \Archive - This mailbox is used to archive messages.
+# \Drafts - This mailbox is used to hold draft messages.
+# \Flagged - This (virtual) mailbox presents all messages in the
+# user's message store marked with the IMAP \Flagged flag.
+# \Junk - This mailbox is where messages deemed to be junk mail
+# are held.
+# \Sent - This mailbox is used to hold copies of messages that
+# have been sent.
+# \Trash - This mailbox is used to hold messages that have been
+# deleted.
+#
+# comment:
+# Defines a default comment or note associated with the mailbox. This
+# value is accessible through the IMAP METADATA mailbox entries
+# "/shared/comment" and "/private/comment". Users with sufficient
+# privileges can override the default value for entries with a custom
+# value.
+
+# NOTE: Assumes "namespace inbox" has been defined in 10-mail.conf.
+namespace inbox {
+ # These mailboxes are widely used and could perhaps be created automatically:
+ mailbox Drafts {
+ special_use = \Drafts
+ }
+ mailbox Junk {
+ special_use = \Junk
+ }
+ mailbox Trash {
+ special_use = \Trash
+ }
+
+ # For \Sent mailboxes there are two widely used names. We'll mark both of
+ # them as \Sent. User typically deletes one of them if duplicates are created.
+ mailbox Sent {
+ special_use = \Sent
+ }
+ mailbox "Sent Messages" {
+ special_use = \Sent
+ }
+
+ # If you have a virtual "All messages" mailbox:
+ #mailbox virtual/All {
+ # special_use = \All
+ # comment = All my messages
+ #}
+
+ # If you have a virtual "Flagged" mailbox:
+ #mailbox virtual/Flagged {
+ # special_use = \Flagged
+ # comment = All my flagged messages
+ #}
+}
diff --git a/install/config/dovecot/conf.d/20-imap.conf b/install/config/dovecot/conf.d/20-imap.conf
new file mode 100644
index 0000000..6f0cb6f
--- /dev/null
+++ b/install/config/dovecot/conf.d/20-imap.conf
@@ -0,0 +1,77 @@
+##
+## IMAP specific settings
+##
+
+# If nothing happens for this long while client is IDLEing, move the connection
+# to imap-hibernate process and close the old imap process. This saves memory,
+# because connections use very little memory in imap-hibernate process. The
+# downside is that recreating the imap process back uses some resources.
+#imap_hibernate_timeout = 0
+
+# Maximum IMAP command line length. Some clients generate very long command
+# lines with huge mailboxes, so you may need to raise this if you get
+# "Too long argument" or "IMAP command line too large" errors often.
+#imap_max_line_length = 64k
+
+# IMAP logout format string:
+# %i - total number of bytes read from client
+# %o - total number of bytes sent to client
+# %{fetch_hdr_count} - Number of mails with mail header data sent to client
+# %{fetch_hdr_bytes} - Number of bytes with mail header data sent to client
+# %{fetch_body_count} - Number of mails with mail body data sent to client
+# %{fetch_body_bytes} - Number of bytes with mail body data sent to client
+# %{deleted} - Number of mails where client added \Deleted flag
+# %{expunged} - Number of mails that client expunged
+# %{trashed} - Number of mails that client copied/moved to the
+# special_use=\Trash mailbox.
+#imap_logout_format = in=%i out=%o
+
+# Override the IMAP CAPABILITY response. If the value begins with '+',
+# add the given capabilities on top of the defaults (e.g. +XFOO XBAR).
+#imap_capability =
+
+# How long to wait between "OK Still here" notifications when client is
+# IDLEing.
+#imap_idle_notify_interval = 2 mins
+
+# ID field names and values to send to clients. Using * as the value makes
+# Dovecot use the default value. The following fields have default values
+# currently: name, version, os, os-version, support-url, support-email.
+#imap_id_send =
+
+# ID fields sent by client to log. * means everything.
+#imap_id_log =
+
+# Workarounds for various client bugs:
+# delay-newmail:
+# Send EXISTS/RECENT new mail notifications only when replying to NOOP
+# and CHECK commands. Some clients ignore them otherwise, for example OSX
+# Mail (
+ #service_count = 1
+
+ # Number of processes to always keep waiting for more connections.
+ #process_min_avail = 0
+
+ # If you set service_count=0, you probably need to grow this.
+ #vsz_limit = 64M
+}
+
+#service managesieve {
+ # Max. number of ManageSieve processes (connections)
+ #process_limit = 1024
+#}
+
+# Service configuration
+
+protocol sieve {
+ # Maximum ManageSieve command line length in bytes. ManageSieve usually does
+ # not involve overly long command lines, so this setting will not normally
+ # need adjustment
+ #managesieve_max_line_length = 65536
+
+ # Maximum number of ManageSieve connections allowed for a user from each IP
+ # address.
+ # NOTE: The username is compared case-sensitively.
+ #mail_max_userip_connections = 10
+
+ # Space separated list of plugins to load (none known to be useful so far).
+ # Do NOT try to load IMAP plugins here.
+ #mail_plugins =
+
+ # MANAGESIEVE logout format string:
+ # %i - total number of bytes read from client
+ # %o - total number of bytes sent to client
+ #managesieve_logout_format = bytes=%i/%o
+
+ # To fool ManageSieve clients that are focused on CMU's timesieved you can
+ # specify the IMPLEMENTATION capability that Dovecot reports to clients.
+ # For example: 'Cyrus timsieved v2.2.13'
+ #managesieve_implementation_string = Dovecot Pigeonhole
+
+ # Explicitly specify the SIEVE and NOTIFY capability reported by the server
+ # before login. If left unassigned these will be reported dynamically
+ # according to what the Sieve interpreter supports by default (after login
+ # this may differ depending on the user).
+ #managesieve_sieve_capability =
+ #managesieve_notify_capability =
+
+ # The maximum number of compile errors that are returned to the client upon
+ # script upload or script verification.
+ #managesieve_max_compile_errors = 5
+
+ # Refer to 90-sieve.conf for script quota configuration and configuration of
+ # Sieve execution limits.
+}
diff --git a/install/config/dovecot/conf.d/20-pop3.conf b/install/config/dovecot/conf.d/20-pop3.conf
new file mode 100644
index 0000000..1423682
--- /dev/null
+++ b/install/config/dovecot/conf.d/20-pop3.conf
@@ -0,0 +1,101 @@
+##
+## POP3 specific settings
+##
+
+# Don't try to set mails non-recent or seen with POP3 sessions. This is
+# mostly intended to reduce disk I/O. With maildir it doesn't move files
+# from new/ to cur/, with mbox it doesn't write Status-header.
+#pop3_no_flag_updates = no
+
+# Support LAST command which exists in old POP3 specs, but has been removed
+# from new ones. Some clients still wish to use this though. Enabling this
+# makes RSET command clear all \Seen flags from messages.
+#pop3_enable_last = no
+
+# If mail has X-UIDL header, use it as the mail's UIDL.
+#pop3_reuse_xuidl = no
+
+# Allow only one POP3 session to run simultaneously for the same user.
+#pop3_lock_session = no
+
+# POP3 requires message sizes to be listed as if they had CR+LF linefeeds.
+# Many POP3 servers violate this by returning the sizes with LF linefeeds,
+# because it's faster to get. When this setting is enabled, Dovecot still
+# tries to do the right thing first, but if that requires opening the
+# message, it fallbacks to the easier (but incorrect) size.
+#pop3_fast_size_lookups = no
+
+# POP3 UIDL (unique mail identifier) format to use. You can use following
+# variables, along with the variable modifiers described in
+# doc/wiki/Variables.txt (e.g. %Uf for the filename in uppercase)
+#
+# %v - Mailbox's IMAP UIDVALIDITY
+# %u - Mail's IMAP UID
+# %m - MD5 sum of the mailbox headers in hex (mbox only)
+# %f - filename (maildir only)
+# %g - Mail's GUID
+#
+# If you want UIDL compatibility with other POP3 servers, use:
+# UW's ipop3d : %08Xv%08Xu
+# Courier : %f or %v-%u (both might be used simultaneosly)
+# Cyrus (<= 2.1.3) : %u
+# Cyrus (>= 2.1.4) : %v.%u
+# Dovecot v0.99.x : %v.%u
+# tpop3d : %Mf
+#
+# Note that Outlook 2003 seems to have problems with %v.%u format which was
+# Dovecot's default, so if you're building a new server it would be a good
+# idea to change this. %08Xu%08Xv should be pretty fail-safe.
+#
+#pop3_uidl_format = %08Xu%08Xv
+
+# Permanently save UIDLs sent to POP3 clients, so pop3_uidl_format changes
+# won't change those UIDLs. Currently this works only with Maildir.
+#pop3_save_uidl = no
+
+# What to do about duplicate UIDLs if they exist?
+# allow: Show duplicates to clients.
+# rename: Append a temporary -2, -3, etc. counter after the UIDL.
+#pop3_uidl_duplicates = allow
+
+# This option changes POP3 behavior so that it's not possible to actually
+# delete mails via POP3, only hide them from future POP3 sessions. The mails
+# will still be counted towards user's quota until actually deleted via IMAP.
+# Use e.g. "$POP3Deleted" as the value (it will be visible as IMAP keyword).
+# Make sure you can legally archive mails before enabling this setting.
+#pop3_deleted_flag =
+
+# POP3 logout format string:
+# %i - total number of bytes read from client
+# %o - total number of bytes sent to client
+# %t - number of TOP commands
+# %p - number of bytes sent to client as a result of TOP command
+# %r - number of RETR commands
+# %b - number of bytes sent to client as a result of RETR command
+# %d - number of deleted messages
+# %{deleted_bytes} - number of bytes in deleted messages
+# %m - number of messages (before deletion)
+# %s - mailbox size in bytes (before deletion)
+# %u - old/new UIDL hash. may help finding out if UIDLs changed unexpectedly
+#pop3_logout_format = top=%t/%p, retr=%r/%b, del=%d/%m, size=%s
+
+# Workarounds for various client bugs:
+# outlook-no-nuls:
+# Outlook and Outlook Express hang if mails contain NUL characters.
+# This setting replaces them with 0x80 character.
+# oe-ns-eoh:
+# Outlook Express and Netscape Mail breaks if end of headers-line is
+# missing. This option simply sends it if it's missing.
+# The list is space-separated.
+#pop3_client_workarounds =
+
+protocol pop3 {
+ # Space separated list of plugins to load (default is global mail_plugins).
+ #mail_plugins = $mail_plugins
+ mail_plugins = quota
+ pop3_client_workarounds = outlook-no-nuls oe-ns-eoh
+
+ # Maximum number of POP3 connections allowed for a user from each IP address.
+ # NOTE: The username is compared case-sensitively.
+ #mail_max_userip_connections = 10
+}
diff --git a/install/config/dovecot/conf.d/90-acl.conf b/install/config/dovecot/conf.d/90-acl.conf
new file mode 100644
index 0000000..f0c0e7a
--- /dev/null
+++ b/install/config/dovecot/conf.d/90-acl.conf
@@ -0,0 +1,19 @@
+##
+## Mailbox access control lists.
+##
+
+# vfile backend reads ACLs from "dovecot-acl" file from mail directory.
+# You can also optionally give a global ACL directory path where ACLs are
+# applied to all users' mailboxes. The global ACL directory contains
+# one file for each mailbox, eg. INBOX or sub.mailbox. cache_secs parameter
+# specifies how many seconds to wait between stat()ing dovecot-acl file
+# to see if it changed.
+plugin {
+ #acl = vfile:/etc/dovecot/global-acls:cache_secs=300
+}
+
+# To let users LIST mailboxes shared by other users, Dovecot needs a
+# shared mailbox dictionary. For example:
+plugin {
+ #acl_shared_dict = file:/var/lib/dovecot/shared-mailboxes
+}
diff --git a/install/config/dovecot/conf.d/90-plugin.conf b/install/config/dovecot/conf.d/90-plugin.conf
new file mode 100644
index 0000000..092e776
--- /dev/null
+++ b/install/config/dovecot/conf.d/90-plugin.conf
@@ -0,0 +1,15 @@
+##
+## Plugin settings
+##
+
+# All wanted plugins must be listed in mail_plugins setting before any of the
+# settings take effect. See for list of plugins and
+# their configuration. Note that %variable expansion is done for all values.
+
+plugin {
+ #setting_name = value
+ sieve=~/.dovecot.sieve
+ sieve_dir = ~/sieve
+ sieve_before = /yytmail/mail/sieve/dovecot.sieve
+ #sieve_user_log = /var/log/sieve.log
+}
diff --git a/install/config/dovecot/conf.d/90-quota.conf b/install/config/dovecot/conf.d/90-quota.conf
new file mode 100644
index 0000000..f1a5b68
--- /dev/null
+++ b/install/config/dovecot/conf.d/90-quota.conf
@@ -0,0 +1,85 @@
+##
+## Quota configuration.
+##
+
+# Note that you also have to enable quota plugin in mail_plugins setting.
+#
+
+##
+## Quota limits
+##
+
+# Quota limits are set using "quota_rule" parameters. To get per-user quota
+# limits, you can set/override them by returning "quota_rule" extra field
+# from userdb. It's also possible to give mailbox-specific limits, for example
+# to give additional 100 MB when saving to Trash:
+
+plugin {
+ #quota_rule = *:storage=1G
+ #quota_rule2 = Trash:storage=+100M
+
+ # LDA/LMTP allows saving the last mail to bring user from under quota to
+ # over quota, if the quota doesn't grow too high. Default is to allow as
+ # long as quota will stay under 10% above the limit. Also allowed e.g. 10M.
+ #quota_grace = 10%%
+}
+
+##
+## Quota warnings
+##
+
+# You can execute a given command when user exceeds a specified quota limit.
+# Each quota root has separate limits. Only the command for the first
+# exceeded limit is excecuted, so put the highest limit first.
+# The commands are executed via script service by connecting to the named
+# UNIX socket (quota-warning below).
+# Note that % needs to be escaped as %%, otherwise "% " expands to empty.
+
+plugin {
+ #quota_warning = storage=95%% quota-warning 95 %u
+ #quota_warning2 = storage=80%% quota-warning 80 %u
+}
+
+# Example quota-warning service. The unix listener's permissions should be
+# set in a way that mail processes can connect to it. Below example assumes
+# that mail processes run as vmail user. If you use mode=0666, all system users
+# can generate quota warnings to anyone.
+#service quota-warning {
+# executable = script /usr/local/bin/quota-warning.sh
+# user = dovecot
+# unix_listener quota-warning {
+# user = vmail
+# }
+#}
+
+##
+## Quota backends
+##
+
+# Multiple backends are supported:
+# dirsize: Find and sum all the files found from mail directory.
+# Extremely SLOW with Maildir. It'll eat your CPU and disk I/O.
+# dict: Keep quota stored in dictionary (eg. SQL)
+# maildir: Maildir++ quota
+# fs: Read-only support for filesystem quota
+
+plugin {
+ #quota = dirsize:User quota
+ #quota = maildir:User quota
+ #quota = dict:User quota::proxy::quota
+ #quota = fs:User quota
+}
+
+# Multiple quota roots are also possible, for example this gives each user
+# their own 100MB quota and one shared 1GB quota within the domain:
+plugin {
+ #quota = dict:user::proxy::quota
+ #quota2 = dict:domain:%d:proxy::quota_domain
+ #quota_rule = *:storage=102400
+ #quota2_rule = *:storage=1048576
+ # SQL backend:
+ quota = dict:user::proxy::quota
+ # Redis backend (v2.1.9+):
+ #quota = dict:User quota::redis:host=127.0.0.1:prefix=user/
+ quota_rule = *:storage=0
+}
diff --git a/install/config/dovecot/conf.d/auth-checkpassword.conf.ext b/install/config/dovecot/conf.d/auth-checkpassword.conf.ext
new file mode 100644
index 0000000..b2fb13a
--- /dev/null
+++ b/install/config/dovecot/conf.d/auth-checkpassword.conf.ext
@@ -0,0 +1,21 @@
+# Authentication for checkpassword users. Included from 10-auth.conf.
+#
+#
+
+passdb {
+ driver = checkpassword
+ args = /usr/bin/checkpassword
+}
+
+# passdb lookup should return also userdb info
+userdb {
+ driver = prefetch
+}
+
+# Standard checkpassword doesn't support direct userdb lookups.
+# If you need checkpassword userdb, the checkpassword must support
+# Dovecot-specific extensions.
+#userdb {
+# driver = checkpassword
+# args = /usr/bin/checkpassword
+#}
diff --git a/install/config/dovecot/conf.d/auth-deny.conf.ext b/install/config/dovecot/conf.d/auth-deny.conf.ext
new file mode 100644
index 0000000..ce3f1cf
--- /dev/null
+++ b/install/config/dovecot/conf.d/auth-deny.conf.ext
@@ -0,0 +1,15 @@
+# Deny access for users. Included from 10-auth.conf.
+
+# Users can be (temporarily) disabled by adding a passdb with deny=yes.
+# If the user is found from that database, authentication will fail.
+# The deny passdb should always be specified before others, so it gets
+# checked first.
+
+# Example deny passdb using passwd-file. You can use any passdb though.
+passdb {
+ driver = passwd-file
+ deny = yes
+
+ # File contains a list of usernames, one per line
+ args = /etc/dovecot/deny-users
+}
diff --git a/install/config/dovecot/conf.d/auth-dict.conf.ext b/install/config/dovecot/conf.d/auth-dict.conf.ext
new file mode 100644
index 0000000..0be4847
--- /dev/null
+++ b/install/config/dovecot/conf.d/auth-dict.conf.ext
@@ -0,0 +1,16 @@
+# Authentication via dict backend. Included from 10-auth.conf.
+#
+#
+
+passdb {
+ driver = dict
+
+ # Path for dict configuration file, see
+ # example-config/dovecot-dict-auth.conf.ext
+ args = /etc/dovecot/dovecot-dict-auth.conf.ext
+}
+
+userdb {
+ driver = dict
+ args = /etc/dovecot/dovecot-dict-auth.conf.ext
+}
diff --git a/install/config/dovecot/conf.d/auth-ldap.conf.ext b/install/config/dovecot/conf.d/auth-ldap.conf.ext
new file mode 100644
index 0000000..5db32fa
--- /dev/null
+++ b/install/config/dovecot/conf.d/auth-ldap.conf.ext
@@ -0,0 +1,33 @@
+# Authentication for LDAP users. Included from 10-auth.conf.
+#
+#
+
+passdb {
+ driver = ldap
+
+ # Path for LDAP configuration file, see example-config/dovecot-ldap.conf.ext
+ args = /etc/dovecot/dovecot-ldap.conf.ext
+}
+
+# "prefetch" user database means that the passdb already provided the
+# needed information and there's no need to do a separate userdb lookup.
+#
+#userdb {
+# driver = prefetch
+#}
+
+userdb {
+ driver = ldap
+ args = /etc/dovecot/dovecot-ldap.conf.ext
+
+ # Default fields can be used to specify defaults that LDAP may override
+ #default_fields = home=/home/virtual/%u
+}
+
+# If you don't have any user-specific settings, you can avoid the userdb LDAP
+# lookup by using userdb static instead of userdb ldap, for example:
+#
+#userdb {
+ #driver = static
+ #args = uid=vmail gid=vmail home=/var/vmail/%u
+#}
diff --git a/install/config/dovecot/conf.d/auth-master.conf.ext b/install/config/dovecot/conf.d/auth-master.conf.ext
new file mode 100644
index 0000000..2cf128f
--- /dev/null
+++ b/install/config/dovecot/conf.d/auth-master.conf.ext
@@ -0,0 +1,16 @@
+# Authentication for master users. Included from 10-auth.conf.
+
+# By adding master=yes setting inside a passdb you make the passdb a list
+# of "master users", who can log in as anyone else.
+#
+
+# Example master user passdb using passwd-file. You can use any passdb though.
+passdb {
+ driver = passwd-file
+ master = yes
+ args = /etc/dovecot/master-users
+
+ # Unless you're using PAM, you probably still want the destination user to
+ # be looked up from passdb that it really exists. pass=yes does that.
+ pass = yes
+}
diff --git a/install/config/dovecot/conf.d/auth-passwdfile.conf.ext b/install/config/dovecot/conf.d/auth-passwdfile.conf.ext
new file mode 100644
index 0000000..c89d28c
--- /dev/null
+++ b/install/config/dovecot/conf.d/auth-passwdfile.conf.ext
@@ -0,0 +1,20 @@
+# Authentication for passwd-file users. Included from 10-auth.conf.
+#
+# passwd-like file with specified location.
+#
+
+passdb {
+ driver = passwd-file
+ args = scheme=CRYPT username_format=%u /etc/dovecot/users
+}
+
+userdb {
+ driver = passwd-file
+ args = username_format=%u /etc/dovecot/users
+
+ # Default fields that can be overridden by passwd-file
+ #default_fields = quota_rule=*:storage=1G
+
+ # Override fields from passwd-file
+ #override_fields = home=/home/virtual/%u
+}
diff --git a/install/config/dovecot/conf.d/auth-sql.conf.ext b/install/config/dovecot/conf.d/auth-sql.conf.ext
new file mode 100644
index 0000000..ec32e03
--- /dev/null
+++ b/install/config/dovecot/conf.d/auth-sql.conf.ext
@@ -0,0 +1,30 @@
+# Authentication for SQL users. Included from 10-auth.conf.
+#
+#
+
+passdb {
+ driver = sql
+
+ # Path for SQL configuration file, see example-config/dovecot-sql.conf.ext
+ args = /etc/dovecot/dovecot-sql.conf.ext
+}
+
+# "prefetch" user database means that the passdb already provided the
+# needed information and there's no need to do a separate userdb lookup.
+#
+#userdb {
+# driver = prefetch
+#}
+#
+#userdb {
+# driver = sql
+# args = /etc/dovecot/dovecot-sql.conf.ext
+#}
+
+# If you don't have any user-specific settings, you can avoid the user_query
+# by using userdb static instead of userdb sql, for example:
+#
+userdb {
+ driver = static
+ args = uid=vmail gid=vmail home=/ewomail/mail/vhosts/%d/%n
+}
diff --git a/install/config/dovecot/conf.d/auth-static.conf.ext b/install/config/dovecot/conf.d/auth-static.conf.ext
new file mode 100644
index 0000000..90890c5
--- /dev/null
+++ b/install/config/dovecot/conf.d/auth-static.conf.ext
@@ -0,0 +1,24 @@
+# Static passdb. Included from 10-auth.conf.
+
+# This can be used for situations where Dovecot doesn't need to verify the
+# username or the password, or if there is a single password for all users:
+#
+# - proxy frontend, where the backend verifies the password
+# - proxy backend, where the frontend already verified the password
+# - authentication with SSL certificates
+# - simple testing
+
+#passdb {
+# driver = static
+# args = proxy=y host=%1Mu.example.com nopassword=y
+#}
+
+#passdb {
+# driver = static
+# args = password=test
+#}
+
+#userdb {
+# driver = static
+# args = uid=vmail gid=vmail home=/home/%u
+#}
diff --git a/install/config/dovecot/conf.d/auth-system.conf.ext b/install/config/dovecot/conf.d/auth-system.conf.ext
new file mode 100644
index 0000000..23f943c
--- /dev/null
+++ b/install/config/dovecot/conf.d/auth-system.conf.ext
@@ -0,0 +1,74 @@
+# Authentication for system users. Included from 10-auth.conf.
+#
+#
+#
+
+# PAM authentication. Preferred nowadays by most systems.
+# PAM is typically used with either userdb passwd or userdb static.
+# REMEMBER: You'll need /etc/pam.d/dovecot file created for PAM
+# authentication to actually work.
+passdb {
+ driver = pam
+ # [session=yes] [setcred=yes] [failure_show_msg=yes] [max_requests=]
+ # [cache_key=] []
+ #args = dovecot
+}
+
+# System users (NSS, /etc/passwd, or similiar).
+# In many systems nowadays this uses Name Service Switch, which is
+# configured in /etc/nsswitch.conf.
+#passdb {
+ #driver = passwd
+ # [blocking=no]
+ #args =
+#}
+
+# Shadow passwords for system users (NSS, /etc/shadow or similiar).
+# Deprecated by PAM nowadays.
+#
+#passdb {
+ #driver = shadow
+ # [blocking=no]
+ #args =
+#}
+
+# PAM-like authentication for OpenBSD.
+#
+#passdb {
+ #driver = bsdauth
+ # [blocking=no] [cache_key=]
+ #args =
+#}
+
+##
+## User databases
+##
+
+# System users (NSS, /etc/passwd, or similiar). In many systems nowadays this
+# uses Name Service Switch, which is configured in /etc/nsswitch.conf.
+userdb {
+ #
+ driver = passwd
+ # [blocking=no]
+ #args =
+
+ # Override fields from passwd
+ #override_fields = home=/home/virtual/%u
+}
+
+# Static settings generated from template
+#userdb {
+ #driver = static
+ # Can return anything a userdb could normally return. For example:
+ #
+ # args = uid=500 gid=500 home=/var/mail/%u
+ #
+ # LDA and LMTP needs to look up users only from the userdb. This of course
+ # doesn't work with static userdb because there is no list of users.
+ # Normally static userdb handles this by doing a passdb lookup. This works
+ # with most passdbs, with PAM being the most notable exception. If you do
+ # the user verification another way, you can add allow_all_users=yes to
+ # the args in which case the passdb lookup is skipped.
+ #
+ #args =
+#}
diff --git a/install/config/dovecot/conf.d/auth-vpopmail.conf.ext b/install/config/dovecot/conf.d/auth-vpopmail.conf.ext
new file mode 100644
index 0000000..f2da976
--- /dev/null
+++ b/install/config/dovecot/conf.d/auth-vpopmail.conf.ext
@@ -0,0 +1,17 @@
+# Authentication for vpopmail users. Included from 10-auth.conf.
+#
+#
+
+passdb {
+ driver = vpopmail
+
+ # [cache_key=] [webmail=]
+ args =
+}
+
+userdb {
+ driver = vpopmail
+
+ # [quota_template=] - %q expands to Maildir++ quota
+ args = quota_template=quota_rule=*:backend=%q
+}
diff --git a/install/config/dovecot/dovecot-dict-auth.conf.ext b/install/config/dovecot/dovecot-dict-auth.conf.ext
new file mode 100644
index 0000000..79f43de
--- /dev/null
+++ b/install/config/dovecot/dovecot-dict-auth.conf.ext
@@ -0,0 +1,54 @@
+# This file is commonly accessed via passdb {} or userdb {} section in
+# conf.d/auth-dict.conf.ext
+
+# Dictionary URI
+#uri =
+
+# Default password scheme
+default_pass_scheme = MD5
+
+# Username iteration prefix. Keys under this are assumed to contain usernames.
+iterate_prefix = userdb/
+
+# Should iteration be disabled for this userdb? If this userdb acts only as a
+# cache there's no reason to try to iterate the (partial & duplicate) users.
+#iterate_disable = no
+
+# The example here shows how to do multiple dict lookups and merge the replies.
+# The "passdb" and "userdb" keys are JSON objects containing key/value pairs,
+# for example: { "uid": 1000, "gid": 1000, "home": "/home/user" }
+
+key passdb {
+ key = passdb/%u
+ format = json
+}
+key userdb {
+ key = userdb/%u
+ format = json
+}
+key quota {
+ key = userdb/%u/quota
+ #format = value
+ # The default_value is used if the key isn't found. If default_value setting
+ # isn't specified at all (even as empty), the passdb/userdb lookup fails with
+ # "user doesn't exist".
+ default_value = 100M
+}
+
+# Space separated list of keys whose values contain key/value paired objects.
+# All the key/value pairs inside the object are added as passdb fields.
+passdb_objects = passdb
+
+#passdb_fields {
+#}
+
+# Userdb key/value object list.
+userdb_objects = userdb
+
+userdb_fields {
+ # dict: refers to key names
+ quota_rule = *:storage=%{dict:quota}
+
+ # dict:. refers to the objkey inside (JSON) object
+ mail = maildir:%{dict:userdb.home}/Maildir
+}
diff --git a/install/config/dovecot/dovecot-dict-sql.conf.ext b/install/config/dovecot/dovecot-dict-sql.conf.ext
new file mode 100644
index 0000000..7f8bdbc
--- /dev/null
+++ b/install/config/dovecot/dovecot-dict-sql.conf.ext
@@ -0,0 +1,41 @@
+# This file is commonly accessed via dict {} section in dovecot.conf
+
+connect = host=127.0.0.1 dbname=ewomail user=ewomail password=123456
+
+# CREATE TABLE quota (
+# username varchar(100) not null,
+# bytes bigint not null default 0,
+# messages integer not null default 0,
+# primary key (username)
+# );
+
+map {
+ pattern = priv/quota/storage
+ table = i_quota
+ username_field = email
+ value_field = bytes
+}
+map {
+ pattern = priv/quota/messages
+ table = i_quota
+ username_field = email
+ value_field = messages
+}
+
+# CREATE TABLE expires (
+# username varchar(100) not null,
+# mailbox varchar(255) not null,
+# expire_stamp integer not null,
+# primary key (username, mailbox)
+# );
+#
+#map {
+# pattern = shared/expire/$user/$mailbox
+# table = expires
+# value_field = expire_stamp
+#
+# fields {
+# username = $user
+# mailbox = $mailbox
+# }
+#}
diff --git a/install/config/dovecot/dovecot-ldap.conf.ext b/install/config/dovecot/dovecot-ldap.conf.ext
new file mode 100644
index 0000000..1ca6733
--- /dev/null
+++ b/install/config/dovecot/dovecot-ldap.conf.ext
@@ -0,0 +1,143 @@
+# This file is commonly accessed via passdb {} or userdb {} section in
+# conf.d/auth-ldap.conf.ext
+
+# This file is opened as root, so it should be owned by root and mode 0600.
+#
+# http://wiki2.dovecot.org/AuthDatabase/LDAP
+#
+# NOTE: If you're not using authentication binds, you'll need to give
+# dovecot-auth read access to userPassword field in the LDAP server.
+# With OpenLDAP this is done by modifying /etc/ldap/slapd.conf. There should
+# already be something like this:
+
+# access to attribute=userPassword
+# by dn="" read # add this
+# by anonymous auth
+# by self write
+# by * none
+
+# Space separated list of LDAP hosts to use. host:port is allowed too.
+#hosts =
+
+# LDAP URIs to use. You can use this instead of hosts list. Note that this
+# setting isn't supported by all LDAP libraries.
+#uris =
+
+# Distinguished Name - the username used to login to the LDAP server.
+# Leave it commented out to bind anonymously (useful with auth_bind=yes).
+#dn =
+
+# Password for LDAP server, if dn is specified.
+#dnpass =
+
+# Use SASL binding instead of the simple binding. Note that this changes
+# ldap_version automatically to be 3 if it's lower. Also note that SASL binds
+# and auth_bind=yes don't work together.
+#sasl_bind = no
+# SASL mechanism name to use.
+#sasl_mech =
+# SASL realm to use.
+#sasl_realm =
+# SASL authorization ID, ie. the dnpass is for this "master user", but the
+# dn is still the logged in user. Normally you want to keep this empty.
+#sasl_authz_id =
+
+# Use TLS to connect to the LDAP server.
+#tls = no
+# TLS options, currently supported only with OpenLDAP:
+#tls_ca_cert_file =
+#tls_ca_cert_dir =
+#tls_cipher_suite =
+# TLS cert/key is used only if LDAP server requires a client certificate.
+#tls_cert_file =
+#tls_key_file =
+# Valid values: never, hard, demand, allow, try
+#tls_require_cert =
+
+# Use the given ldaprc path.
+#ldaprc_path =
+
+# LDAP library debug level as specified by LDAP_DEBUG_* in ldap_log.h.
+# -1 = everything. You may need to recompile OpenLDAP with debugging enabled
+# to get enough output.
+#debug_level = 0
+
+# Use authentication binding for verifying password's validity. This works by
+# logging into LDAP server using the username and password given by client.
+# The pass_filter is used to find the DN for the user. Note that the pass_attrs
+# is still used, only the password field is ignored in it. Before doing any
+# search, the binding is switched back to the default DN.
+#auth_bind = no
+
+# If authentication binding is used, you can save one LDAP request per login
+# if users' DN can be specified with a common template. The template can use
+# the standard %variables (see user_filter). Note that you can't
+# use any pass_attrs if you use this setting.
+#
+# If you use this setting, it's a good idea to use a different
+# dovecot-ldap.conf.ext for userdb (it can even be a symlink, just as long as
+# the filename is different in userdb's args). That way one connection is used
+# only for LDAP binds and another connection is used for user lookups.
+# Otherwise the binding is changed to the default DN before each user lookup.
+#
+# For example:
+# auth_bind_userdn = cn=%u,ou=people,o=org
+#
+#auth_bind_userdn =
+
+# LDAP protocol version to use. Likely 2 or 3.
+#ldap_version = 3
+
+# LDAP base. %variables can be used here.
+# For example: dc=mail, dc=example, dc=org
+base =
+
+# Dereference: never, searching, finding, always
+#deref = never
+
+# Search scope: base, onelevel, subtree
+#scope = subtree
+
+# User attributes are given in LDAP-name=dovecot-internal-name list. The
+# internal names are:
+# uid - System UID
+# gid - System GID
+# home - Home directory
+# mail - Mail location
+#
+# There are also other special fields which can be returned, see
+# http://wiki2.dovecot.org/UserDatabase/ExtraFields
+#user_attrs = homeDirectory=home,uidNumber=uid,gidNumber=gid
+
+# Filter for user lookup. Some variables can be used (see
+# http://wiki2.dovecot.org/Variables for full list):
+# %u - username
+# %n - user part in user@domain, same as %u if there's no domain
+# %d - domain part in user@domain, empty if user there's no domain
+#user_filter = (&(objectClass=posixAccount)(uid=%u))
+
+# Password checking attributes:
+# user: Virtual user name (user@domain), if you wish to change the
+# user-given username to something else
+# password: Password, may optionally start with {type}, eg. {crypt}
+# There are also other special fields which can be returned, see
+# http://wiki2.dovecot.org/PasswordDatabase/ExtraFields
+#pass_attrs = uid=user,userPassword=password
+
+# If you wish to avoid two LDAP lookups (passdb + userdb), you can use
+# userdb prefetch instead of userdb ldap in dovecot.conf. In that case you'll
+# also have to include user_attrs in pass_attrs field prefixed with "userdb_"
+# string. For example:
+#pass_attrs = uid=user,userPassword=password,\
+# homeDirectory=userdb_home,uidNumber=userdb_uid,gidNumber=userdb_gid
+
+# Filter for password lookups
+#pass_filter = (&(objectClass=posixAccount)(uid=%u))
+
+# Attributes and filter to get a list of all users
+#iterate_attrs = uid=user
+#iterate_filter = (objectClass=posixAccount)
+
+# Default password scheme. "{scheme}" before password overrides this.
+# List of supported schemes is in: http://wiki2.dovecot.org/Authentication
+#default_pass_scheme = CRYPT
diff --git a/install/config/dovecot/dovecot-sql.conf.ext b/install/config/dovecot/dovecot-sql.conf.ext
new file mode 100644
index 0000000..51d9c38
--- /dev/null
+++ b/install/config/dovecot/dovecot-sql.conf.ext
@@ -0,0 +1,15 @@
+driver = mysql
+
+connect = host=127.0.0.1 dbname=ewomail user=ewomail password=123456
+
+default_pass_scheme = MD5
+#default_pass_scheme = CRYPT
+
+user_query = \
+ SELECT maildir AS home \
+ FROM i_users WHERE email='%u'
+
+# Query to get a list of all usernames.
+iterate_query = SELECT email AS user FROM i_users
+
+password_query = SELECT u.password FROM i_users as u INNER JOIN i_domains as d ON u.domain_id=d.id WHERE u.email='%u' and u.active=1 and d.active=1;
diff --git a/install/config/dovecot/dovecot.conf b/install/config/dovecot/dovecot.conf
new file mode 100644
index 0000000..be5cbd1
--- /dev/null
+++ b/install/config/dovecot/dovecot.conf
@@ -0,0 +1,180 @@
+mail_uid = vmail
+mail_gid = vmail
+
+listen = *
+
+mail_privileged_group = vmail
+
+log_path = /var/log/dovecot.log
+mail_debug = yes
+auth_verbose = yes
+auth_debug = yes
+auth_debug_passwords = no
+# Possible values: no, plain, sha1.
+auth_verbose_passwords = no
+
+ssl = yes
+#verbose_ssl = no
+
+ssl_cert = \]: SASL (PLAIN|LOGIN) authentication failed
+ reject: RCPT from (.*)\[\]: 550 5.1.1
+ reject: RCPT from (.*)\[\]: 450 4.7.1
+ reject: RCPT from (.*)\[\]: 554 5.7.1
+ignoreregex =
\ No newline at end of file
diff --git a/install/config/mail/backup/README.md b/install/config/mail/backup/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/install/config/mail/sieve/dovecot.sieve b/install/config/mail/sieve/dovecot.sieve
new file mode 100644
index 0000000..4621083
--- /dev/null
+++ b/install/config/mail/sieve/dovecot.sieve
@@ -0,0 +1,9 @@
+require ["fileinto"];
+
+# rule:[Move Spam to Junk Folder]
+
+if header :is "X-Spam-Flag" "YES"
+{
+ fileinto "Spam";
+ stop;
+}
\ No newline at end of file
diff --git a/install/config/mail/vmail/README.md b/install/config/mail/vmail/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/install/config/postfix/access b/install/config/postfix/access
new file mode 100644
index 0000000..4a57535
--- /dev/null
+++ b/install/config/postfix/access
@@ -0,0 +1,451 @@
+# ACCESS(5) ACCESS(5)
+#
+# NAME
+# access - Postfix SMTP server access table
+#
+# SYNOPSIS
+# postmap /etc/postfix/access
+#
+# postmap -q "string" /etc/postfix/access
+#
+# postmap -q - /etc/postfix/access as the lookup key for such addresses. The value is
+# specified with the smtpd_null_access_lookup_key parameter
+# in the Postfix main.cf file.
+#
+# EMAIL ADDRESS EXTENSION
+# When a mail address localpart contains the optional recip-
+# ient delimiter (e.g., user+foo@domain), the lookup order
+# becomes: user+foo@domain, user@domain, domain, user+foo@,
+# and user@.
+#
+# HOST NAME/ADDRESS PATTERNS
+# With lookups from indexed files such as DB or DBM, or from
+# networked tables such as NIS, LDAP or SQL, the following
+# lookup patterns are examined in the order as listed:
+#
+# domain.tld
+# Matches domain.tld.
+#
+# The pattern domain.tld also matches subdomains, but
+# only when the string smtpd_access_maps is listed in
+# the Postfix parent_domain_matches_subdomains con-
+# figuration setting. Otherwise, specify .domain.tld
+# (note the initial dot) in order to match subdo-
+# mains.
+#
+# net.work.addr.ess
+#
+# net.work.addr
+#
+# net.work
+#
+# net Matches the specified IPv4 host address or subnet-
+# work. An IPv4 host address is a sequence of four
+# decimal octets separated by ".".
+#
+# Subnetworks are matched by repeatedly truncating
+# the last ".octet" from the remote IPv4 host address
+# string until a match is found in the access table,
+# or until further truncation is not possible.
+#
+# NOTE 1: The access map lookup key must be in canon-
+# ical form: do not specify unnecessary null charac-
+# ters, and do not enclose network address informa-
+# tion with "[]" characters.
+#
+# NOTE 2: use the cidr lookup table type to specify
+# network/netmask patterns. See cidr_table(5) for
+# details.
+#
+# net:work:addr:ess
+#
+# net:work:addr
+#
+# net:work
+#
+# net Matches the specified IPv6 host address or subnet-
+# work. An IPv6 host address is a sequence of three
+# to eight hexadecimal octet pairs separated by ":".
+#
+# Subnetworks are matched by repeatedly truncating
+# the last ":octetpair" from the remote IPv6 host
+# address string until a match is found in the access
+# table, or until further truncation is not possible.
+#
+# NOTE 1: the truncation and comparison are done with
+# the string representation of the IPv6 host address.
+# Thus, not all the ":" subnetworks will be tried.
+#
+# NOTE 2: The access map lookup key must be in canon-
+# ical form: do not specify unnecessary null charac-
+# ters, and do not enclose network address informa-
+# tion with "[]" characters.
+#
+# NOTE 3: use the cidr lookup table type to specify
+# network/netmask patterns. See cidr_table(5) for
+# details.
+#
+# IPv6 support is available in Postfix 2.2 and later.
+#
+# ACCEPT ACTIONS
+# OK Accept the address etc. that matches the pattern.
+#
+# all-numerical
+# An all-numerical result is treated as OK. This for-
+# mat is generated by address-based relay authoriza-
+# tion schemes such as pop-before-smtp.
+#
+# REJECT ACTIONS
+# Postfix version 2.3 and later support enhanced status
+# codes as defined in RFC 3463. When no code is specified
+# at the beginning of the text below, Postfix inserts a
+# default enhanced status code of "5.7.1" in the case of
+# reject actions, and "4.7.1" in the case of defer actions.
+# See "ENHANCED STATUS CODES" below.
+#
+# 4NN text
+#
+# 5NN text
+# Reject the address etc. that matches the pattern,
+# and respond with the numerical three-digit code and
+# text. 4NN means "try again later", while 5NN means
+# "do not try again".
+#
+# The following responses have special meaning for
+# the Postfix SMTP server:
+#
+# 421 text (Postfix 2.3 and later)
+#
+# 521 text (Postfix 2.6 and later)
+# After responding with the numerical three-
+# digit code and text, disconnect immediately
+# from the SMTP client. This frees up SMTP
+# server resources so that they can be made
+# available to another SMTP client.
+#
+# Note: The "521" response should be used only
+# with botnets and other malware where inter-
+# operability is of no concern. The "send 521
+# and disconnect" behavior is NOT defined in
+# the SMTP standard.
+#
+# REJECT optional text...
+# Reject the address etc. that matches the pattern.
+# Reply with "$access_map_reject_code optional
+# text..." when the optional text is specified, oth-
+# erwise reply with a generic error response message.
+#
+# DEFER optional text...
+# Reject the address etc. that matches the pattern.
+# Reply with "$access_map_defer_code optional
+# text..." when the optional text is specified, oth-
+# erwise reply with a generic error response message.
+#
+# This feature is available in Postfix 2.6 and later.
+#
+# DEFER_IF_REJECT optional text...
+# Defer the request if some later restriction would
+# result in a REJECT action. Reply with
+# "$access_map_defer_code 4.7.1 optional text..."
+# when the optional text is specified, otherwise
+# reply with a generic error response message.
+#
+# Prior to Postfix 2.6, the SMTP reply code is 450.
+#
+# This feature is available in Postfix 2.1 and later.
+#
+# DEFER_IF_PERMIT optional text...
+# Defer the request if some later restriction would
+# result in a an explicit or implicit PERMIT action.
+# Reply with "$access_map_defer_code 4.7.1 optional
+# text..." when the optional text is specified, oth-
+# erwise reply with a generic error response message.
+#
+# Prior to Postfix 2.6, the SMTP reply code is 450.
+#
+# This feature is available in Postfix 2.1 and later.
+#
+# OTHER ACTIONS
+# restriction...
+# Apply the named UCE restriction(s) (permit, reject,
+# reject_unauth_destination, and so on).
+#
+# BCC user@domain
+# Send one copy of the message to the specified
+# recipient.
+#
+# If multiple BCC actions are specified within the
+# same SMTP MAIL transaction, only the last action
+# will be used.
+#
+# This feature is not part of the stable Postfix
+# release.
+#
+# DISCARD optional text...
+# Claim successful delivery and silently discard the
+# message. Log the optional text if specified, oth-
+# erwise log a generic message.
+#
+# Note: this action currently affects all recipients
+# of the message. To discard only one recipient
+# without discarding the entire message, use the
+# transport(5) table to direct mail to the discard(8)
+# service.
+#
+# This feature is available in Postfix 2.0 and later.
+#
+# DUNNO Pretend that the lookup key was not found. This
+# prevents Postfix from trying substrings of the
+# lookup key (such as a subdomain name, or a network
+# address subnetwork).
+#
+# This feature is available in Postfix 2.0 and later.
+#
+# FILTER transport:destination
+# After the message is queued, send the entire mes-
+# sage through the specified external content filter.
+# The transport:destination syntax is described in
+# the transport(5) manual page. More information
+# about external content filters is in the Postfix
+# FILTER_README file.
+#
+# Note: this action overrides the content_filter set-
+# ting, and currently affects all recipients of the
+# message.
+#
+# This feature is available in Postfix 2.0 and later.
+#
+# HOLD optional text...
+# Place the message on the hold queue, where it will
+# sit until someone either deletes it or releases it
+# for delivery. Log the optional text if specified,
+# otherwise log a generic message.
+#
+# Mail that is placed on hold can be examined with
+# the postcat(1) command, and can be destroyed or
+# released with the postsuper(1) command.
+#
+# Note: use "postsuper -r" to release mail that was
+# kept on hold for a significant fraction of $maxi-
+# mal_queue_lifetime or $bounce_queue_lifetime, or
+# longer. Use "postsuper -H" only for mail that will
+# not expire within a few delivery attempts.
+#
+# Note: this action currently affects all recipients
+# of the message.
+#
+# This feature is available in Postfix 2.0 and later.
+#
+# PREPEND headername: headervalue
+# Prepend the specified message header to the mes-
+# sage. When more than one PREPEND action executes,
+# the first prepended header appears before the sec-
+# ond etc. prepended header.
+#
+# Note: this action must execute before the message
+# content is received; it cannot execute in the con-
+# text of smtpd_end_of_data_restrictions.
+#
+# This feature is available in Postfix 2.1 and later.
+#
+# REDIRECT user@domain
+# After the message is queued, send the message to
+# the specified address instead of the intended
+# recipient(s).
+#
+# Note: this action overrides the FILTER action, and
+# currently affects all recipients of the message.
+#
+# This feature is available in Postfix 2.1 and later.
+#
+# WARN optional text...
+# Log a warning with the optional text, together with
+# client information and if available, with helo,
+# sender, recipient and protocol information.
+#
+# This feature is available in Postfix 2.1 and later.
+#
+# ENHANCED STATUS CODES
+# Postfix version 2.3 and later support enhanced status
+# codes as defined in RFC 3463. When an enhanced status
+# code is specified in an access table, it is subject to
+# modification. The following transformations are needed
+# when the same access table is used for client, helo,
+# sender, or recipient access restrictions; they happen
+# regardless of whether Postfix replies to a MAIL FROM, RCPT
+# TO or other SMTP command.
+#
+# o When a sender address matches a REJECT action, the
+# Postfix SMTP server will transform a recipient DSN
+# status (e.g., 4.1.1-4.1.6) into the corresponding
+# sender DSN status, and vice versa.
+#
+# o When non-address information matches a REJECT
+# action (such as the HELO command argument or the
+# client hostname/address), the Postfix SMTP server
+# will transform a sender or recipient DSN status
+# into a generic non-address DSN status (e.g.,
+# 4.0.0).
+#
+# REGULAR EXPRESSION TABLES
+# This section describes how the table lookups change when
+# the table is given in the form of regular expressions. For
+# a description of regular expression lookup table syntax,
+# see regexp_table(5) or pcre_table(5).
+#
+# Each pattern is a regular expression that is applied to
+# the entire string being looked up. Depending on the appli-
+# cation, that string is an entire client hostname, an
+# entire client IP address, or an entire mail address. Thus,
+# no parent domain or parent network search is done,
+# user@domain mail addresses are not broken up into their
+# user@ and domain constituent parts, nor is user+foo broken
+# up into user and foo.
+#
+# Patterns are applied in the order as specified in the ta-
+# ble, until a pattern is found that matches the search
+# string.
+#
+# Actions are the same as with indexed file lookups, with
+# the additional feature that parenthesized substrings from
+# the pattern can be interpolated as $1, $2 and so on.
+#
+# TCP-BASED TABLES
+# This section describes how the table lookups change when
+# lookups are directed to a TCP-based server. For a descrip-
+# tion of the TCP client/server lookup protocol, see tcp_ta-
+# ble(5). This feature is not available up to and including
+# Postfix version 2.4.
+#
+# Each lookup operation uses the entire query string once.
+# Depending on the application, that string is an entire
+# client hostname, an entire client IP address, or an entire
+# mail address. Thus, no parent domain or parent network
+# search is done, user@domain mail addresses are not broken
+# up into their user@ and domain constituent parts, nor is
+# user+foo broken up into user and foo.
+#
+# Actions are the same as with indexed file lookups.
+#
+# EXAMPLE
+# The following example uses an indexed file, so that the
+# order of table entries does not matter. The example per-
+# mits access by the client at address 1.2.3.4 but rejects
+# all other clients in 1.2.3.0/24. Instead of hash lookup
+# tables, some systems use dbm. Use the command "postconf
+# -m" to find out what lookup tables Postfix supports on
+# your system.
+#
+# /etc/postfix/main.cf:
+# smtpd_client_restrictions =
+# check_client_access hash:/etc/postfix/access
+#
+# /etc/postfix/access:
+# 1.2.3 REJECT
+# 1.2.3.4 OK
+#
+# Execute the command "postmap /etc/postfix/access" after
+# editing the file.
+#
+# BUGS
+# The table format does not understand quoting conventions.
+#
+# SEE ALSO
+# postmap(1), Postfix lookup table manager
+# smtpd(8), SMTP server
+# postconf(5), configuration parameters
+# transport(5), transport:nexthop syntax
+#
+# README FILES
+# Use "postconf readme_directory" or "postconf html_direc-
+# tory" to locate this information.
+# SMTPD_ACCESS_README, built-in SMTP server access control
+# DATABASE_README, Postfix lookup table overview
+#
+# LICENSE
+# The Secure Mailer license must be distributed with this
+# software.
+#
+# AUTHOR(S)
+# Wietse Venema
+# IBM T.J. Watson Research
+# P.O. Box 704
+# Yorktown Heights, NY 10598, USA
+#
+# ACCESS(5)
diff --git a/install/config/postfix/canonical b/install/config/postfix/canonical
new file mode 100644
index 0000000..720db18
--- /dev/null
+++ b/install/config/postfix/canonical
@@ -0,0 +1,278 @@
+# CANONICAL(5) CANONICAL(5)
+#
+# NAME
+# canonical - Postfix canonical table format
+#
+# SYNOPSIS
+# postmap /etc/postfix/canonical
+#
+# postmap -q "string" /etc/postfix/canonical
+#
+# postmap -q - /etc/postfix/canonical $/
+# REJECT IFRAME vulnerability exploit
+#
+# SEE ALSO
+# cleanup(8), canonicalize and enqueue Postfix message
+# pcre_table(5), format of PCRE lookup tables
+# regexp_table(5), format of POSIX regular expression tables
+# postconf(1), Postfix configuration utility
+# postmap(1), Postfix lookup table management
+# postsuper(1), Postfix janitor
+# postcat(1), show Postfix queue file contents
+# RFC 2045, base64 and quoted-printable encoding rules
+# RFC 2047, message header encoding for non-ASCII text
+#
+# README FILES
+# Use "postconf readme_directory" or "postconf html_direc-
+# tory" to locate this information.
+# DATABASE_README, Postfix lookup table overview
+# CONTENT_INSPECTION_README, Postfix content inspection overview
+# BUILTIN_FILTER_README, Postfix built-in content inspection
+# BACKSCATTER_README, blocking returned forged mail
+#
+# LICENSE
+# The Secure Mailer license must be distributed with this
+# software.
+#
+# AUTHOR(S)
+# Wietse Venema
+# IBM T.J. Watson Research
+# P.O. Box 704
+# Yorktown Heights, NY 10598, USA
+#
+# HEADER_CHECKS(5)
diff --git a/install/config/postfix/main.cf b/install/config/postfix/main.cf
new file mode 100644
index 0000000..7e7f1d3
--- /dev/null
+++ b/install/config/postfix/main.cf
@@ -0,0 +1,746 @@
+# Global Postfix configuration file. This file lists only a subset
+# of all parameters. For the syntax, and for a complete parameter
+# list, see the postconf(5) manual page (command: "man 5 postconf").
+#
+# For common configuration examples, see BASIC_CONFIGURATION_README
+# and STANDARD_CONFIGURATION_README. To find these documents, use
+# the command "postconf html_directory readme_directory", or go to
+# http://www.postfix.org/.
+#
+# For best results, change no more than 2-3 parameters at a time,
+# and test if Postfix still works after every change.
+
+# SOFT BOUNCE
+#
+# The soft_bounce parameter provides a limited safety net for
+# testing. When soft_bounce is enabled, mail will remain queued that
+# would otherwise bounce. This parameter disables locally-generated
+# bounces, and prevents the SMTP server from rejecting mail permanently
+# (by changing 5xx replies into 4xx replies). However, soft_bounce
+# is no cure for address rewriting mistakes or mail routing mistakes.
+#
+#soft_bounce = no
+
+# LOCAL PATHNAME INFORMATION
+#
+# The queue_directory specifies the location of the Postfix queue.
+# This is also the root directory of Postfix daemons that run chrooted.
+# See the files in examples/chroot-setup for setting up Postfix chroot
+# environments on different UNIX systems.
+#
+queue_directory = /var/spool/postfix
+
+# The command_directory parameter specifies the location of all
+# postXXX commands.
+#
+command_directory = /usr/sbin
+
+# The daemon_directory parameter specifies the location of all Postfix
+# daemon programs (i.e. programs listed in the master.cf file). This
+# directory must be owned by root.
+#
+daemon_directory = /usr/libexec/postfix
+
+# The data_directory parameter specifies the location of Postfix-writable
+# data files (caches, random numbers). This directory must be owned
+# by the mail_owner account (see below).
+#
+data_directory = /var/lib/postfix
+
+# QUEUE AND PROCESS OWNERSHIP
+#
+# The mail_owner parameter specifies the owner of the Postfix queue
+# and of most Postfix daemon processes. Specify the name of a user
+# account THAT DOES NOT SHARE ITS USER OR GROUP ID WITH OTHER ACCOUNTS
+# AND THAT OWNS NO OTHER FILES OR PROCESSES ON THE SYSTEM. In
+# particular, don't specify nobody or daemon. PLEASE USE A DEDICATED
+# USER.
+#
+mail_owner = postfix
+
+# The default_privs parameter specifies the default rights used by
+# the local delivery agent for delivery to external file or command.
+# These rights are used in the absence of a recipient user context.
+# DO NOT SPECIFY A PRIVILEGED USER OR THE POSTFIX OWNER.
+#
+#default_privs = nobody
+
+# INTERNET HOST AND DOMAIN NAMES
+#
+# The myhostname parameter specifies the internet hostname of this
+# mail system. The default is to use the fully-qualified domain name
+# from gethostname(). $myhostname is used as a default value for many
+# other configuration parameters.
+#
+myhostname = mail.shopvd.cn
+#myhostname = virtual.domain.tld
+
+# The mydomain parameter specifies the local internet domain name.
+# The default is to use $myhostname minus the first component.
+# $mydomain is used as a default value for many other configuration
+# parameters.
+#
+mydomain = shopvd.cn
+
+# SENDING MAIL
+#
+# The myorigin parameter specifies the domain that locally-posted
+# mail appears to come from. The default is to append $myhostname,
+# which is fine for small sites. If you run a domain with multiple
+# machines, you should (1) change this to $mydomain and (2) set up
+# a domain-wide alias database that aliases each user to
+# user@that.users.mailhost.
+#
+# For the sake of consistency between sender and recipient addresses,
+# myorigin also specifies the default domain name that is appended
+# to recipient addresses that have no @domain part.
+#
+#myorigin = $myhostname
+myorigin = $myhostname
+
+# RECEIVING MAIL
+
+# The inet_interfaces parameter specifies the network interface
+# addresses that this mail system receives mail on. By default,
+# the software claims all active interfaces on the machine. The
+# parameter also controls delivery of mail to user@[ip.address].
+#
+# See also the proxy_interfaces parameter, for network addresses that
+# are forwarded to us via a proxy or network address translator.
+#
+# Note: you need to stop/start Postfix when this parameter changes.
+#
+#inet_interfaces = all
+#inet_interfaces = $myhostname
+#inet_interfaces = $myhostname, localhost
+#inet_interfaces = localhost
+
+# Enable IPv4, and IPv6 if supported
+#inet_protocols = all
+
+inet_protocols = ipv4
+
+# The proxy_interfaces parameter specifies the network interface
+# addresses that this mail system receives mail on by way of a
+# proxy or network address translation unit. This setting extends
+# the address list specified with the inet_interfaces parameter.
+#
+# You must specify your proxy/NAT addresses when your system is a
+# backup MX host for other domains, otherwise mail delivery loops
+# will happen when the primary MX host is down.
+#
+#proxy_interfaces =
+#proxy_interfaces = 1.2.3.4
+
+# The mydestination parameter specifies the list of domains that this
+# machine considers itself the final destination for.
+#
+# These domains are routed to the delivery agent specified with the
+# local_transport parameter setting. By default, that is the UNIX
+# compatible delivery agent that lookups all recipients in /etc/passwd
+# and /etc/aliases or their equivalent.
+#
+# The default is $myhostname + localhost.$mydomain. On a mail domain
+# gateway, you should also include $mydomain.
+#
+# Do not specify the names of virtual domains - those domains are
+# specified elsewhere (see VIRTUAL_README).
+#
+# Do not specify the names of domains that this machine is backup MX
+# host for. Specify those names via the relay_domains settings for
+# the SMTP server, or use permit_mx_backup if you are lazy (see
+# STANDARD_CONFIGURATION_README).
+#
+# The local machine is always the final destination for mail addressed
+# to user@[the.net.work.address] of an interface that the mail system
+# receives mail on (see the inet_interfaces parameter).
+#
+# Specify a list of host or domain names, /file/name or type:table
+# patterns, separated by commas and/or whitespace. A /file/name
+# pattern is replaced by its contents; a type:table is matched when
+# a name matches a lookup key (the right-hand side is ignored).
+# Continue long lines by starting the next line with whitespace.
+#
+# See also below, section "REJECTING MAIL FOR UNKNOWN LOCAL USERS".
+#
+mydestination = $myhostname, localhost.$mydomain, localhost
+#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
+#mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain,
+# mail.$mydomain, www.$mydomain, ftp.$mydomain
+
+# REJECTING MAIL FOR UNKNOWN LOCAL USERS
+#
+# The local_recipient_maps parameter specifies optional lookup tables
+# with all names or addresses of users that are local with respect
+# to $mydestination, $inet_interfaces or $proxy_interfaces.
+#
+# If this parameter is defined, then the SMTP server will reject
+# mail for unknown local users. This parameter is defined by default.
+#
+# To turn off local recipient checking in the SMTP server, specify
+# local_recipient_maps = (i.e. empty).
+#
+# The default setting assumes that you use the default Postfix local
+# delivery agent for local delivery. You need to update the
+# local_recipient_maps setting if:
+#
+# - You define $mydestination domain recipients in files other than
+# /etc/passwd, /etc/aliases, or the $virtual_alias_maps files.
+# For example, you define $mydestination domain recipients in
+# the $virtual_mailbox_maps files.
+#
+# - You redefine the local delivery agent in master.cf.
+#
+# - You redefine the "local_transport" setting in main.cf.
+#
+# - You use the "luser_relay", "mailbox_transport", or "fallback_transport"
+# feature of the Postfix local delivery agent (see local(8)).
+#
+# Details are described in the LOCAL_RECIPIENT_README file.
+#
+# Beware: if the Postfix SMTP server runs chrooted, you probably have
+# to access the passwd file via the proxymap service, in order to
+# overcome chroot restrictions. The alternative, having a copy of
+# the system passwd file in the chroot jail is just not practical.
+#
+# The right-hand side of the lookup tables is conveniently ignored.
+# In the left-hand side, specify a bare username, an @domain.tld
+# wild-card, or specify a user@domain.tld address.
+#
+#local_recipient_maps = unix:passwd.byname $alias_maps
+#local_recipient_maps = proxy:unix:passwd.byname $alias_maps
+#local_recipient_maps =
+
+# The unknown_local_recipient_reject_code specifies the SMTP server
+# response code when a recipient domain matches $mydestination or
+# ${proxy,inet}_interfaces, while $local_recipient_maps is non-empty
+# and the recipient address or address local-part is not found.
+#
+# The default setting is 550 (reject mail) but it is safer to start
+# with 450 (try again later) until you are certain that your
+# local_recipient_maps settings are OK.
+#
+unknown_local_recipient_reject_code = 550
+
+# TRUST AND RELAY CONTROL
+
+# The mynetworks parameter specifies the list of "trusted" SMTP
+# clients that have more privileges than "strangers".
+#
+# In particular, "trusted" SMTP clients are allowed to relay mail
+# through Postfix. See the smtpd_recipient_restrictions parameter
+# in postconf(5).
+#
+# You can specify the list of "trusted" network addresses by hand
+# or you can let Postfix do it for you (which is the default).
+#
+# By default (mynetworks_style = subnet), Postfix "trusts" SMTP
+# clients in the same IP subnetworks as the local machine.
+# On Linux, this does works correctly only with interfaces specified
+# with the "ifconfig" command.
+#
+# Specify "mynetworks_style = class" when Postfix should "trust" SMTP
+# clients in the same IP class A/B/C networks as the local machine.
+# Don't do this with a dialup site - it would cause Postfix to "trust"
+# your entire provider's network. Instead, specify an explicit
+# mynetworks list by hand, as described below.
+#
+# Specify "mynetworks_style = host" when Postfix should "trust"
+# only the local machine.
+#
+#mynetworks_style = class
+#mynetworks_style = subnet
+#mynetworks_style = host
+
+# Alternatively, you can specify the mynetworks list by hand, in
+# which case Postfix ignores the mynetworks_style setting.
+#
+# Specify an explicit list of network/netmask patterns, where the
+# mask specifies the number of bits in the network part of a host
+# address.
+#
+# You can also specify the absolute pathname of a pattern file instead
+# of listing the patterns here. Specify type:table for table-based lookups
+# (the value on the table right-hand side is not used).
+#
+#mynetworks = 168.100.189.0/28, 127.0.0.0/8
+mynetworks = 127.0.0.0/8
+#mynetworks = $config_directory/mynetworks
+#mynetworks = hash:/etc/postfix/network_table
+
+# The relay_domains parameter restricts what destinations this system will
+# relay mail to. See the smtpd_recipient_restrictions description in
+# postconf(5) for detailed information.
+#
+# By default, Postfix relays mail
+# - from "trusted" clients (IP address matches $mynetworks) to any destination,
+# - from "untrusted" clients to destinations that match $relay_domains or
+# subdomains thereof, except addresses with sender-specified routing.
+# The default relay_domains value is $mydestination.
+#
+# In addition to the above, the Postfix SMTP server by default accepts mail
+# that Postfix is final destination for:
+# - destinations that match $inet_interfaces or $proxy_interfaces,
+# - destinations that match $mydestination
+# - destinations that match $virtual_alias_domains,
+# - destinations that match $virtual_mailbox_domains.
+# These destinations do not need to be listed in $relay_domains.
+#
+# Specify a list of hosts or domains, /file/name patterns or type:name
+# lookup tables, separated by commas and/or whitespace. Continue
+# long lines by starting the next line with whitespace. A file name
+# is replaced by its contents; a type:name table is matched when a
+# (parent) domain appears as lookup key.
+#
+# NOTE: Postfix will not automatically forward mail for domains that
+# list this system as their primary or backup MX host. See the
+# permit_mx_backup restriction description in postconf(5).
+#
+#relay_domains = $mydestination
+
+# INTERNET OR INTRANET
+
+# The relayhost parameter specifies the default host to send mail to
+# when no entry is matched in the optional transport(5) table. When
+# no relayhost is given, mail is routed directly to the destination.
+#
+# On an intranet, specify the organizational domain name. If your
+# internal DNS uses no MX records, specify the name of the intranet
+# gateway host instead.
+#
+# In the case of SMTP, specify a domain, host, host:port, [host]:port,
+# [address] or [address]:port; the form [host] turns off MX lookups.
+#
+# If you're connected via UUCP, see also the default_transport parameter.
+#
+#relayhost = $mydomain
+#relayhost = [gateway.my.domain]
+#relayhost = [mailserver.isp.tld]
+#relayhost = uucphost
+#relayhost = [an.ip.add.ress]
+
+# REJECTING UNKNOWN RELAY USERS
+#
+# The relay_recipient_maps parameter specifies optional lookup tables
+# with all addresses in the domains that match $relay_domains.
+#
+# If this parameter is defined, then the SMTP server will reject
+# mail for unknown relay users. This feature is off by default.
+#
+# The right-hand side of the lookup tables is conveniently ignored.
+# In the left-hand side, specify an @domain.tld wild-card, or specify
+# a user@domain.tld address.
+#
+#relay_recipient_maps = hash:/etc/postfix/relay_recipients
+
+# INPUT RATE CONTROL
+#
+# The in_flow_delay configuration parameter implements mail input
+# flow control. This feature is turned on by default, although it
+# still needs further development (it's disabled on SCO UNIX due
+# to an SCO bug).
+#
+# A Postfix process will pause for $in_flow_delay seconds before
+# accepting a new message, when the message arrival rate exceeds the
+# message delivery rate. With the default 100 SMTP server process
+# limit, this limits the mail inflow to 100 messages a second more
+# than the number of messages delivered per second.
+#
+# Specify 0 to disable the feature. Valid delays are 0..10.
+#
+#in_flow_delay = 1s
+
+# ADDRESS REWRITING
+#
+# The ADDRESS_REWRITING_README document gives information about
+# address masquerading or other forms of address rewriting including
+# username->Firstname.Lastname mapping.
+
+# ADDRESS REDIRECTION (VIRTUAL DOMAIN)
+#
+# The VIRTUAL_README document gives information about the many forms
+# of domain hosting that Postfix supports.
+
+# "USER HAS MOVED" BOUNCE MESSAGES
+#
+# See the discussion in the ADDRESS_REWRITING_README document.
+
+# TRANSPORT MAP
+#
+# See the discussion in the ADDRESS_REWRITING_README document.
+
+# ALIAS DATABASE
+#
+# The alias_maps parameter specifies the list of alias databases used
+# by the local delivery agent. The default list is system dependent.
+#
+# On systems with NIS, the default is to search the local alias
+# database, then the NIS alias database. See aliases(5) for syntax
+# details.
+#
+# If you change the alias database, run "postalias /etc/aliases" (or
+# wherever your system stores the mail alias file), or simply run
+# "newaliases" to build the necessary DBM or DB file.
+#
+# It will take a minute or so before changes become visible. Use
+# "postfix reload" to eliminate the delay.
+#
+#alias_maps = dbm:/etc/aliases
+alias_maps = hash:/etc/aliases
+#alias_maps = hash:/etc/aliases, nis:mail.aliases
+#alias_maps = netinfo:/aliases
+
+# The alias_database parameter specifies the alias database(s) that
+# are built with "newaliases" or "sendmail -bi". This is a separate
+# configuration parameter, because alias_maps (see above) may specify
+# tables that are not necessarily all under control by Postfix.
+#
+#alias_database = dbm:/etc/aliases
+#alias_database = dbm:/etc/mail/aliases
+alias_database = hash:/etc/aliases
+#alias_database = hash:/etc/aliases, hash:/opt/majordomo/aliases
+
+# ADDRESS EXTENSIONS (e.g., user+foo)
+#
+# The recipient_delimiter parameter specifies the separator between
+# user names and address extensions (user+foo). See canonical(5),
+# local(8), relocated(5) and virtual(5) for the effects this has on
+# aliases, canonical, virtual, relocated and .forward file lookups.
+# Basically, the software tries user+foo and .forward+foo before
+# trying user and .forward.
+#
+recipient_delimiter = +
+
+# DELIVERY TO MAILBOX
+#
+# The home_mailbox parameter specifies the optional pathname of a
+# mailbox file relative to a user's home directory. The default
+# mailbox file is /var/spool/mail/user or /var/mail/user. Specify
+# "Maildir/" for qmail-style delivery (the / is required).
+#
+#home_mailbox = Mailbox
+home_mailbox = Maildir/
+
+# The mail_spool_directory parameter specifies the directory where
+# UNIX-style mailboxes are kept. The default setting depends on the
+# system type.
+#
+#mail_spool_directory = /var/mail
+#mail_spool_directory = /var/spool/mail
+
+# The mailbox_command parameter specifies the optional external
+# command to use instead of mailbox delivery. The command is run as
+# the recipient with proper HOME, SHELL and LOGNAME environment settings.
+# Exception: delivery for root is done as $default_user.
+#
+# Other environment variables of interest: USER (recipient username),
+# EXTENSION (address extension), DOMAIN (domain part of address),
+# and LOCAL (the address localpart).
+#
+# Unlike other Postfix configuration parameters, the mailbox_command
+# parameter is not subjected to $parameter substitutions. This is to
+# make it easier to specify shell syntax (see example below).
+#
+# Avoid shell meta characters because they will force Postfix to run
+# an expensive shell process. Procmail alone is expensive enough.
+#
+# IF YOU USE THIS TO DELIVER MAIL SYSTEM-WIDE, YOU MUST SET UP AN
+# ALIAS THAT FORWARDS MAIL FOR ROOT TO A REAL USER.
+#
+#mailbox_command = /some/where/procmail
+#mailbox_command = /some/where/procmail -a "$EXTENSION"
+
+# The mailbox_transport specifies the optional transport in master.cf
+# to use after processing aliases and .forward files. This parameter
+# has precedence over the mailbox_command, fallback_transport and
+# luser_relay parameters.
+#
+# Specify a string of the form transport:nexthop, where transport is
+# the name of a mail delivery transport defined in master.cf. The
+# :nexthop part is optional. For more details see the sample transport
+# configuration file.
+#
+# NOTE: if you use this feature for accounts not in the UNIX password
+# file, then you must update the "local_recipient_maps" setting in
+# the main.cf file, otherwise the SMTP server will reject mail for
+# non-UNIX accounts with "User unknown in local recipient table".
+#
+#mailbox_transport = lmtp:unix:/var/lib/imap/socket/lmtp
+
+# If using the cyrus-imapd IMAP server deliver local mail to the IMAP
+# server using LMTP (Local Mail Transport Protocol), this is prefered
+# over the older cyrus deliver program by setting the
+# mailbox_transport as below:
+#
+# mailbox_transport = lmtp:unix:/var/lib/imap/socket/lmtp
+#
+# The efficiency of LMTP delivery for cyrus-imapd can be enhanced via
+# these settings.
+#
+# local_destination_recipient_limit = 300
+# local_destination_concurrency_limit = 5
+#
+# Of course you should adjust these settings as appropriate for the
+# capacity of the hardware you are using. The recipient limit setting
+# can be used to take advantage of the single instance message store
+# capability of Cyrus. The concurrency limit can be used to control
+# how many simultaneous LMTP sessions will be permitted to the Cyrus
+# message store.
+#
+# To use the old cyrus deliver program you have to set:
+#mailbox_transport = cyrus
+
+# The fallback_transport specifies the optional transport in master.cf
+# to use for recipients that are not found in the UNIX passwd database.
+# This parameter has precedence over the luser_relay parameter.
+#
+# Specify a string of the form transport:nexthop, where transport is
+# the name of a mail delivery transport defined in master.cf. The
+# :nexthop part is optional. For more details see the sample transport
+# configuration file.
+#
+# NOTE: if you use this feature for accounts not in the UNIX password
+# file, then you must update the "local_recipient_maps" setting in
+# the main.cf file, otherwise the SMTP server will reject mail for
+# non-UNIX accounts with "User unknown in local recipient table".
+#
+#fallback_transport = lmtp:unix:/var/lib/imap/socket/lmtp
+#fallback_transport =
+
+# The luser_relay parameter specifies an optional destination address
+# for unknown recipients. By default, mail for unknown@$mydestination,
+# unknown@[$inet_interfaces] or unknown@[$proxy_interfaces] is returned
+# as undeliverable.
+#
+# The following expansions are done on luser_relay: $user (recipient
+# username), $shell (recipient shell), $home (recipient home directory),
+# $recipient (full recipient address), $extension (recipient address
+# extension), $domain (recipient domain), $local (entire recipient
+# localpart), $recipient_delimiter. Specify ${name?value} or
+# ${name:value} to expand value only when $name does (does not) exist.
+#
+# luser_relay works only for the default Postfix local delivery agent.
+#
+# NOTE: if you use this feature for accounts not in the UNIX password
+# file, then you must specify "local_recipient_maps =" (i.e. empty) in
+# the main.cf file, otherwise the SMTP server will reject mail for
+# non-UNIX accounts with "User unknown in local recipient table".
+#
+#luser_relay = $user@other.host
+#luser_relay = $local@other.host
+#luser_relay = admin+$local
+
+# JUNK MAIL CONTROLS
+#
+# The controls listed here are only a very small subset. The file
+# SMTPD_ACCESS_README provides an overview.
+
+# The header_checks parameter specifies an optional table with patterns
+# that each logical message header is matched against, including
+# headers that span multiple physical lines.
+#
+# By default, these patterns also apply to MIME headers and to the
+# headers of attached messages. With older Postfix versions, MIME and
+# attached message headers were treated as body text.
+#
+# For details, see "man header_checks".
+#
+#header_checks = regexp:/etc/postfix/header_checks
+
+# FAST ETRN SERVICE
+#
+# Postfix maintains per-destination logfiles with information about
+# deferred mail, so that mail can be flushed quickly with the SMTP
+# "ETRN domain.tld" command, or by executing "sendmail -qRdomain.tld".
+# See the ETRN_README document for a detailed description.
+#
+# The fast_flush_domains parameter controls what destinations are
+# eligible for this service. By default, they are all domains that
+# this server is willing to relay mail to.
+#
+#fast_flush_domains = $relay_domains
+
+# SHOW SOFTWARE VERSION OR NOT
+#
+# The smtpd_banner parameter specifies the text that follows the 220
+# code in the SMTP server's greeting banner. Some people like to see
+# the mail version advertised. By default, Postfix shows no version.
+#
+# You MUST specify $myhostname at the start of the text. That is an
+# RFC requirement. Postfix itself does not care.
+#
+#smtpd_banner = $myhostname ESMTP $mail_name
+#smtpd_banner = $myhostname ESMTP $mail_name ($mail_version)
+
+# PARALLEL DELIVERY TO THE SAME DESTINATION
+#
+# How many parallel deliveries to the same user or domain? With local
+# delivery, it does not make sense to do massively parallel delivery
+# to the same user, because mailbox updates must happen sequentially,
+# and expensive pipelines in .forward files can cause disasters when
+# too many are run at the same time. With SMTP deliveries, 10
+# simultaneous connections to the same domain could be sufficient to
+# raise eyebrows.
+#
+# Each message delivery transport has its XXX_destination_concurrency_limit
+# parameter. The default is $default_destination_concurrency_limit for
+# most delivery transports. For the local delivery agent the default is 2.
+
+#local_destination_concurrency_limit = 2
+#default_destination_concurrency_limit = 20
+
+# DEBUGGING CONTROL
+#
+# The debug_peer_level parameter specifies the increment in verbose
+# logging level when an SMTP client or server host name or address
+# matches a pattern in the debug_peer_list parameter.
+#
+debug_peer_level = 2
+
+# The debug_peer_list parameter specifies an optional list of domain
+# or network patterns, /file/name patterns or type:name tables. When
+# an SMTP client or server host name or address matches a pattern,
+# increase the verbose logging level by the amount specified in the
+# debug_peer_level parameter.
+#
+#debug_peer_list = 127.0.0.1
+#debug_peer_list = some.domain
+
+# The debugger_command specifies the external command that is executed
+# when a Postfix daemon program is run with the -D option.
+#
+# Use "command .. & sleep 5" so that the debugger can attach before
+# the process marches on. If you use an X-based debugger, be sure to
+# set up your XAUTHORITY environment variable before starting Postfix.
+#
+debugger_command =
+ PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
+ ddd $daemon_directory/$process_name $process_id & sleep 5
+
+# If you can't use X, use this to capture the call stack when a
+# daemon crashes. The result is in a file in the configuration
+# directory, and is named after the process name and the process ID.
+#
+# debugger_command =
+# PATH=/bin:/usr/bin:/usr/local/bin; export PATH; (echo cont;
+# echo where) | gdb $daemon_directory/$process_name $process_id 2>&1
+# >$config_directory/$process_name.$process_id.log & sleep 5
+#
+# Another possibility is to run gdb under a detached screen session.
+# To attach to the screen sesssion, su root and run "screen -r
+# " where uniquely matches one of the detached
+# sessions (from "screen -list").
+#
+# debugger_command =
+# PATH=/bin:/usr/bin:/sbin:/usr/sbin; export PATH; screen
+# -dmS $process_name gdb $daemon_directory/$process_name
+# $process_id & sleep 1
+
+# INSTALL-TIME CONFIGURATION INFORMATION
+#
+# The following parameters are used when installing a new Postfix version.
+#
+# sendmail_path: The full pathname of the Postfix sendmail command.
+# This is the Sendmail-compatible mail posting interface.
+#
+sendmail_path = /usr/sbin/sendmail.postfix
+
+# newaliases_path: The full pathname of the Postfix newaliases command.
+# This is the Sendmail-compatible command to build alias databases.
+#
+newaliases_path = /usr/bin/newaliases.postfix
+
+# mailq_path: The full pathname of the Postfix mailq command. This
+# is the Sendmail-compatible mail queue listing command.
+#
+mailq_path = /usr/bin/mailq.postfix
+
+# setgid_group: The group for mail submission and queue management
+# commands. This must be a group name with a numerical group ID that
+# is not shared with other accounts, not even with the Postfix account.
+#
+setgid_group = postdrop
+
+# html_directory: The location of the Postfix HTML documentation.
+#
+html_directory = no
+
+# manpage_directory: The location of the Postfix on-line manual pages.
+#
+manpage_directory = /usr/share/man
+
+# sample_directory: The location of the Postfix sample configuration files.
+# This parameter is obsolete as of Postfix 2.1.
+#
+sample_directory = /usr/share/doc/postfix-2.6.6/samples
+
+# readme_directory: The location of the Postfix README files.
+#
+readme_directory = /usr/share/doc/postfix-2.6.6/README_FILES
+
+biff = no
+
+smtpd_tls_key_file=/etc/ssl/private/dovecot.pem
+smtpd_tls_cert_file=/etc/ssl/certs/dovecot.pem
+smtpd_tls_CAfile = /etc/ssl/certs/dovecot.pem
+
+smtpd_sasl_type = dovecot
+smtpd_sasl_path = private/auth
+
+smtpd_sasl_auth_enable = yes
+smtpd_sasl_local_domain =
+smtpd_sasl_security_options=noanonymous
+smtpd_delay_reject = yes
+broken_sasl_auth_clients = yes
+
+#### TLS bits ####
+smtpd_tls_auth_only = no
+smtp_use_tls = yes
+smtpd_use_tls = yes
+smtp_tls_note_starttls_offer = yes
+
+smtpd_tls_security_level = may
+smtpd_tls_loglevel = 0
+smtpd_tls_session_cache_timeout = 3600s
+tls_random_source = dev:/dev/urandom
+tls_smtp_use_tls = yes
+
+smtpd_helo_required = yes
+smtpd_helo_restrictions = permit_mynetworks,permit_sasl_authenticated
+
+enable_original_recipient = no
+disable_vrfy_command = yes
+
+
+smtpd_sender_login_maps = mysql:/etc/postfix/mysql/mysql-sender-login-maps.cf
+
+smtpd_reject_unlisted_sender = yes
+
+smtpd_sender_restrictions = permit_mynetworks, reject_sender_login_mismatch, permit_sasl_authenticated
+recipient_bcc_maps = mysql:/etc/postfix/mysql/mysql_bcc_user.cf
+
+smtpd_recipient_restrictions = reject_unknown_sender_domain,reject_sender_login_mismatch,reject_authenticated_sender_login_mismatch,permit_sasl_authenticated,permit_mynetworks, reject_unauth_destination,reject_unknown_recipient_domain,check_policy_service unix:private/policy-spf
+
+virtual_mailbox_domains = mysql:/etc/postfix/mysql/mysql-mailbox-domains.cf
+virtual_mailbox_maps = mysql:/etc/postfix/mysql/mysql-mailbox-maps.cf
+virtual_alias_maps = mysql:/etc/postfix/mysql/mysql-alias-maps.cf
+
+
+virtual_transport = lmtp:unix:private/dovecot-lmtp
+smtp-amavis_destination_recipient_limit = 1
+
+mailbox_size_limit = 0
+
+#ֽ
+message_size_limit = 0
+content_filter = smtp-amavis:[127.0.0.1]:10024
+
+policy_time_limit = 3600
+
+#źͳʱ
+queue_run_delay = 200s
+minimal_backoff_time = 200s
+maximal_backoff_time = 300s
+
+bounce_queue_lifetime = 300s
+maximal_queue_lifetime = 300s
diff --git a/install/config/postfix/master.cf b/install/config/postfix/master.cf
new file mode 100644
index 0000000..060fbd9
--- /dev/null
+++ b/install/config/postfix/master.cf
@@ -0,0 +1,145 @@
+#
+# Postfix master process configuration file. For details on the format
+# of the file, see the master(5) manual page (command: "man 5 master").
+#
+# Do not forget to execute "postfix reload" after editing this file.
+#
+# ==========================================================================
+# service type private unpriv chroot wakeup maxproc command + args
+# (yes) (yes) (yes) (never) (100)
+# ==========================================================================
+smtp inet n - n - - smtpd
+#submission inet n - n - - smtpd
+# -o smtpd_tls_security_level=encrypt
+# -o smtpd_sasl_auth_enable=yes
+# -o smtpd_client_restrictions=permit_sasl_authenticated,reject
+# -o milter_macro_daemon_name=ORIGINATING
+smtps inet n - n - - smtpd
+ -o smtpd_tls_wrappermode=yes
+ -o smtpd_sasl_auth_enable=yes
+ -o smtpd_client_restrictions=permit_sasl_authenticated,reject
+# -o milter_macro_daemon_name=ORIGINATING
+#628 inet n - n - - qmqpd
+pickup fifo n - n 60 1 pickup
+cleanup unix n - n - 0 cleanup
+qmgr fifo n - n 300 1 qmgr
+#qmgr fifo n - n 300 1 oqmgr
+tlsmgr unix - - n 1000? 1 tlsmgr
+rewrite unix - - n - - trivial-rewrite
+bounce unix - - n - 0 bounce
+defer unix - - n - 0 bounce
+trace unix - - n - 0 bounce
+verify unix - - n - 1 verify
+flush unix n - n 1000? 0 flush
+proxymap unix - - n - - proxymap
+proxywrite unix - - n - 1 proxymap
+smtp unix - - n - - smtp
+# When relaying mail as backup MX, disable fallback_relay to avoid MX loops
+relay unix - - n - - smtp
+ -o smtp_fallback_relay=
+# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
+showq unix n - n - - showq
+error unix - - n - - error
+retry unix - - n - - error
+discard unix - - n - - discard
+local unix - n n - - local
+virtual unix - n n - - virtual
+lmtp unix - - n - - lmtp
+anvil unix - - n - 1 anvil
+scache unix - - n - 1 scache
+#
+# ====================================================================
+# Interfaces to non-Postfix software. Be sure to examine the manual
+# pages of the non-Postfix software to find out what options it wants.
+#
+# Many of the following services use the Postfix pipe(8) delivery
+# agent. See the pipe(8) man page for information about ${recipient}
+# and other message envelope options.
+# ====================================================================
+#
+# maildrop. See the Postfix MAILDROP_README file for details.
+# Also specify in main.cf: maildrop_destination_recipient_limit=1
+#
+#maildrop unix - n n - - pipe
+# flags=DRhu user=vmail argv=/usr/local/bin/maildrop -d ${recipient}
+#
+# ====================================================================
+#
+# The Cyrus deliver program has changed incompatibly, multiple times.
+#
+#old-cyrus unix - n n - - pipe
+# flags=R user=cyrus argv=/usr/lib/cyrus-imapd/deliver -e -m ${extension} ${user}
+#
+# ====================================================================
+#
+# Cyrus 2.1.5 (Amos Gouaux)
+# Also specify in main.cf: cyrus_destination_recipient_limit=1
+#
+#cyrus unix - n n - - pipe
+# user=cyrus argv=/usr/lib/cyrus-imapd/deliver -e -r ${sender} -m ${extension} ${user}
+#
+# ====================================================================
+#
+# See the Postfix UUCP_README file for configuration details.
+#
+#uucp unix - n n - - pipe
+# flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
+#
+# ====================================================================
+#
+# Other external delivery methods.
+#
+#ifmail unix - n n - - pipe
+# flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
+#
+#bsmtp unix - n n - - pipe
+# flags=Fq. user=bsmtp argv=/usr/local/sbin/bsmtp -f $sender $nexthop $recipient
+#
+#scalemail-backend unix - n n - 2 pipe
+# flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store
+# ${nexthop} ${user} ${extension}
+#
+#mailman unix - n n - - pipe
+# flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
+# ${nexthop} ${user}
+
+## spf check
+policy-spf unix - n n - - spawn
+ user=nobody argv=/usr/bin/perl /usr/libexec/postfix/postfix-policyd-spf-perl
+
+submission inet n - n - - smtpd
+ -o smtpd_tls_security_level=encrypt
+ -o smtpd_sasl_auth_enable=yes
+ -o smtpd_sasl_type=dovecot
+ -o smtpd_sasl_path=private/auth
+ -o smtpd_client_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
+# -o content_filter=smtp-amavis:[127.0.0.1]:10026
+
+
+smtp-amavis unix - - - - 2 smtp
+ -o smtp_data_done_timeout=1200
+ -o smtp_send_xforward_command=yes
+ -o disable_dns_lookups=yes
+ -o max_use=20
+
+127.0.0.1:10025 inet n - - - - smtpd
+ -o content_filter=
+ -o local_recipient_maps=
+ -o relay_recipient_maps=
+ -o smtpd_restriction_classes=
+ -o smtpd_delay_reject=no
+ -o smtpd_tls_security_level=none
+ -o smtpd_client_restrictions=permit_mynetworks,reject
+ -o smtpd_helo_restrictions=
+ -o smtpd_sender_restrictions=
+ -o smtpd_recipient_restrictions=permit_mynetworks,reject
+ -o smtpd_end_of_data_restrictions=
+ -o mynetworks_style=host
+ -o mynetworks=127.0.0.0/8
+ -o strict_rfc821_envelopes=yes
+ -o smtpd_error_sleep_time=0
+ -o smtpd_soft_error_limit=1001
+ -o smtpd_hard_error_limit=1000
+ -o smtpd_client_connection_count_limit=0
+ -o smtpd_client_connection_rate_limit=0
+ -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_address_mappings
diff --git a/install/config/postfix/mysql/mysql-alias-maps.cf b/install/config/postfix/mysql/mysql-alias-maps.cf
new file mode 100644
index 0000000..a444ffa
--- /dev/null
+++ b/install/config/postfix/mysql/mysql-alias-maps.cf
@@ -0,0 +1,5 @@
+user = ewomail
+password = 123456
+hosts = 127.0.0.1
+dbname = ewomail
+query = SELECT destination FROM i_aliases WHERE source='%s'
\ No newline at end of file
diff --git a/install/config/postfix/mysql/mysql-mailbox-domains.cf b/install/config/postfix/mysql/mysql-mailbox-domains.cf
new file mode 100644
index 0000000..e8baf91
--- /dev/null
+++ b/install/config/postfix/mysql/mysql-mailbox-domains.cf
@@ -0,0 +1,5 @@
+user = ewomail
+password = 123456
+hosts = 127.0.0.1
+dbname = ewomail
+query = SELECT 1 FROM i_domains WHERE name='%s' and active=1
\ No newline at end of file
diff --git a/install/config/postfix/mysql/mysql-mailbox-maps.cf b/install/config/postfix/mysql/mysql-mailbox-maps.cf
new file mode 100644
index 0000000..59daeeb
--- /dev/null
+++ b/install/config/postfix/mysql/mysql-mailbox-maps.cf
@@ -0,0 +1,5 @@
+user = ewomail
+password = 123456
+hosts = 127.0.0.1
+dbname = ewomail
+query = SELECT email FROM i_users WHERE email='%s' and active=1
\ No newline at end of file
diff --git a/install/config/postfix/mysql/mysql-sender-login-maps.cf b/install/config/postfix/mysql/mysql-sender-login-maps.cf
new file mode 100644
index 0000000..59daeeb
--- /dev/null
+++ b/install/config/postfix/mysql/mysql-sender-login-maps.cf
@@ -0,0 +1,5 @@
+user = ewomail
+password = 123456
+hosts = 127.0.0.1
+dbname = ewomail
+query = SELECT email FROM i_users WHERE email='%s' and active=1
\ No newline at end of file
diff --git a/install/config/postfix/mysql/mysql_bcc_user.cf b/install/config/postfix/mysql/mysql_bcc_user.cf
new file mode 100644
index 0000000..ea3ae63
--- /dev/null
+++ b/install/config/postfix/mysql/mysql_bcc_user.cf
@@ -0,0 +1,5 @@
+user = ewomail
+password = 123456
+hosts = 127.0.0.1
+dbname = ewomail
+query = SELECT to_email FROM i_bcc_user WHERE source='%s'
\ No newline at end of file
diff --git a/install/config/postfix/relocated b/install/config/postfix/relocated
new file mode 100644
index 0000000..3fcab4c
--- /dev/null
+++ b/install/config/postfix/relocated
@@ -0,0 +1,171 @@
+# RELOCATED(5) RELOCATED(5)
+#
+# NAME
+# relocated - Postfix relocated table format
+#
+# SYNOPSIS
+# postmap /etc/postfix/relocated
+#
+# DESCRIPTION
+# The optional relocated(5) table provides the information
+# that is used in "user has moved to new_location" bounce
+# messages.
+#
+# Normally, the relocated(5) table is specified as a text
+# file that serves as input to the postmap(1) command. The
+# result, an indexed file in dbm or db format, is used for
+# fast searching by the mail system. Execute the command
+# "postmap /etc/postfix/relocated" to rebuild an indexed
+# file after changing the corresponding relocated table.
+#
+# When the table is provided via other means such as NIS,
+# LDAP or SQL, the same lookups are done as for ordinary
+# indexed files.
+#
+# Alternatively, the table can be provided as a regular-
+# expression map where patterns are given as regular expres-
+# sions, or lookups can be directed to TCP-based server. In
+# those case, the lookups are done in a slightly different
+# way as described below under "REGULAR EXPRESSION TABLES"
+# or "TCP-BASED TABLES".
+#
+# Table lookups are case insensitive.
+#
+# CASE FOLDING
+# The search string is folded to lowercase before database
+# lookup. As of Postfix 2.3, the search string is not case
+# folded with database types such as regexp: or pcre: whose
+# lookup fields can match both upper and lower case.
+#
+# TABLE FORMAT
+# The input format for the postmap(1) command is as follows:
+#
+# o An entry has one of the following form:
+#
+# pattern new_location
+#
+# Where new_location specifies contact information
+# such as an email address, or perhaps a street
+# address or telephone number.
+#
+# o Empty lines and whitespace-only lines are ignored,
+# as are lines whose first non-whitespace character
+# is a `#'.
+#
+# o A logical line starts with non-whitespace text. A
+# line that starts with whitespace continues a logi-
+# cal line.
+#
+# TABLE SEARCH ORDER
+# With lookups from indexed files such as DB or DBM, or from
+# networked tables such as NIS, LDAP or SQL, patterns are
+# tried in the order as listed below:
+#
+# user@domain
+# Matches user@domain. This form has precedence over
+# all other forms.
+#
+# user Matches user@site when site is $myorigin, when site
+# is listed in $mydestination, or when site is listed
+# in $inet_interfaces or $proxy_interfaces.
+#
+# @domain
+# Matches other addresses in domain. This form has
+# the lowest precedence.
+#
+# ADDRESS EXTENSION
+# When a mail address localpart contains the optional recip-
+# ient delimiter (e.g., user+foo@domain), the lookup order
+# becomes: user+foo@domain, user@domain, user+foo, user, and
+# @domain.
+#
+# REGULAR EXPRESSION TABLES
+# This section describes how the table lookups change when
+# the table is given in the form of regular expressions or
+# when lookups are directed to a TCP-based server. For a
+# description of regular expression lookup table syntax, see
+# regexp_table(5) or pcre_table(5). For a description of the
+# TCP client/server table lookup protocol, see tcp_table(5).
+# This feature is not available up to and including Postfix
+# version 2.4.
+#
+# Each pattern is a regular expression that is applied to
+# the entire address being looked up. Thus, user@domain mail
+# addresses are not broken up into their user and @domain
+# constituent parts, nor is user+foo broken up into user and
+# foo.
+#
+# Patterns are applied in the order as specified in the ta-
+# ble, until a pattern is found that matches the search
+# string.
+#
+# Results are the same as with indexed file lookups, with
+# the additional feature that parenthesized substrings from
+# the pattern can be interpolated as $1, $2 and so on.
+#
+# TCP-BASED TABLES
+# This section describes how the table lookups change when
+# lookups are directed to a TCP-based server. For a descrip-
+# tion of the TCP client/server lookup protocol, see tcp_ta-
+# ble(5). This feature is not available up to and including
+# Postfix version 2.4.
+#
+# Each lookup operation uses the entire address once. Thus,
+# user@domain mail addresses are not broken up into their
+# user and @domain constituent parts, nor is user+foo broken
+# up into user and foo.
+#
+# Results are the same as with indexed file lookups.
+#
+# BUGS
+# The table format does not understand quoting conventions.
+#
+# CONFIGURATION PARAMETERS
+# The following main.cf parameters are especially relevant.
+# The text below provides only a parameter summary. See
+# postconf(5) for more details including examples.
+#
+# relocated_maps
+# List of lookup tables for relocated users or sites.
+#
+# Other parameters of interest:
+#
+# inet_interfaces
+# The network interface addresses that this system
+# receives mail on. You need to stop and start Post-
+# fix when this parameter changes.
+#
+# mydestination
+# List of domains that this mail system considers
+# local.
+#
+# myorigin
+# The domain that is appended to locally-posted mail.
+#
+# proxy_interfaces
+# Other interfaces that this machine receives mail on
+# by way of a proxy agent or network address transla-
+# tor.
+#
+# SEE ALSO
+# trivial-rewrite(8), address resolver
+# postmap(1), Postfix lookup table manager
+# postconf(5), configuration parameters
+#
+# README FILES
+# Use "postconf readme_directory" or "postconf html_direc-
+# tory" to locate this information.
+# DATABASE_README, Postfix lookup table overview
+# ADDRESS_REWRITING_README, address rewriting guide
+#
+# LICENSE
+# The Secure Mailer license must be distributed with this
+# software.
+#
+# AUTHOR(S)
+# Wietse Venema
+# IBM T.J. Watson Research
+# P.O. Box 704
+# Yorktown Heights, NY 10598, USA
+#
+# RELOCATED(5)
diff --git a/install/config/postfix/transport b/install/config/postfix/transport
new file mode 100644
index 0000000..0544b27
--- /dev/null
+++ b/install/config/postfix/transport
@@ -0,0 +1,293 @@
+# TRANSPORT(5) TRANSPORT(5)
+#
+# NAME
+# transport - Postfix transport table format
+#
+# SYNOPSIS
+# postmap /etc/postfix/transport
+#
+# postmap -q "string" /etc/postfix/transport
+#
+# postmap -q - /etc/postfix/transport
+// +----------------------------------------------------------------------
+
+class init{
+
+ public $db;
+
+ public $domain = 'ewomail.cn';
+
+ //数据库名字
+ public $mail_db = 'ewomail';
+ //数据库账号
+ public $mail_db_username = 'ewomail';
+
+ public $root_pwd;
+
+ public $mail_pwd;
+
+ public function __construct($domain){
+
+ if(!$domain){
+ die("Missing domain parameter");
+ }
+
+ $this->domain = $domain;
+ $this->db = new mysqli('127.0.0.1','root','','mysql');
+ if ($this->db->connect_error) {
+ die('Connect Error('.$this->db->connect_errno.')'.$this->db->connect_error);
+ }
+ if (!$this->db->set_charset("utf8")) {
+ die("Error loading character set utf8: ".$this->db->error);
+ }
+
+ $this->import_sql();
+ $this->update_mail_config();
+ $this->update_password();
+ $this->update_file();
+ $this->ending();
+
+ echo "the configuration succeeds\n";
+
+ }
+
+ /**
+ * 结束后更新文件
+ * */
+ public function ending()
+ {
+ $info = "domain:".$this->domain."\n";
+ $info .= "mysql-root-password:".$this->root_pwd."\n";
+ $info .= "mysql-ewomail-password:".$this->mail_pwd."\n";
+ file_put_contents("/ewomail/config.ini",$info);
+ }
+
+ /**
+ * 更新数据库密码
+ * */
+ public function update_password()
+ {
+ $this->db->select_db('mysql');
+ $root_pwd = $this->create_password();
+ $mail_pwd = $this->create_password();
+ $this->root_pwd = $root_pwd;
+ $this->mail_pwd = $mail_pwd;
+
+ $this->db->query("GRANT all privileges on *.* TO '{$this->mail_db_username}'@'localhost' IDENTIFIED BY '$mail_pwd'");
+ $this->db->query("GRANT all privileges on *.* TO '{$this->mail_db_username}'@'127.0.0.1' IDENTIFIED BY '$mail_pwd'");
+
+ $this->db->query("UPDATE user SET password=PASSWORD('$root_pwd') WHERE user='root'");
+ $this->db->query("FLUSH PRIVILEGES");
+
+ $this->update_password_file($mail_pwd);
+
+ }
+
+ /**
+ * 修改相关数据库的文件配置
+ * */
+ public function update_password_file($password)
+ {
+ //修改dovecot数据库配置
+ $dovecot_conf = [
+ '/etc/dovecot/dovecot-sql.conf.ext',
+ '/etc/dovecot/dovecot-dict-sql.conf.ext',
+ ];
+
+ foreach($dovecot_conf as $conf){
+ $this->op_file($conf,function($line)use($password){
+ if (trim($line) == '') {
+ return $line;
+ }
+ if(preg_match('/^connect/',$line)){
+ $c = preg_replace("/password=.+/","password=".$password,$line);
+ }else{
+ $c = $line;
+ }
+ return $c;
+ });
+ }
+
+ $postfix_conf = [
+ '/etc/postfix/mysql/mysql_bcc_user.cf',
+ '/etc/postfix/mysql/mysql-alias-maps.cf',
+ '/etc/postfix/mysql/mysql-mailbox-domains.cf',
+ '/etc/postfix/mysql/mysql-mailbox-maps.cf',
+ '/etc/postfix/mysql/mysql-sender-login-maps.cf'
+ ];
+
+ foreach($postfix_conf as $conf){
+ $this->op_file($conf,function($line)use($password){
+ if (trim($line) == '') {
+ return $line;
+ }
+ if(preg_match('/^password/',$line)){
+ $c = "password = ".$password."\n";
+ }else{
+ $c = $line;
+ }
+ return $c;
+ });
+ }
+
+
+ //修改ewomail配置文件
+ $conf = '/ewomail/www/ewomail-admin/core/config.php';
+ $this->op_file($conf,function($line)use($password){
+ if (trim($line) == '') {
+ return $line;
+ }
+ if(preg_match("/'dbpw'/",$line)){
+ $c = preg_replace("/'dbpw'.+/","'dbpw' => '".$password."',",$line);
+ }else if(preg_match("/'code_key'/",$line)){
+ $c = preg_replace("/'code_key'.+/","'code_key' => '".$this->create_password()."',",$line);
+ }else if(preg_match("/'url'/",$line)){
+ $url = "http://mail.".$this->domain.":8010";
+ $c = preg_replace("/'url'.+/","'url' => '$url',",$line);
+ }else if(preg_match("/'webmail_url'/",$line)){
+ $url = "http://mail.".$this->domain.":8000";
+ $c = preg_replace("/'webmail_url'.+/","'webmail_url' => '$url',",$line);
+ }else{
+ $c = $line;
+ }
+ return $c;
+ });
+
+ }
+
+ /**
+ * 修改配置文件
+ * */
+ public function update_file()
+ {
+ $amavisd_conf = '/etc/amavisd/amavisd.conf';
+ $this->op_file($amavisd_conf,function($line){
+ if (trim($line) == '') {
+ return $line;
+ }
+
+ if(preg_match('/^\\$mydomain/',$line)){
+ $c = "\$mydomain = '{$this->domain}';\n";
+ }else if(preg_match('/\\$myhostname/',$line)){
+ $c = "\$myhostname = 'mail.{$this->domain}';\n";
+ }else if(preg_match('/\\$final_virus_destiny/',$line)){
+ $c = "#".$line;
+ }else if(preg_match('/\\$final_banned_destiny/',$line)){
+ //$c = "\$final_banned_destiny = D_PASS;\n";
+ $c = "#".$line;
+ }else if(preg_match('/\\$final_spam_destiny/',$line)){
+ $c = "#".$line;
+ }else if(preg_match('/\\$final_bad_header_destiny/',$line)){
+ //$c = "\$final_bad_header_destiny = D_PASS;\n";
+ $c = "#".$line;
+ }else{
+ $c = $line;
+ }
+ return $c;
+ });
+
+ $amavisd_str = file_get_contents($amavisd_conf);
+ $amavisd_out = '$inet_socket_bind = "127.0.0.1";'."\n";
+ $amavisd_out .= '$signed_header_fields{\'received\'} = 0;
+$signed_header_fields{\'to\'} = 1;
+$originating = 1;
+
+# Add dkim_key here.
+dkim_key("'.$this->domain.'", "dkim", "/ewomail/dkim/mail.pem");
+
+@dkim_signature_options_bysender_maps = ({
+# catchall defaults
+\'.\' => {c => \'relaxed/simple\', ttl => 30*24*3600 },
+} );';
+ file_put_contents($amavisd_conf,$amavisd_str."\n".$amavisd_out);
+
+ $postfix_conf = "/etc/postfix/main.cf";
+ $this->op_file($postfix_conf,function($line){
+ if (trim($line) == '') {
+ return $line;
+ }
+
+ if(preg_match('/^mydomain/',$line)){
+ $c = "mydomain = {$this->domain}\n";
+ }else if(preg_match('/^myhostname/',$line)){
+ $c = "myhostname = mail.{$this->domain}\n";
+ }else{
+ $c = $line;
+ }
+ return $c;
+ });
+
+ //fail2ban
+ $fail2ban_conf = "/etc/fail2ban/fail2ban.conf";
+ $this->op_file($fail2ban_conf,function($line){
+ if (trim($line) == '') {
+ return $line;
+ }
+
+ if(preg_match('/^logtarget/',$line)){
+ $c = "logtarget = /var/log/fail2ban.log\n";
+ }else{
+ $c = $line;
+ }
+ return $c;
+ });
+
+ //apache
+ $apache_conf = '/ewomail/apache/conf/extra/httpd-vhosts.conf';
+ $apache_str = "
+Listen 8000
+Listen 8010
+Listen 8020
+
+
+ServerName localhost
+DocumentRoot /ewomail/www/ewomail-admin/
+DirectoryIndex index.php index.html index.htm
+
+Options +Includes -Indexes
+AllowOverride All
+Order Deny,Allow
+Allow from All
+
+
+
+
+ServerName localhost
+DocumentRoot /ewomail/www/rainloop/
+DirectoryIndex index.php index.html index.htm
+
+Options +Includes -Indexes
+AllowOverride All
+Order Deny,Allow
+Allow from All
+
+
+
+
+ServerName localhost
+DocumentRoot /ewomail/www/phpMyAdmin/
+DirectoryIndex index.php index.html index.htm
+
+Options +Includes -Indexes
+AllowOverride All
+Order Deny,Allow
+Allow from All
+
+
+ ";
+
+ if(copy($apache_conf,$apache_conf.".backup")){
+ file_put_contents($apache_conf,$apache_str);
+ }
+
+ }
+
+ public function op_file($file,$fun)
+ {
+ $f = fopen($file,"r");
+ $c = '';
+ if($f){
+ copy($file,$file.".backup");
+ while (!feof($f)) {
+ $line = fgets($f);
+ $c .= $fun($line);
+ }
+
+ fclose($f);
+ file_put_contents($file,$c);
+ }
+
+ }
+
+ /**
+ * 导入备份
+ * */
+ public function import_sql()
+ {
+ $sql_file = '/ewomail/www/ewomail-admin/upload/install.sql';
+ $file = fopen($sql_file,"r");
+ if(!$file){
+ die("Data file read failed");
+ }
+ $sqlArr = [];
+ $sql = '';
+ $t = false;
+ while (!feof($file)) {
+ $line = fgets($file);
+ if (trim($line) == '') {
+ continue;
+ }
+
+ if(preg_match('/^DROP TABLE IF EXISTS.+;/i',$line)){
+ $sqlArr[] = $line;
+ }
+
+ if(preg_match('/^CREATE TABLE.+/i',$line)){
+ $t = true;
+ }
+ if($t){
+ $sql .= $line;
+ if(preg_match('/ENGINE.+;/i',$line)){
+ $sqlArr[] = $sql;
+ $sql = '';
+ $t = false;
+ }
+ }
+
+ if(preg_match('/^INSERT.+;/i',$line)){
+ $sqlArr[] = $line;
+ }
+
+ }
+
+ $r = $this->db->query("CREATE DATABASE IF NOT EXISTS ".$this->mail_db." DEFAULT CHARSET utf8 COLLATE utf8_general_ci");
+ if(!$r){
+ die('Database creation failed');
+ }
+
+ if(!$this->db->select_db($this->mail_db)){
+ die('Database switch failed');
+ }
+
+ foreach($sqlArr as $v){
+ if(!$this->db->query($v)){
+ echo $v."\n";
+ echo $this->db->error;
+ exit;
+ }
+ }
+
+ @unlink($sql_file);
+ }
+
+ /**
+ * 修改数据里的mail配置
+ * */
+ public function update_mail_config()
+ {
+ //修改相关配置数据
+ $imap = 'imap.'.$this->domain;
+ $smtp = 'smtp.'.$this->domain;
+ $mydomain = $this->domain;
+ $myhostname = 'mail.'.$this->domain;
+ $this->db->query("update i_mail_config set value='$imap' where name='imap'");
+ $this->db->query("update i_mail_config set value='$smtp' where name='smtp'");
+ $this->db->query("update i_mail_config set value='$mydomain' where name='mydomain'");
+ $this->db->query("update i_mail_config set value='$myhostname' where name='myhostname'");
+ $this->db->query("INSERT INTO i_domains (name,active,ctime) VALUES('$mydomain',1,NOW())");
+ }
+
+ /**
+ * 创建密码
+ * */
+ function create_password( $length = 16 ) {
+ // 密码字符集,可任意添加你需要的字符
+ $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+
+ $password = '';
+ for ( $i = 0; $i < $length; $i++ )
+ {
+ // 这里提供两种字符获取方式
+ // 第一种是使用 substr 截取$chars中的任意一位字符;
+ // 第二种是取字符数组 $chars 的任意元素
+ // $password .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
+ $password .= $chars[ mt_rand(0, strlen($chars) - 1) ];
+ }
+
+ return $password;
+ }
+}
+
+$init = new init($argv[1]);
+$init->db->close();
+?>
\ No newline at end of file
diff --git a/install/soft/RPM-GPG-KEY-EPEL-6 b/install/soft/RPM-GPG-KEY-EPEL-6
new file mode 100644
index 0000000..7a20304
--- /dev/null
+++ b/install/soft/RPM-GPG-KEY-EPEL-6
@@ -0,0 +1,29 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.5 (GNU/Linux)
+
+mQINBEvSKUIBEADLGnUj24ZVKW7liFN/JA5CgtzlNnKs7sBg7fVbNWryiE3URbn1
+JXvrdwHtkKyY96/ifZ1Ld3lE2gOF61bGZ2CWwJNee76Sp9Z+isP8RQXbG5jwj/4B
+M9HK7phktqFVJ8VbY2jfTjcfxRvGM8YBwXF8hx0CDZURAjvf1xRSQJ7iAo58qcHn
+XtxOAvQmAbR9z6Q/h/D+Y/PhoIJp1OV4VNHCbCs9M7HUVBpgC53PDcTUQuwcgeY6
+pQgo9eT1eLNSZVrJ5Bctivl1UcD6P6CIGkkeT2gNhqindRPngUXGXW7Qzoefe+fV
+QqJSm7Tq2q9oqVZ46J964waCRItRySpuW5dxZO34WM6wsw2BP2MlACbH4l3luqtp
+Xo3Bvfnk+HAFH3HcMuwdaulxv7zYKXCfNoSfgrpEfo2Ex4Im/I3WdtwME/Gbnwdq
+3VJzgAxLVFhczDHwNkjmIdPAlNJ9/ixRjip4dgZtW8VcBCrNoL+LhDrIfjvnLdRu
+vBHy9P3sCF7FZycaHlMWP6RiLtHnEMGcbZ8QpQHi2dReU1wyr9QgguGU+jqSXYar
+1yEcsdRGasppNIZ8+Qawbm/a4doT10TEtPArhSoHlwbvqTDYjtfV92lC/2iwgO6g
+YgG9XrO4V8dV39Ffm7oLFfvTbg5mv4Q/E6AWo/gkjmtxkculbyAvjFtYAQARAQAB
+tCFFUEVMICg2KSA8ZXBlbEBmZWRvcmFwcm9qZWN0Lm9yZz6JAjYEEwECACAFAkvS
+KUICGw8GCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRA7Sd8qBgi4lR/GD/wLGPv9
+qO39eyb9NlrwfKdUEo1tHxKdrhNz+XYrO4yVDTBZRPSuvL2yaoeSIhQOKhNPfEgT
+9mdsbsgcfmoHxmGVcn+lbheWsSvcgrXuz0gLt8TGGKGGROAoLXpuUsb1HNtKEOwP
+Q4z1uQ2nOz5hLRyDOV0I2LwYV8BjGIjBKUMFEUxFTsL7XOZkrAg/WbTH2PW3hrfS
+WtcRA7EYonI3B80d39ffws7SmyKbS5PmZjqOPuTvV2F0tMhKIhncBwoojWZPExft
+HpKhzKVh8fdDO/3P1y1Fk3Cin8UbCO9MWMFNR27fVzCANlEPljsHA+3Ez4F7uboF
+p0OOEov4Yyi4BEbgqZnthTG4ub9nyiupIZ3ckPHr3nVcDUGcL6lQD/nkmNVIeLYP
+x1uHPOSlWfuojAYgzRH6LL7Idg4FHHBA0to7FW8dQXFIOyNiJFAOT2j8P5+tVdq8
+wB0PDSH8yRpn4HdJ9RYquau4OkjluxOWf0uRaS//SUcCZh+1/KBEOmcvBHYRZA5J
+l/nakCgxGb2paQOzqqpOcHKvlyLuzO5uybMXaipLExTGJXBlXrbbASfXa/yGYSAG
+iVrGz9CE6676dMlm8F+s3XXE13QZrXmjloc6jwOljnfAkjTGXjiB7OULESed96MR
+XtfLk0W5Ab9pd7tKDR6QHI7rgHXfCopRnZ2VVQ==
+=V/6I
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/install/soft/centos7-dovecot-2.2.24-el6.x86_64.rpm b/install/soft/centos7-dovecot-2.2.24-el6.x86_64.rpm
new file mode 100644
index 0000000..fc3527c
Binary files /dev/null and b/install/soft/centos7-dovecot-2.2.24-el6.x86_64.rpm differ
diff --git a/install/soft/dovecot-2.2.24-el6.x86_64.rpm b/install/soft/dovecot-2.2.24-el6.x86_64.rpm
new file mode 100644
index 0000000..bd7b424
Binary files /dev/null and b/install/soft/dovecot-2.2.24-el6.x86_64.rpm differ
diff --git a/install/soft/dovecot.init b/install/soft/dovecot.init
new file mode 100644
index 0000000..2a06c75
--- /dev/null
+++ b/install/soft/dovecot.init
@@ -0,0 +1,72 @@
+### BEGIN INIT INFO
+# Provides: dovecot
+# Required-Start: $local_fs $remote_fs $network $syslog $time
+# Required-Stop: $local_fs $remote_fs $network $syslog
+# Should-Start: postgresql mysql slapd winbind
+# Should-Stop: postgresql mysql slapd winbind
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Dovecot init script
+# Description: Init script for dovecot services
+### END INIT INFO
+
+# Example /etc/init.d/dovecot script. Change DAEMON if necessary.
+# License is public domain.
+
+DAEMON=/usr/local/dovecot/sbin/dovecot
+
+# Uncomment to allow Dovecot daemons to produce core dumps.
+#ulimit -c unlimited
+
+test -x $DAEMON || exit 1
+set -e
+
+base_dir=`$DAEMON config -h base_dir`
+pidfile=$base_dir/master.pid
+
+if test -f $pidfile; then
+ running=yes
+else
+ running=no
+fi
+
+case "$1" in
+ start)
+ echo -n "Starting Dovecot"
+ $DAEMON
+ echo "."
+ ;;
+ stop)
+ if test $running = yes; then
+ echo "Stopping Dovecot"
+ kill `cat $pidfile`
+ echo "."
+ else
+ echo "Dovecot is already stopped."
+ fi
+ ;;
+ reload)
+ if test $running = yes; then
+ echo -n "Reloading Dovecot configuration"
+ kill -HUP `cat $pidfile`
+ echo "."
+ else
+ echo "Dovecot isn't running."
+ fi
+ ;;
+ restart|force-reload)
+ echo -n "Restarting Dovecot"
+ if test $running = yes; then
+ kill `cat $pidfile`
+ sleep 1
+ fi
+ $DAEMON
+ echo "."
+ ;;
+ *)
+ echo "Usage: /etc/init.d/dovecot {start|stop|reload|restart|force-reload}" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
\ No newline at end of file
diff --git a/install/soft/dovecot.service b/install/soft/dovecot.service
new file mode 100644
index 0000000..6c06f29
--- /dev/null
+++ b/install/soft/dovecot.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Dovecot IMAP/POP3 email server
+After=network.target
+
+[Service]
+Type=forking
+PIDFile=/usr/local/dovecot/var/run/dovecot/master.pid
+ExecStart=/usr/local/dovecot/sbin/dovecot
+ExecReload=/bin/kill -HUP $MAINPID
+PrivateTmp=true
+
+[Install]
+WantedBy=multi-user.target
diff --git a/install/soft/epel-6.repo b/install/soft/epel-6.repo
new file mode 100644
index 0000000..7a0e3cc
--- /dev/null
+++ b/install/soft/epel-6.repo
@@ -0,0 +1,29 @@
+[epel]
+name=Extra Packages for Enterprise Linux 6 - $basearch
+baseurl=http://mirrors.aliyun.com/epel/6/$basearch
+ http://mirrors.aliyuncs.com/epel/6/$basearch
+#mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-6&arch=$basearch
+failovermethod=priority
+enabled=1
+gpgcheck=0
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
+
+[epel-debuginfo]
+name=Extra Packages for Enterprise Linux 6 - $basearch - Debug
+baseurl=http://mirrors.aliyun.com/epel/6/$basearch/debug
+ http://mirrors.aliyuncs.com/epel/6/$basearch/debug
+#mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-6&arch=$basearch
+failovermethod=priority
+enabled=0
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
+gpgcheck=0
+
+[epel-source]
+name=Extra Packages for Enterprise Linux 6 - $basearch - Source
+baseurl=http://mirrors.aliyun.com/epel/6/SRPMS
+ http://mirrors.aliyuncs.com/epel/6/SRPMS
+#mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=epel-source-6&arch=$basearch
+failovermethod=priority
+enabled=0
+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
+gpgcheck=0
\ No newline at end of file
diff --git a/install/soft/epel-release-latest-7.noarch.rpm b/install/soft/epel-release-latest-7.noarch.rpm
new file mode 100644
index 0000000..c2e0868
Binary files /dev/null and b/install/soft/epel-release-latest-7.noarch.rpm differ
diff --git a/install/soft/ewomail-lamp-1.0-el6.x86_64.rpm b/install/soft/ewomail-lamp-1.0-el6.x86_64.rpm
new file mode 100644
index 0000000..e388ad0
Binary files /dev/null and b/install/soft/ewomail-lamp-1.0-el6.x86_64.rpm differ
diff --git a/install/soft/httpd.conf b/install/soft/httpd.conf
new file mode 100644
index 0000000..f50b62b
--- /dev/null
+++ b/install/soft/httpd.conf
@@ -0,0 +1,424 @@
+#
+# This is the main Apache HTTP server configuration file. It contains the
+# configuration directives that give the server its instructions.
+# See for detailed information.
+# In particular, see
+#
+# for a discussion of each configuration directive.
+#
+# Do NOT simply read the instructions in here without understanding
+# what they do. They're here only as hints or reminders. If you are unsure
+# consult the online docs. You have been warned.
+#
+# Configuration and logfile names: If the filenames you specify for many
+# of the server's control files begin with "/" (or "drive:/" for Win32), the
+# server will use that explicit path. If the filenames do *not* begin
+# with "/", the value of ServerRoot is prepended -- so 'log/access_log'
+# with ServerRoot set to '/www' will be interpreted by the
+# server as '/www/log/access_log', where as '/log/access_log' will be
+# interpreted as '/log/access_log'.
+
+#
+# ServerRoot: The top of the directory tree under which the server's
+# configuration, error, and log files are kept.
+#
+# Do not add a slash at the end of the directory path. If you point
+# ServerRoot at a non-local disk, be sure to point the LockFile directive
+# at a local disk. If you wish to share the same ServerRoot for multiple
+# httpd daemons, you will need to change at least LockFile and PidFile.
+#
+ServerRoot "/ewomail/apache"
+
+#
+# Listen: Allows you to bind Apache to specific IP addresses and/or
+# ports, instead of the default. See also the
+# directive.
+#
+# Change this to Listen on specific IP addresses as shown below to
+# prevent Apache from glomming onto all bound IP addresses.
+#
+#Listen 12.34.56.78:80
+#Listen 80
+
+#
+# Dynamic Shared Object (DSO) Support
+#
+# To be able to use the functionality of a module which was built as a DSO you
+# have to place corresponding `LoadModule' lines at this location so the
+# directives contained in it are actually available _before_ they are used.
+# Statically compiled modules (those listed by `httpd -l') do not need
+# to be loaded here.
+#
+# Example:
+# LoadModule foo_module modules/mod_foo.so
+#
+LoadModule deflate_module modules/mod_deflate.so
+LoadModule expires_module modules/mod_expires.so
+LoadModule headers_module modules/mod_headers.so
+LoadModule ssl_module modules/mod_ssl.so
+LoadModule rewrite_module modules/mod_rewrite.so
+LoadModule php5_module modules/libphp5.so
+
+
+
+#
+# If you wish httpd to run as a different user or group, you must run
+# httpd as root initially and it will switch.
+#
+# User/Group: The name (or #number) of the user/group to run httpd as.
+# It is usually good practice to create a dedicated user and group for
+# running httpd, as with most system services.
+#
+User www
+Group www
+
+
+
+
+# 'Main' server configuration
+#
+# The directives in this section set up the values used by the 'main'
+# server, which responds to any requests that aren't handled by a
+# definition. These values also provide defaults for
+# any containers you may define later in the file.
+#
+# All of these directives may appear inside containers,
+# in which case these default settings will be overridden for the
+# virtual host being defined.
+#
+
+#
+# ServerAdmin: Your address, where problems with the server should be
+# e-mailed. This address appears on some server-generated pages, such
+# as error documents. e.g. admin@your-domain.com
+#
+ServerAdmin you@example.com
+
+#
+# ServerName gives the name and port that the server uses to identify itself.
+# This can often be determined automatically, but we recommend you specify
+# it explicitly to prevent problems during startup.
+#
+# If your host doesn't have a registered DNS name, enter its IP address here.
+#
+ServerName localhost:80
+
+#
+# DocumentRoot: The directory out of which you will serve your
+# documents. By default, all requests are taken from this directory, but
+# symbolic links and aliases may be used to point to other locations.
+#
+DocumentRoot "/ewomail/apache/htdocs"
+
+#
+# Each directory to which Apache has access can be configured with respect
+# to which services and features are allowed and/or disabled in that
+# directory (and its subdirectories).
+#
+# First, we configure the "default" to be a very restrictive set of
+# features.
+#
+
+ Options FollowSymLinks
+ AllowOverride None
+ Order deny,allow
+ Deny from all
+
+
+#
+# Note that from this point forward you must specifically allow
+# particular features to be enabled - so if something's not working as
+# you might expect, make sure that you have specifically enabled it
+# below.
+#
+
+#
+# This should be changed to whatever you set DocumentRoot to.
+#
+
+ #
+ # Possible values for the Options directive are "None", "All",
+ # or any combination of:
+ # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
+ #
+ # Note that "MultiViews" must be named *explicitly* --- "Options All"
+ # doesn't give it to you.
+ #
+ # The Options directive is both complicated and important. Please see
+ # http://httpd.apache.org/docs/2.2/mod/core.html#options
+ # for more information.
+ #
+ Options Indexes FollowSymLinks
+
+ #
+ # AllowOverride controls what directives may be placed in .htaccess files.
+ # It can be "All", "None", or any combination of the keywords:
+ # Options FileInfo AuthConfig Limit
+ #
+ AllowOverride None
+
+ #
+ # Controls who can get stuff from this server.
+ #
+ Order allow,deny
+ Allow from all
+
+
+
+#
+# DirectoryIndex: sets the file that Apache will serve if a directory
+# is requested.
+#
+
+ DirectoryIndex index.html
+
+
+#
+# The following lines prevent .htaccess and .htpasswd files from being
+# viewed by Web clients.
+#
+
+ Order allow,deny
+ Deny from all
+ Satisfy All
+
+
+#
+# ErrorLog: The location of the error log file.
+# If you do not specify an ErrorLog directive within a
+# container, error messages relating to that virtual host will be
+# logged here. If you *do* define an error logfile for a
+# container, that host's errors will be logged there and not here.
+#
+ErrorLog "logs/error_log"
+
+#
+# LogLevel: Control the number of messages logged to the error_log.
+# Possible values include: debug, info, notice, warn, error, crit,
+# alert, emerg.
+#
+LogLevel warn
+
+
+ #
+ # The following directives define some format nicknames for use with
+ # a CustomLog directive (see below).
+ #
+ LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+ LogFormat "%h %l %u %t \"%r\" %>s %b" common
+
+
+ # You need to enable mod_logio.c to use %I and %O
+ LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
+
+
+ #
+ # The location and format of the access logfile (Common Logfile Format).
+ # If you do not define any access logfiles within a
+ # container, they will be logged here. Contrariwise, if you *do*
+ # define per- access logfiles, transactions will be
+ # logged therein and *not* in this file.
+ #
+ CustomLog "logs/access_log" common
+
+ #
+ # If you prefer a logfile with access, agent, and referer information
+ # (Combined Logfile Format) you can use the following directive.
+ #
+ #CustomLog "logs/access_log" combined
+
+
+
+ #
+ # Redirect: Allows you to tell clients about documents that used to
+ # exist in your server's namespace, but do not anymore. The client
+ # will make a new request for the document at its new location.
+ # Example:
+ # Redirect permanent /foo http://www.example.com/bar
+
+ #
+ # Alias: Maps web paths into filesystem paths and is used to
+ # access content that does not live under the DocumentRoot.
+ # Example:
+ # Alias /webpath /full/filesystem/path
+ #
+ # If you include a trailing / on /webpath then the server will
+ # require it to be present in the URL. You will also likely
+ # need to provide a section to allow access to
+ # the filesystem path.
+
+ #
+ # ScriptAlias: This controls which directories contain server scripts.
+ # ScriptAliases are essentially the same as Aliases, except that
+ # documents in the target directory are treated as applications and
+ # run by the server when requested rather than as documents sent to the
+ # client. The same rules about trailing "/" apply to ScriptAlias
+ # directives as to Alias.
+ #
+ ScriptAlias /cgi-bin/ "/ewomail/apache/cgi-bin/"
+
+
+
+
+ #
+ # ScriptSock: On threaded servers, designate the path to the UNIX
+ # socket used to communicate with the CGI daemon of mod_cgid.
+ #
+ #Scriptsock logs/cgisock
+
+
+#
+# "/ewomail/apache/cgi-bin" should be changed to whatever your ScriptAliased
+# CGI directory exists, if you have that configured.
+#
+
+ AllowOverride None
+ Options None
+ Order allow,deny
+ Allow from all
+
+
+#
+# DefaultType: the default MIME type the server will use for a document
+# if it cannot otherwise determine one, such as from filename extensions.
+# If your server contains mostly text or HTML documents, "text/plain" is
+# a good value. If most of your content is binary, such as applications
+# or images, you may want to use "application/octet-stream" instead to
+# keep browsers from trying to display binary files as though they are
+# text.
+#
+DefaultType text/plain
+
+
+ #
+ # TypesConfig points to the file containing the list of mappings from
+ # filename extension to MIME-type.
+ #
+ TypesConfig conf/mime.types
+
+ #
+ # AddType allows you to add to or override the MIME configuration
+ # file specified in TypesConfig for specific file types.
+ #
+ #AddType application/x-gzip .tgz
+ #
+ # AddEncoding allows you to have certain browsers uncompress
+ # information on the fly. Note: Not all browsers support this.
+ #
+ #AddEncoding x-compress .Z
+ #AddEncoding x-gzip .gz .tgz
+ #
+ # If the AddEncoding directives above are commented-out, then you
+ # probably should define those extensions to indicate media types:
+ #
+ AddType application/x-compress .Z
+ AddType application/x-gzip .gz .tgz
+ AddType application/x-httpd-php .php
+
+ #
+ # AddHandler allows you to map certain file extensions to "handlers":
+ # actions unrelated to filetype. These can be either built into the server
+ # or added with the Action directive (see below)
+ #
+ # To use CGI scripts outside of ScriptAliased directories:
+ # (You will also need to add "ExecCGI" to the "Options" directive.)
+ #
+ #AddHandler cgi-script .cgi
+
+ # For type maps (negotiated resources):
+ #AddHandler type-map var
+
+ #
+ # Filters allow you to process content before it is sent to the client.
+ #
+ # To parse .shtml files for server-side includes (SSI):
+ # (You will also need to add "Includes" to the "Options" directive.)
+ #
+ #AddType text/html .shtml
+ #AddOutputFilter INCLUDES .shtml
+
+
+#
+# The mod_mime_magic module allows the server to use various hints from the
+# contents of the file itself to determine its type. The MIMEMagicFile
+# directive tells the module where the hint definitions are located.
+#
+#MIMEMagicFile conf/magic
+
+#
+# Customizable error responses come in three flavors:
+# 1) plain text 2) local redirects 3) external redirects
+#
+# Some examples:
+#ErrorDocument 500 "The server made a boo boo."
+#ErrorDocument 404 /missing.html
+#ErrorDocument 404 "/cgi-bin/missing_handler.pl"
+#ErrorDocument 402 http://www.example.com/subscription_info.html
+#
+
+#
+# MaxRanges: Maximum number of Ranges in a request before
+# returning the entire resource, or one of the special
+# values 'default', 'none' or 'unlimited'.
+# Default setting is to accept 200 Ranges.
+#MaxRanges unlimited
+
+#
+# EnableMMAP and EnableSendfile: On systems that support it,
+# memory-mapping or the sendfile syscall is used to deliver
+# files. This usually improves server performance, but must
+# be turned off when serving from networked-mounted
+# filesystems or if support for these functions is otherwise
+# broken on your system.
+#
+#EnableMMAP off
+#EnableSendfile off
+
+# Supplemental configuration
+#
+# The configuration files in the conf/extra/ directory can be
+# included to add extra features or to modify the default configuration of
+# the server, or you may simply copy their contents here and change as
+# necessary.
+
+# Server-pool management (MPM specific)
+#Include conf/extra/httpd-mpm.conf
+
+# Multi-language error messages
+#Include conf/extra/httpd-multilang-errordoc.conf
+
+# Fancy directory listings
+#Include conf/extra/httpd-autoindex.conf
+
+# Language settings
+#Include conf/extra/httpd-languages.conf
+
+# User home directories
+#Include conf/extra/httpd-userdir.conf
+
+# Real-time info on requests and configuration
+#Include conf/extra/httpd-info.conf
+
+# Virtual hosts
+Include conf/extra/httpd-vhosts.conf
+
+# Local access to the Apache HTTP Server Manual
+#Include conf/extra/httpd-manual.conf
+
+# Distributed authoring and versioning (WebDAV)
+#Include conf/extra/httpd-dav.conf
+
+# Various default settings
+#Include conf/extra/httpd-default.conf
+
+# Secure (SSL/TLS) connections
+#Include conf/extra/httpd-ssl.conf
+#
+# Note: The following must must be present to support
+# starting without SSL on platforms with no /dev/random equivalent
+# but a statically compiled-in mod_ssl.
+#
+
+SSLRandomSeed startup builtin
+SSLRandomSeed connect builtin
+
diff --git a/install/soft/httpd.init b/install/soft/httpd.init
new file mode 100644
index 0000000..43129aa
--- /dev/null
+++ b/install/soft/httpd.init
@@ -0,0 +1,124 @@
+#!/bin/sh
+# Startup script for the Apache Web Server
+# chkconfig: 345 85 15
+# Description: Startup script for Apache webserver on Debian. Place in /etc/init.d and
+# run 'update-rc.d -f httpd defaults', or use the appropriate command on your
+# distro. For CentOS/Redhat run: 'chkconfig --add httpd'
+
+### BEGIN INIT INFO
+# Provides: httpd
+# Required-Start: $all
+# Required-Stop: $all
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: starts Apache Web Server
+# Description: starts Apache Web Server
+### END INIT INFO
+
+# Author: ezhttp
+# website: http://lnmp.org
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+# Apache control script designed to allow an easy command line interface
+# to controlling Apache. Written by Marc Slemko, 1997/08/23
+#
+# The exit codes returned are:
+# XXX this doc is no longer correct now that the interesting
+# XXX functions are handled by httpd
+# 0 - operation completed successfully
+# 1 -
+# 2 - usage error
+# 3 - httpd could not be started
+# 4 - httpd could not be stopped
+# 5 - httpd could not be started during a restart
+# 6 - httpd could not be restarted during a restart
+# 7 - httpd could not be restarted during a graceful restart
+# 8 - configuration syntax error
+#
+# When multiple arguments are given, only the error from the _last_
+# one is reported. Run "apachectl help" for usage info
+#
+ARGV="$@"
+#
+# |||||||||||||||||||| START CONFIGURATION SECTION ||||||||||||||||||||
+# -------------------- --------------------
+#
+# the path to your httpd binary, including options if necessary
+apache_location=/ewomail/apache
+HTTPD=$apache_location/bin/httpd
+#
+# pick up any necessary environment variables
+if test -f $apache_location/bin/envvars; then
+ . $apache_location/bin/envvars
+fi
+#
+# a command that outputs a formatted text version of the HTML at the
+# url given on the command line. Designed for lynx, however other
+# programs may work.
+LYNX="lynx -dump"
+#
+# the URL to your server's mod_status status page. If you do not
+# have one, then status and fullstatus will not work.
+STATUSURL="http://localhost:80/server-status"
+#
+# Set this variable to a command that increases the maximum
+# number of file descriptors allowed per child process. This is
+# critical for configurations that use many file descriptors,
+# such as mass vhosting, or a multithreaded server.
+ULIMIT_MAX_FILES="ulimit -S -n `ulimit -H -n`"
+# -------------------- --------------------
+# |||||||||||||||||||| END CONFIGURATION SECTION ||||||||||||||||||||
+
+# Set the maximum number of file descriptors allowed per child process.
+if [ "x$ULIMIT_MAX_FILES" != "x" ] ; then
+ $ULIMIT_MAX_FILES
+fi
+
+ERROR=0
+if [ "x$ARGV" = "x" ] ; then
+ ARGV="-h"
+fi
+
+case $ARGV in
+start|stop|restart|graceful|graceful-stop)
+ $HTTPD -k $ARGV
+ ERROR=$?
+ ;;
+startssl|sslstart|start-SSL)
+ echo The startssl option is no longer supported.
+ echo Please edit httpd.conf to include the SSL configuration settings
+ echo and then use "apachectl start".
+ ERROR=2
+ ;;
+configtest)
+ $HTTPD -t
+ ERROR=$?
+ ;;
+status)
+ $LYNX $STATUSURL | awk ' /process$/ { print; exit } { print } '
+ ;;
+fullstatus)
+ $LYNX $STATUSURL
+ ;;
+*)
+ $HTTPD $ARGV
+ ERROR=$?
+esac
+
+exit $ERROR
+
diff --git a/install/soft/iptables b/install/soft/iptables
new file mode 100644
index 0000000..ee90f12
--- /dev/null
+++ b/install/soft/iptables
@@ -0,0 +1,25 @@
+# Generated by iptables-save v1.4.7 on Sun Nov 20 16:17:22 2016
+*filter
+:INPUT ACCEPT [0:0]
+:FORWARD ACCEPT [0:0]
+:OUTPUT ACCEPT [0:0]
+-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
+-A INPUT -p icmp -j ACCEPT
+-A INPUT -i lo -j ACCEPT
+-A INPUT -m state --state NEW -m tcp -p tcp --dport 993 -j ACCEPT
+-A INPUT -m state --state NEW -m tcp -p tcp --dport 995 -j ACCEPT
+-A INPUT -m state --state NEW -m tcp -p tcp --dport 587 -j ACCEPT
+-A INPUT -m state --state NEW -m tcp -p tcp --dport 465 -j ACCEPT
+-A INPUT -m state --state NEW -m tcp -p tcp --dport 143 -j ACCEPT
+-A INPUT -m state --state NEW -m tcp -p tcp --dport 110 -j ACCEPT
+-A INPUT -m state --state NEW -m tcp -p tcp --dport 109 -j ACCEPT
+-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
+-A INPUT -m state --state NEW -m tcp -p tcp --dport 25 -j ACCEPT
+-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
+-A INPUT -m state --state NEW -m tcp -p tcp --dport 8000 -j ACCEPT
+-A INPUT -m state --state NEW -m tcp -p tcp --dport 8010 -j ACCEPT
+-A INPUT -m state --state NEW -m tcp -p tcp --dport 8020 -j ACCEPT
+-A INPUT -j REJECT --reject-with icmp-host-prohibited
+-A FORWARD -j REJECT --reject-with icmp-host-prohibited
+COMMIT
+# Completed on Sun Nov 20 16:17:22 2016
diff --git a/install/soft/nginx.init b/install/soft/nginx.init
new file mode 100644
index 0000000..9a3d02e
--- /dev/null
+++ b/install/soft/nginx.init
@@ -0,0 +1,94 @@
+#! /bin/bash
+# chkconfig: 2345 55 25
+# Description: Startup script for nginx webserver on Debian. Place in /etc/init.d and
+# run 'update-rc.d -f nginx defaults', or use the appropriate command on your
+# distro. For CentOS/Redhat run: 'chkconfig --add nginx'
+
+### BEGIN INIT INFO
+# Provides: nginx
+# Required-Start: $all
+# Required-Stop: $all
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: starts the nginx web server
+# Description: starts nginx using start-stop-daemon
+### END INIT INFO
+
+# Author: ezhttp
+# website: http://lnmp.org
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+DESC="nginx daemon"
+nginx_location=/ewomail/nginx
+DAEMON=$nginx_location/sbin/nginx
+CONFIGFILE=$nginx_location/conf/nginx.conf
+PIDFILE=$nginx_location/logs/nginx.pid
+SCRIPTNAME=/etc/init.d/nginx
+
+set -e
+[ -x "$DAEMON" ] || exit 0
+
+acqNginxPid(){
+ local pid
+ if [ -f $PIDFILE ] ; then
+ pid=`cat $PIDFILE`
+ echo ${pid}
+ fi
+}
+
+do_start() {
+ local pid=`acqNginxPid`
+ if [[ ".${pid}" == "." ]] ; then
+ $DAEMON -c $CONFIGFILE
+ else
+ echo -n "nginx already running"
+ fi
+}
+
+do_stop() {
+ local pid=`acqNginxPid`
+ if [ ".${pid}" != "." ] ; then
+ kill -INT ${pid}
+ else
+ echo -n "nginx not running"
+ fi
+}
+
+do_reload() {
+ local pid=`acqNginxPid`
+ if [ ".${pid}" != "." ] ; then
+ kill -HUP ${pid}
+ else
+ echo -n "nginx can't reload"
+ fi
+}
+
+case "$1" in
+ start)
+ echo -n "Starting $DESC: $NAME"
+ do_start
+ echo "."
+ ;;
+ stop)
+ echo -n "Stopping $DESC: $NAME"
+ do_stop
+ echo "."
+ ;;
+ reload|graceful)
+ echo -n "Reloading $DESC configuration..."
+ do_reload
+ echo "."
+ ;;
+ restart)
+ echo -n "Restarting $DESC: $NAME"
+ do_stop
+ do_start
+ echo "."
+ ;;
+ *)
+ echo "Usage: $SCRIPTNAME {start|stop|reload|restart}" >&2
+ exit 3
+ ;;
+esac
+
+exit 0
diff --git a/install/soft/php-cli.ini b/install/soft/php-cli.ini
new file mode 100644
index 0000000..d85b316
--- /dev/null
+++ b/install/soft/php-cli.ini
@@ -0,0 +1,1837 @@
+[PHP]
+
+;;;;;;;;;;;;;;;;;;;
+; About php.ini ;
+;;;;;;;;;;;;;;;;;;;
+; PHP's initialization file, generally called php.ini, is responsible for
+; configuring many of the aspects of PHP's behavior.
+
+; PHP attempts to find and load this configuration from a number of locations.
+; The following is a summary of its search order:
+; 1. SAPI module specific location.
+; 2. The PHPRC environment variable. (As of PHP 5.2.0)
+; 3. A number of predefined registry keys on Windows (As of PHP 5.2.0)
+; 4. Current working directory (except CLI)
+; 5. The web server's directory (for SAPI modules), or directory of PHP
+; (otherwise in Windows)
+; 6. The directory from the --with-config-file-path compile time option, or the
+; Windows directory (C:\windows or C:\winnt)
+; See the PHP docs for more specific information.
+; http://php.net/configuration.file
+
+; The syntax of the file is extremely simple. Whitespace and lines
+; beginning with a semicolon are silently ignored (as you probably guessed).
+; Section headers (e.g. [Foo]) are also silently ignored, even though
+; they might mean something in the future.
+
+; Directives following the section heading [PATH=/www/mysite] only
+; apply to PHP files in the /www/mysite directory. Directives
+; following the section heading [HOST=www.example.com] only apply to
+; PHP files served from www.example.com. Directives set in these
+; special sections cannot be overridden by user-defined INI files or
+; at runtime. Currently, [PATH=] and [HOST=] sections only work under
+; CGI/FastCGI.
+; http://php.net/ini.sections
+
+; Directives are specified using the following syntax:
+; directive = value
+; Directive names are *case sensitive* - foo=bar is different from FOO=bar.
+; Directives are variables used to configure PHP or PHP extensions.
+; There is no name validation. If PHP can't find an expected
+; directive because it is not set or is mistyped, a default value will be used.
+
+; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one
+; of the INI constants (On, Off, True, False, Yes, No and None) or an expression
+; (e.g. E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a
+; previously set variable or directive (e.g. ${foo})
+
+; Expressions in the INI file are limited to bitwise operators and parentheses:
+; | bitwise OR
+; ^ bitwise XOR
+; & bitwise AND
+; ~ bitwise NOT
+; ! boolean NOT
+
+; Boolean flags can be turned on using the values 1, On, True or Yes.
+; They can be turned off using the values 0, Off, False or No.
+
+; An empty string can be denoted by simply not writing anything after the equal
+; sign, or by using the None keyword:
+
+; foo = ; sets foo to an empty string
+; foo = None ; sets foo to an empty string
+; foo = "None" ; sets foo to the string 'None'
+
+; If you use constants in your value, and these constants belong to a
+; dynamically loaded extension (either a PHP extension or a Zend extension),
+; you may only use these constants *after* the line that loads the extension.
+
+;;;;;;;;;;;;;;;;;;;
+; About this file ;
+;;;;;;;;;;;;;;;;;;;
+; PHP comes packaged with two INI files. One that is recommended to be used
+; in production environments and one that is recommended to be used in
+; development environments.
+
+; php.ini-production contains settings which hold security, performance and
+; best practices at its core. But please be aware, these settings may break
+; compatibility with older or less security conscience applications. We
+; recommending using the production ini in production and testing environments.
+
+; php.ini-development is very similar to its production variant, except it's
+; much more verbose when it comes to errors. We recommending using the
+; development version only in development environments as errors shown to
+; application users can inadvertently leak otherwise secure information.
+
+; This is php.ini-production INI file.
+
+;;;;;;;;;;;;;;;;;;;
+; Quick Reference ;
+;;;;;;;;;;;;;;;;;;;
+; The following are all the settings which are different in either the production
+; or development versions of the INIs with respect to PHP's default behavior.
+; Please see the actual settings later in the document for more details as to why
+; we recommend these changes in PHP's behavior.
+
+; display_errors
+; Default Value: On
+; Development Value: On
+; Production Value: Off
+
+; display_startup_errors
+; Default Value: Off
+; Development Value: On
+; Production Value: Off
+
+; error_reporting
+; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
+; Development Value: E_ALL
+; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT
+
+; html_errors
+; Default Value: On
+; Development Value: On
+; Production value: On
+
+; log_errors
+; Default Value: Off
+; Development Value: On
+; Production Value: On
+
+; max_input_time
+; Default Value: -1 (Unlimited)
+; Development Value: 60 (60 seconds)
+; Production Value: 60 (60 seconds)
+
+; output_buffering
+; Default Value: Off
+; Development Value: 4096
+; Production Value: 4096
+
+; register_argc_argv
+; Default Value: On
+; Development Value: Off
+; Production Value: Off
+
+; request_order
+; Default Value: None
+; Development Value: "GP"
+; Production Value: "GP"
+
+; session.gc_divisor
+; Default Value: 100
+; Development Value: 1000
+; Production Value: 1000
+
+; session.hash_bits_per_character
+; Default Value: 4
+; Development Value: 5
+; Production Value: 5
+
+; short_open_tag
+; Default Value: On
+; Development Value: Off
+; Production Value: Off
+
+; track_errors
+; Default Value: Off
+; Development Value: On
+; Production Value: Off
+
+; url_rewriter.tags
+; Default Value: "a=href,area=href,frame=src,form=,fieldset="
+; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry"
+; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry"
+
+; variables_order
+; Default Value: "EGPCS"
+; Development Value: "GPCS"
+; Production Value: "GPCS"
+
+;;;;;;;;;;;;;;;;;;;;
+; php.ini Options ;
+;;;;;;;;;;;;;;;;;;;;
+; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini"
+;user_ini.filename = ".user.ini"
+
+; To disable this feature set this option to empty value
+;user_ini.filename =
+
+; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes)
+;user_ini.cache_ttl = 300
+
+;;;;;;;;;;;;;;;;;;;;
+; Language Options ;
+;;;;;;;;;;;;;;;;;;;;
+
+; Enable the PHP scripting language engine under Apache.
+; http://php.net/engine
+engine = On
+
+; This directive determines whether or not PHP will recognize code between
+; and ?> tags as PHP source which should be processed as such. It is
+; generally recommended that should be used and that this feature
+; should be disabled, as enabling it may result in issues when generating XML
+; documents, however this remains supported for backward compatibility reasons.
+; Note that this directive does not control the = shorthand tag, which can be
+; used regardless of this directive.
+; Default Value: On
+; Development Value: Off
+; Production Value: Off
+; http://php.net/short-open-tag
+short_open_tag = On
+
+; Allow ASP-style <% %> tags.
+; http://php.net/asp-tags
+asp_tags = Off
+
+; The number of significant digits displayed in floating point numbers.
+; http://php.net/precision
+precision = 14
+
+; Output buffering is a mechanism for controlling how much output data
+; (excluding headers and cookies) PHP should keep internally before pushing that
+; data to the client. If your application's output exceeds this setting, PHP
+; will send that data in chunks of roughly the size you specify.
+; Turning on this setting and managing its maximum buffer size can yield some
+; interesting side-effects depending on your application and web server.
+; You may be able to send headers and cookies after you've already sent output
+; through print or echo. You also may see performance benefits if your server is
+; emitting less packets due to buffered output versus PHP streaming the output
+; as it gets it. On production servers, 4096 bytes is a good setting for performance
+; reasons.
+; Note: Output buffering can also be controlled via Output Buffering Control
+; functions.
+; Possible Values:
+; On = Enabled and buffer is unlimited. (Use with caution)
+; Off = Disabled
+; Integer = Enables the buffer and sets its maximum size in bytes.
+; Note: This directive is hardcoded to Off for the CLI SAPI
+; Default Value: Off
+; Development Value: 4096
+; Production Value: 4096
+; http://php.net/output-buffering
+output_buffering = 4096
+
+; You can redirect all of the output of your scripts to a function. For
+; example, if you set output_handler to "mb_output_handler", character
+; encoding will be transparently converted to the specified encoding.
+; Setting any output handler automatically turns on output buffering.
+; Note: People who wrote portable scripts should not depend on this ini
+; directive. Instead, explicitly set the output handler using ob_start().
+; Using this ini directive may cause problems unless you know what script
+; is doing.
+; Note: You cannot use both "mb_output_handler" with "ob_iconv_handler"
+; and you cannot use both "ob_gzhandler" and "zlib.output_compression".
+; Note: output_handler must be empty if this is set 'On' !!!!
+; Instead you must use zlib.output_handler.
+; http://php.net/output-handler
+;output_handler =
+
+; Transparent output compression using the zlib library
+; Valid values for this option are 'off', 'on', or a specific buffer size
+; to be used for compression (default is 4KB)
+; Note: Resulting chunk size may vary due to nature of compression. PHP
+; outputs chunks that are few hundreds bytes each as a result of
+; compression. If you prefer a larger chunk size for better
+; performance, enable output_buffering in addition.
+; Note: You need to use zlib.output_handler instead of the standard
+; output_handler, or otherwise the output will be corrupted.
+; http://php.net/zlib.output-compression
+zlib.output_compression = Off
+
+; http://php.net/zlib.output-compression-level
+;zlib.output_compression_level = -1
+
+; You cannot specify additional output handlers if zlib.output_compression
+; is activated here. This setting does the same as output_handler but in
+; a different order.
+; http://php.net/zlib.output-handler
+;zlib.output_handler =
+
+; Implicit flush tells PHP to tell the output layer to flush itself
+; automatically after every output block. This is equivalent to calling the
+; PHP function flush() after each and every call to print() or echo() and each
+; and every HTML block. Turning this option on has serious performance
+; implications and is generally recommended for debugging purposes only.
+; http://php.net/implicit-flush
+; Note: This directive is hardcoded to On for the CLI SAPI
+implicit_flush = Off
+
+; The unserialize callback function will be called (with the undefined class'
+; name as parameter), if the unserializer finds an undefined class
+; which should be instantiated. A warning appears if the specified function is
+; not defined, or if the function doesn't include/implement the missing class.
+; So only set this entry, if you really want to implement such a
+; callback-function.
+unserialize_callback_func =
+
+; When floats & doubles are serialized store serialize_precision significant
+; digits after the floating point. The default value ensures that when floats
+; are decoded with unserialize, the data will remain the same.
+serialize_precision = 17
+
+; open_basedir, if set, limits all file operations to the defined directory
+; and below. This directive makes most sense if used in a per-directory
+; or per-virtualhost web server configuration file. This directive is
+; *NOT* affected by whether Safe Mode is turned On or Off.
+; http://php.net/open-basedir
+;open_basedir =
+
+; This directive allows you to disable certain functions for security reasons.
+; It receives a comma-delimited list of function names. This directive is
+; *NOT* affected by whether Safe Mode is turned On or Off.
+; http://php.net/disable-functions
+;disable_functions = dl,eval,assert,exec,popen,system,passthru,shell_exec,escapeshellarg,escapeshellcmd,proc_close,proc_open
+
+; This directive allows you to disable certain classes for security reasons.
+; It receives a comma-delimited list of class names. This directive is
+; *NOT* affected by whether Safe Mode is turned On or Off.
+; http://php.net/disable-classes
+disable_classes =
+
+; Colors for Syntax Highlighting mode. Anything that's acceptable in
+; would work.
+; http://php.net/syntax-highlighting
+;highlight.string = #DD0000
+;highlight.comment = #FF9900
+;highlight.keyword = #007700
+;highlight.default = #0000BB
+;highlight.html = #000000
+
+; If enabled, the request will be allowed to complete even if the user aborts
+; the request. Consider enabling it if executing long requests, which may end up
+; being interrupted by the user or a browser timing out. PHP's default behavior
+; is to disable this feature.
+; http://php.net/ignore-user-abort
+;ignore_user_abort = On
+
+; Determines the size of the realpath cache to be used by PHP. This value should
+; be increased on systems where PHP opens many files to reflect the quantity of
+; the file operations performed.
+; http://php.net/realpath-cache-size
+;realpath_cache_size = 16k
+
+; Duration of time, in seconds for which to cache realpath information for a given
+; file or directory. For systems with rarely changing files, consider increasing this
+; value.
+; http://php.net/realpath-cache-ttl
+;realpath_cache_ttl = 120
+
+; Enables or disables the circular reference collector.
+; http://php.net/zend.enable-gc
+zend.enable_gc = On
+
+; If enabled, scripts may be written in encodings that are incompatible with
+; the scanner. CP936, Big5, CP949 and Shift_JIS are the examples of such
+; encodings. To use this feature, mbstring extension must be enabled.
+; Default: Off
+;zend.multibyte = Off
+
+; Allows to set the default encoding for the scripts. This value will be used
+; unless "declare(encoding=...)" directive appears at the top of the script.
+; Only affects if zend.multibyte is set.
+; Default: ""
+;zend.script_encoding =
+
+;;;;;;;;;;;;;;;;;
+; Miscellaneous ;
+;;;;;;;;;;;;;;;;;
+
+; Decides whether PHP may expose the fact that it is installed on the server
+; (e.g. by adding its signature to the Web server header). It is no security
+; threat in any way, but it makes it possible to determine whether you use PHP
+; on your server or not.
+; http://php.net/expose-php
+expose_php = Off
+
+;;;;;;;;;;;;;;;;;;;
+; Resource Limits ;
+;;;;;;;;;;;;;;;;;;;
+
+; Maximum execution time of each script, in seconds
+; http://php.net/max-execution-time
+; Note: This directive is hardcoded to 0 for the CLI SAPI
+max_execution_time = 30
+
+; Maximum amount of time each script may spend parsing request data. It's a good
+; idea to limit this time on productions servers in order to eliminate unexpectedly
+; long running scripts.
+; Note: This directive is hardcoded to -1 for the CLI SAPI
+; Default Value: -1 (Unlimited)
+; Development Value: 60 (60 seconds)
+; Production Value: 60 (60 seconds)
+; http://php.net/max-input-time
+max_input_time = 60
+
+; Maximum input variable nesting level
+; http://php.net/max-input-nesting-level
+;max_input_nesting_level = 64
+
+; How many GET/POST/COOKIE input variables may be accepted
+; max_input_vars = 1000
+
+; Maximum amount of memory a script may consume (128MB)
+; http://php.net/memory-limit
+memory_limit = 128M
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Error handling and logging ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; This directive informs PHP of which errors, warnings and notices you would like
+; it to take action for. The recommended way of setting values for this
+; directive is through the use of the error level constants and bitwise
+; operators. The error level constants are below here for convenience as well as
+; some common settings and their meanings.
+; By default, PHP is set to take action on all errors, notices and warnings EXCEPT
+; those related to E_NOTICE and E_STRICT, which together cover best practices and
+; recommended coding standards in PHP. For performance reasons, this is the
+; recommend error reporting setting. Your production server shouldn't be wasting
+; resources complaining about best practices and coding standards. That's what
+; development servers and development settings are for.
+; Note: The php.ini-development file has this setting as E_ALL. This
+; means it pretty much reports everything which is exactly what you want during
+; development and early testing.
+;
+; Error Level Constants:
+; E_ALL - All errors and warnings (includes E_STRICT as of PHP 5.4.0)
+; E_ERROR - fatal run-time errors
+; E_RECOVERABLE_ERROR - almost fatal run-time errors
+; E_WARNING - run-time warnings (non-fatal errors)
+; E_PARSE - compile-time parse errors
+; E_NOTICE - run-time notices (these are warnings which often result
+; from a bug in your code, but it's possible that it was
+; intentional (e.g., using an uninitialized variable and
+; relying on the fact it's automatically initialized to an
+; empty string)
+; E_STRICT - run-time notices, enable to have PHP suggest changes
+; to your code which will ensure the best interoperability
+; and forward compatibility of your code
+; E_CORE_ERROR - fatal errors that occur during PHP's initial startup
+; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's
+; initial startup
+; E_COMPILE_ERROR - fatal compile-time errors
+; E_COMPILE_WARNING - compile-time warnings (non-fatal errors)
+; E_USER_ERROR - user-generated error message
+; E_USER_WARNING - user-generated warning message
+; E_USER_NOTICE - user-generated notice message
+; E_DEPRECATED - warn about code that will not work in future versions
+; of PHP
+; E_USER_DEPRECATED - user-generated deprecation warnings
+;
+; Common Values:
+; E_ALL (Show all errors, warnings and notices including coding standards.)
+; E_ALL & ~E_NOTICE (Show all errors, except for notices)
+; E_ALL & ~E_NOTICE & ~E_STRICT (Show all errors, except for notices and coding standards warnings.)
+; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors)
+; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
+; Development Value: E_ALL
+; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT
+; http://php.net/error-reporting
+error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
+
+; This directive controls whether or not and where PHP will output errors,
+; notices and warnings too. Error output is very useful during development, but
+; it could be very dangerous in production environments. Depending on the code
+; which is triggering the error, sensitive information could potentially leak
+; out of your application such as database usernames and passwords or worse.
+; It's recommended that errors be logged on production servers rather than
+; having the errors sent to STDOUT.
+; Possible Values:
+; Off = Do not display any errors
+; stderr = Display errors to STDERR (affects only CGI/CLI binaries!)
+; On or stdout = Display errors to STDOUT
+; Default Value: On
+; Development Value: On
+; Production Value: Off
+; http://php.net/display-errors
+display_errors = Off
+
+; The display of errors which occur during PHP's startup sequence are handled
+; separately from display_errors. PHP's default behavior is to suppress those
+; errors from clients. Turning the display of startup errors on can be useful in
+; debugging configuration problems. But, it's strongly recommended that you
+; leave this setting off on production servers.
+; Default Value: Off
+; Development Value: On
+; Production Value: Off
+; http://php.net/display-startup-errors
+display_startup_errors = Off
+
+; Besides displaying errors, PHP can also log errors to locations such as a
+; server-specific log, STDERR, or a location specified by the error_log
+; directive found below. While errors should not be displayed on productions
+; servers they should still be monitored and logging is a great way to do that.
+; Default Value: Off
+; Development Value: On
+; Production Value: On
+; http://php.net/log-errors
+log_errors = On
+
+; Set maximum length of log_errors. In error_log information about the source is
+; added. The default is 1024 and 0 allows to not apply any maximum length at all.
+; http://php.net/log-errors-max-len
+log_errors_max_len = 1024
+
+; Do not log repeated messages. Repeated errors must occur in same file on same
+; line unless ignore_repeated_source is set true.
+; http://php.net/ignore-repeated-errors
+ignore_repeated_errors = Off
+
+; Ignore source of message when ignoring repeated messages. When this setting
+; is On you will not log errors with repeated messages from different files or
+; source lines.
+; http://php.net/ignore-repeated-source
+ignore_repeated_source = Off
+
+; If this parameter is set to Off, then memory leaks will not be shown (on
+; stdout or in the log). This has only effect in a debug compile, and if
+; error reporting includes E_WARNING in the allowed list
+; http://php.net/report-memleaks
+report_memleaks = On
+
+; This setting is on by default.
+;report_zend_debug = 0
+
+; Store the last error/warning message in $php_errormsg (boolean). Setting this value
+; to On can assist in debugging and is appropriate for development servers. It should
+; however be disabled on production servers.
+; Default Value: Off
+; Development Value: On
+; Production Value: Off
+; http://php.net/track-errors
+track_errors = Off
+
+; Turn off normal error reporting and emit XML-RPC error XML
+; http://php.net/xmlrpc-errors
+;xmlrpc_errors = 0
+
+; An XML-RPC faultCode
+;xmlrpc_error_number = 0
+
+; When PHP displays or logs an error, it has the capability of formatting the
+; error message as HTML for easier reading. This directive controls whether
+; the error message is formatted as HTML or not.
+; Note: This directive is hardcoded to Off for the CLI SAPI
+; Default Value: On
+; Development Value: On
+; Production value: On
+; http://php.net/html-errors
+html_errors = On
+
+; If html_errors is set to On *and* docref_root is not empty, then PHP
+; produces clickable error messages that direct to a page describing the error
+; or function causing the error in detail.
+; You can download a copy of the PHP manual from http://php.net/docs
+; and change docref_root to the base URL of your local copy including the
+; leading '/'. You must also specify the file extension being used including
+; the dot. PHP's default behavior is to leave these settings empty, in which
+; case no links to documentation are generated.
+; Note: Never use this feature for production boxes.
+; http://php.net/docref-root
+; Examples
+;docref_root = "/phpmanual/"
+
+; http://php.net/docref-ext
+;docref_ext = .html
+
+; String to output before an error message. PHP's default behavior is to leave
+; this setting blank.
+; http://php.net/error-prepend-string
+; Example:
+;error_prepend_string = ""
+
+; String to output after an error message. PHP's default behavior is to leave
+; this setting blank.
+; http://php.net/error-append-string
+; Example:
+;error_append_string = " "
+
+; Log errors to specified file. PHP's default behavior is to leave this value
+; empty.
+; http://php.net/error-log
+; Example:
+;error_log = php_errors.log
+; Log errors to syslog (Event Log on Windows).
+;error_log = syslog
+
+;windows.show_crt_warning
+; Default value: 0
+; Development value: 0
+; Production value: 0
+
+;;;;;;;;;;;;;;;;;
+; Data Handling ;
+;;;;;;;;;;;;;;;;;
+
+; The separator used in PHP generated URLs to separate arguments.
+; PHP's default setting is "&".
+; http://php.net/arg-separator.output
+; Example:
+;arg_separator.output = "&"
+
+; List of separator(s) used by PHP to parse input URLs into variables.
+; PHP's default setting is "&".
+; NOTE: Every character in this directive is considered as separator!
+; http://php.net/arg-separator.input
+; Example:
+;arg_separator.input = ";&"
+
+; This directive determines which super global arrays are registered when PHP
+; starts up. G,P,C,E & S are abbreviations for the following respective super
+; globals: GET, POST, COOKIE, ENV and SERVER. There is a performance penalty
+; paid for the registration of these arrays and because ENV is not as commonly
+; used as the others, ENV is not recommended on productions servers. You
+; can still get access to the environment variables through getenv() should you
+; need to.
+; Default Value: "EGPCS"
+; Development Value: "GPCS"
+; Production Value: "GPCS";
+; http://php.net/variables-order
+variables_order = "GPCS"
+
+; This directive determines which super global data (G,P,C,E & S) should
+; be registered into the super global array REQUEST. If so, it also determines
+; the order in which that data is registered. The values for this directive are
+; specified in the same manner as the variables_order directive, EXCEPT one.
+; Leaving this value empty will cause PHP to use the value set in the
+; variables_order directive. It does not mean it will leave the super globals
+; array REQUEST empty.
+; Default Value: None
+; Development Value: "GP"
+; Production Value: "GP"
+; http://php.net/request-order
+request_order = "CGP"
+
+; This directive determines whether PHP registers $argv & $argc each time it
+; runs. $argv contains an array of all the arguments passed to PHP when a script
+; is invoked. $argc contains an integer representing the number of arguments
+; that were passed when the script was invoked. These arrays are extremely
+; useful when running scripts from the command line. When this directive is
+; enabled, registering these variables consumes CPU cycles and memory each time
+; a script is executed. For performance reasons, this feature should be disabled
+; on production servers.
+; Note: This directive is hardcoded to On for the CLI SAPI
+; Default Value: On
+; Development Value: Off
+; Production Value: Off
+; http://php.net/register-argc-argv
+register_argc_argv = Off
+
+; When enabled, the ENV, REQUEST and SERVER variables are created when they're
+; first used (Just In Time) instead of when the script starts. If these
+; variables are not used within a script, having this directive on will result
+; in a performance gain. The PHP directive register_argc_argv must be disabled
+; for this directive to have any affect.
+; http://php.net/auto-globals-jit
+auto_globals_jit = On
+
+; Whether PHP will read the POST data.
+; This option is enabled by default.
+; Most likely, you won't want to disable this option globally. It causes $_POST
+; and $_FILES to always be empty; the only way you will be able to read the
+; POST data will be through the php://input stream wrapper. This can be useful
+; to proxy requests or to process the POST data in a memory efficient fashion.
+; http://php.net/enable-post-data-reading
+;enable_post_data_reading = Off
+
+; Maximum size of POST data that PHP will accept.
+; Its value may be 0 to disable the limit. It is ignored if POST data reading
+; is disabled through enable_post_data_reading.
+; http://php.net/post-max-size
+post_max_size = 300M
+
+; Automatically add files before PHP document.
+; http://php.net/auto-prepend-file
+auto_prepend_file =
+
+; Automatically add files after PHP document.
+; http://php.net/auto-append-file
+auto_append_file =
+
+; By default, PHP will output a character encoding using
+; the Content-type: header. To disable sending of the charset, simply
+; set it to be empty.
+;
+; PHP's built-in default is text/html
+; http://php.net/default-mimetype
+default_mimetype = "text/html"
+
+; PHP's default character set is set to empty.
+; http://php.net/default-charset
+;default_charset = "UTF-8"
+
+; Always populate the $HTTP_RAW_POST_DATA variable. PHP's default behavior is
+; to disable this feature. If post reading is disabled through
+; enable_post_data_reading, $HTTP_RAW_POST_DATA is *NOT* populated.
+; http://php.net/always-populate-raw-post-data
+;always_populate_raw_post_data = On
+
+;;;;;;;;;;;;;;;;;;;;;;;;;
+; Paths and Directories ;
+;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; UNIX: "/path1:/path2"
+;include_path = ".:/php/includes"
+;
+; Windows: "\path1;\path2"
+;include_path = ".;c:\php\includes"
+;
+; PHP's default setting for include_path is ".;/path/to/php/pear"
+; http://php.net/include-path
+
+; The root of the PHP pages, used only if nonempty.
+; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root
+; if you are running php as a CGI under any web server (other than IIS)
+; see documentation for security issues. The alternate is to use the
+; cgi.force_redirect configuration below
+; http://php.net/doc-root
+doc_root =
+
+; The directory under which PHP opens the script using /~username used only
+; if nonempty.
+; http://php.net/user-dir
+user_dir =
+
+; Directory in which the loadable extensions (modules) reside.
+; http://php.net/extension-dir
+; extension_dir = "./"
+; On windows:
+; extension_dir = "ext"
+
+; Whether or not to enable the dl() function. The dl() function does NOT work
+; properly in multithreaded servers, such as IIS or Zeus, and is automatically
+; disabled on them.
+; http://php.net/enable-dl
+enable_dl = Off
+
+; cgi.force_redirect is necessary to provide security running PHP as a CGI under
+; most web servers. Left undefined, PHP turns this on by default. You can
+; turn it off here AT YOUR OWN RISK
+; **You CAN safely turn this off for IIS, in fact, you MUST.**
+; http://php.net/cgi.force-redirect
+;cgi.force_redirect = 1
+
+; if cgi.nph is enabled it will force cgi to always sent Status: 200 with
+; every request. PHP's default behavior is to disable this feature.
+;cgi.nph = 1
+
+; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape
+; (iPlanet) web servers, you MAY need to set an environment variable name that PHP
+; will look for to know it is OK to continue execution. Setting this variable MAY
+; cause security issues, KNOW WHAT YOU ARE DOING FIRST.
+; http://php.net/cgi.redirect-status-env
+;cgi.redirect_status_env =
+
+; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's
+; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
+; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting
+; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting
+; of zero causes PHP to behave as before. Default is 1. You should fix your scripts
+; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
+; http://php.net/cgi.fix-pathinfo
+;cgi.fix_pathinfo=1
+
+; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate
+; security tokens of the calling client. This allows IIS to define the
+; security context that the request runs under. mod_fastcgi under Apache
+; does not currently support this feature (03/17/2002)
+; Set to 1 if running under IIS. Default is zero.
+; http://php.net/fastcgi.impersonate
+;fastcgi.impersonate = 1
+
+; Disable logging through FastCGI connection. PHP's default behavior is to enable
+; this feature.
+;fastcgi.logging = 0
+
+; cgi.rfc2616_headers configuration option tells PHP what type of headers to
+; use when sending HTTP response code. If it's set 0 PHP sends Status: header that
+; is supported by Apache. When this option is set to 1 PHP will send
+; RFC2616 compliant header.
+; Default is zero.
+; http://php.net/cgi.rfc2616-headers
+;cgi.rfc2616_headers = 0
+
+;;;;;;;;;;;;;;;;
+; File Uploads ;
+;;;;;;;;;;;;;;;;
+
+; Whether to allow HTTP file uploads.
+; http://php.net/file-uploads
+file_uploads = On
+
+; Temporary directory for HTTP uploaded files (will use system default if not
+; specified).
+; http://php.net/upload-tmp-dir
+;upload_tmp_dir =
+
+; Maximum allowed size for uploaded files.
+; http://php.net/upload-max-filesize
+upload_max_filesize = 300M
+
+; Maximum number of files that can be uploaded via a single request
+max_file_uploads = 20
+
+;;;;;;;;;;;;;;;;;;
+; Fopen wrappers ;
+;;;;;;;;;;;;;;;;;;
+
+; Whether to allow the treatment of URLs (like http:// or ftp://) as files.
+; http://php.net/allow-url-fopen
+allow_url_fopen = On
+
+; Whether to allow include/require to open URLs (like http:// or ftp://) as files.
+; http://php.net/allow-url-include
+allow_url_include = Off
+
+; Define the anonymous ftp password (your email address). PHP's default setting
+; for this is empty.
+; http://php.net/from
+;from="john@doe.com"
+
+; Define the User-Agent string. PHP's default setting for this is empty.
+; http://php.net/user-agent
+;user_agent="PHP"
+
+; Default timeout for socket based streams (seconds)
+; http://php.net/default-socket-timeout
+default_socket_timeout = 60
+
+; If your scripts have to deal with files from Macintosh systems,
+; or you are running on a Mac and need to deal with files from
+; unix or win32 systems, setting this flag will cause PHP to
+; automatically detect the EOL character in those files so that
+; fgets() and file() will work regardless of the source of the file.
+; http://php.net/auto-detect-line-endings
+;auto_detect_line_endings = Off
+
+;;;;;;;;;;;;;;;;;;;;;;
+; Dynamic Extensions ;
+;;;;;;;;;;;;;;;;;;;;;;
+
+; If you wish to have an extension loaded automatically, use the following
+; syntax:
+;
+; extension=modulename.extension
+;
+; For example, on Windows:
+;
+; extension=msql.dll
+;
+; ... or under UNIX:
+;
+; extension=msql.so
+;
+; ... or with a path:
+;
+; extension=/path/to/extension/msql.so
+;
+; If you only provide the name of the extension, PHP will look for it in its
+; default extension directory.
+;
+; Windows Extensions
+; Note that ODBC support is built in, so no dll is needed for it.
+; Note that many DLL files are located in the extensions/ (PHP 4) ext/ (PHP 5)
+; extension folders as well as the separate PECL DLL download (PHP 5).
+; Be sure to appropriately set the extension_dir directive.
+;
+;extension=php_bz2.dll
+;extension=php_curl.dll
+;extension=php_fileinfo.dll
+;extension=php_gd2.dll
+;extension=php_gettext.dll
+;extension=php_gmp.dll
+;extension=php_intl.dll
+;extension=php_imap.dll
+;extension=php_interbase.dll
+;extension=php_ldap.dll
+;extension=php_mbstring.dll
+;extension=php_exif.dll ; Must be after mbstring as it depends on it
+;extension=php_mysql.dll
+;extension=php_mysqli.dll
+;extension=php_oci8.dll ; Use with Oracle 10gR2 Instant Client
+;extension=php_oci8_11g.dll ; Use with Oracle 11gR2 Instant Client
+;extension=php_openssl.dll
+;extension=php_pdo_firebird.dll
+;extension=php_pdo_mysql.dll
+;extension=php_pdo_oci.dll
+;extension=php_pdo_odbc.dll
+;extension=php_pdo_pgsql.dll
+;extension=php_pdo_sqlite.dll
+;extension=php_pgsql.dll
+;extension=php_pspell.dll
+;extension=php_shmop.dll
+
+; The MIBS data available in the PHP distribution must be installed.
+; See http://www.php.net/manual/en/snmp.installation.php
+;extension=php_snmp.dll
+
+;extension=php_soap.dll
+;extension=php_sockets.dll
+;extension=php_sqlite3.dll
+;extension=php_sybase_ct.dll
+;extension=php_tidy.dll
+;extension=php_xmlrpc.dll
+;extension=php_xsl.dll
+
+;;;;;;;;;;;;;;;;;;;
+; Module Settings ;
+;;;;;;;;;;;;;;;;;;;
+
+[CLI Server]
+; Whether the CLI web server uses ANSI color coding in its terminal output.
+cli_server.color = On
+
+[Date]
+; Defines the default timezone used by the date functions
+; http://php.net/date.timezone
+date.timezone = Asia/Shanghai
+
+; http://php.net/date.default-latitude
+;date.default_latitude = 31.7667
+
+; http://php.net/date.default-longitude
+;date.default_longitude = 35.2333
+
+; http://php.net/date.sunrise-zenith
+;date.sunrise_zenith = 90.583333
+
+; http://php.net/date.sunset-zenith
+;date.sunset_zenith = 90.583333
+
+[filter]
+; http://php.net/filter.default
+;filter.default = unsafe_raw
+
+; http://php.net/filter.default-flags
+;filter.default_flags =
+
+[iconv]
+;iconv.input_encoding = ISO-8859-1
+;iconv.internal_encoding = ISO-8859-1
+;iconv.output_encoding = ISO-8859-1
+
+[intl]
+;intl.default_locale =
+; This directive allows you to produce PHP errors when some error
+; happens within intl functions. The value is the level of the error produced.
+; Default is 0, which does not produce any errors.
+;intl.error_level = E_WARNING
+
+[sqlite]
+; http://php.net/sqlite.assoc-case
+;sqlite.assoc_case = 0
+
+[sqlite3]
+;sqlite3.extension_dir =
+
+[Pcre]
+;PCRE library backtracking limit.
+; http://php.net/pcre.backtrack-limit
+;pcre.backtrack_limit=100000
+
+;PCRE library recursion limit.
+;Please note that if you set this value to a high number you may consume all
+;the available process stack and eventually crash PHP (due to reaching the
+;stack size limit imposed by the Operating System).
+; http://php.net/pcre.recursion-limit
+;pcre.recursion_limit=100000
+
+[Pdo]
+; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off"
+; http://php.net/pdo-odbc.connection-pooling
+;pdo_odbc.connection_pooling=strict
+
+;pdo_odbc.db2_instance_name
+
+[Pdo_mysql]
+; If mysqlnd is used: Number of cache slots for the internal result set cache
+; http://php.net/pdo_mysql.cache_size
+pdo_mysql.cache_size = 2000
+
+; Default socket name for local MySQL connects. If empty, uses the built-in
+; MySQL defaults.
+; http://php.net/pdo_mysql.default-socket
+pdo_mysql.default_socket=
+
+[Phar]
+; http://php.net/phar.readonly
+;phar.readonly = On
+
+; http://php.net/phar.require-hash
+;phar.require_hash = On
+
+;phar.cache_list =
+
+[mail function]
+; For Win32 only.
+; http://php.net/smtp
+SMTP = localhost
+; http://php.net/smtp-port
+smtp_port = 25
+
+; For Win32 only.
+; http://php.net/sendmail-from
+;sendmail_from = me@example.com
+
+; For Unix only. You may supply arguments as well (default: "sendmail -t -i").
+; http://php.net/sendmail-path
+;sendmail_path =
+
+; Force the addition of the specified parameters to be passed as extra parameters
+; to the sendmail binary. These parameters will always replace the value of
+; the 5th parameter to mail(), even in safe mode.
+;mail.force_extra_parameters =
+
+; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename
+mail.add_x_header = On
+
+; The path to a log file that will log all mail() calls. Log entries include
+; the full path of the script, line number, To address and headers.
+;mail.log =
+; Log mail to syslog (Event Log on Windows).
+;mail.log = syslog
+
+[SQL]
+; http://php.net/sql.safe-mode
+sql.safe_mode = Off
+
+[ODBC]
+; http://php.net/odbc.default-db
+;odbc.default_db = Not yet implemented
+
+; http://php.net/odbc.default-user
+;odbc.default_user = Not yet implemented
+
+; http://php.net/odbc.default-pw
+;odbc.default_pw = Not yet implemented
+
+; Controls the ODBC cursor model.
+; Default: SQL_CURSOR_STATIC (default).
+;odbc.default_cursortype
+
+; Allow or prevent persistent links.
+; http://php.net/odbc.allow-persistent
+odbc.allow_persistent = On
+
+; Check that a connection is still valid before reuse.
+; http://php.net/odbc.check-persistent
+odbc.check_persistent = On
+
+; Maximum number of persistent links. -1 means no limit.
+; http://php.net/odbc.max-persistent
+odbc.max_persistent = -1
+
+; Maximum number of links (persistent + non-persistent). -1 means no limit.
+; http://php.net/odbc.max-links
+odbc.max_links = -1
+
+; Handling of LONG fields. Returns number of bytes to variables. 0 means
+; passthru.
+; http://php.net/odbc.defaultlrl
+odbc.defaultlrl = 4096
+
+; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char.
+; See the documentation on odbc_binmode and odbc_longreadlen for an explanation
+; of odbc.defaultlrl and odbc.defaultbinmode
+; http://php.net/odbc.defaultbinmode
+odbc.defaultbinmode = 1
+
+;birdstep.max_links = -1
+
+[Interbase]
+; Allow or prevent persistent links.
+ibase.allow_persistent = 1
+
+; Maximum number of persistent links. -1 means no limit.
+ibase.max_persistent = -1
+
+; Maximum number of links (persistent + non-persistent). -1 means no limit.
+ibase.max_links = -1
+
+; Default database name for ibase_connect().
+;ibase.default_db =
+
+; Default username for ibase_connect().
+;ibase.default_user =
+
+; Default password for ibase_connect().
+;ibase.default_password =
+
+; Default charset for ibase_connect().
+;ibase.default_charset =
+
+; Default timestamp format.
+ibase.timestampformat = "%Y-%m-%d %H:%M:%S"
+
+; Default date format.
+ibase.dateformat = "%Y-%m-%d"
+
+; Default time format.
+ibase.timeformat = "%H:%M:%S"
+
+[MySQL]
+; Allow accessing, from PHP's perspective, local files with LOAD DATA statements
+; http://php.net/mysql.allow_local_infile
+mysql.allow_local_infile = On
+
+; Allow or prevent persistent links.
+; http://php.net/mysql.allow-persistent
+mysql.allow_persistent = On
+
+; If mysqlnd is used: Number of cache slots for the internal result set cache
+; http://php.net/mysql.cache_size
+mysql.cache_size = 2000
+
+; Maximum number of persistent links. -1 means no limit.
+; http://php.net/mysql.max-persistent
+mysql.max_persistent = -1
+
+; Maximum number of links (persistent + non-persistent). -1 means no limit.
+; http://php.net/mysql.max-links
+mysql.max_links = -1
+
+; Default port number for mysql_connect(). If unset, mysql_connect() will use
+; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the
+; compile-time value defined MYSQL_PORT (in that order). Win32 will only look
+; at MYSQL_PORT.
+; http://php.net/mysql.default-port
+mysql.default_port =
+
+; Default socket name for local MySQL connects. If empty, uses the built-in
+; MySQL defaults.
+; http://php.net/mysql.default-socket
+mysql.default_socket =
+
+; Default host for mysql_connect() (doesn't apply in safe mode).
+; http://php.net/mysql.default-host
+mysql.default_host =
+
+; Default user for mysql_connect() (doesn't apply in safe mode).
+; http://php.net/mysql.default-user
+mysql.default_user =
+
+; Default password for mysql_connect() (doesn't apply in safe mode).
+; Note that this is generally a *bad* idea to store passwords in this file.
+; *Any* user with PHP access can run 'echo get_cfg_var("mysql.default_password")
+; and reveal this password! And of course, any users with read access to this
+; file will be able to reveal the password as well.
+; http://php.net/mysql.default-password
+mysql.default_password =
+
+; Maximum time (in seconds) for connect timeout. -1 means no limit
+; http://php.net/mysql.connect-timeout
+mysql.connect_timeout = 60
+
+; Trace mode. When trace_mode is active (=On), warnings for table/index scans and
+; SQL-Errors will be displayed.
+; http://php.net/mysql.trace-mode
+mysql.trace_mode = Off
+
+[MySQLi]
+
+; Maximum number of persistent links. -1 means no limit.
+; http://php.net/mysqli.max-persistent
+mysqli.max_persistent = -1
+
+; Allow accessing, from PHP's perspective, local files with LOAD DATA statements
+; http://php.net/mysqli.allow_local_infile
+;mysqli.allow_local_infile = On
+
+; Allow or prevent persistent links.
+; http://php.net/mysqli.allow-persistent
+mysqli.allow_persistent = On
+
+; Maximum number of links. -1 means no limit.
+; http://php.net/mysqli.max-links
+mysqli.max_links = -1
+
+; If mysqlnd is used: Number of cache slots for the internal result set cache
+; http://php.net/mysqli.cache_size
+mysqli.cache_size = 2000
+
+; Default port number for mysqli_connect(). If unset, mysqli_connect() will use
+; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the
+; compile-time value defined MYSQL_PORT (in that order). Win32 will only look
+; at MYSQL_PORT.
+; http://php.net/mysqli.default-port
+mysqli.default_port = 3306
+
+; Default socket name for local MySQL connects. If empty, uses the built-in
+; MySQL defaults.
+; http://php.net/mysqli.default-socket
+mysqli.default_socket =
+
+; Default host for mysql_connect() (doesn't apply in safe mode).
+; http://php.net/mysqli.default-host
+mysqli.default_host =
+
+; Default user for mysql_connect() (doesn't apply in safe mode).
+; http://php.net/mysqli.default-user
+mysqli.default_user =
+
+; Default password for mysqli_connect() (doesn't apply in safe mode).
+; Note that this is generally a *bad* idea to store passwords in this file.
+; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw")
+; and reveal this password! And of course, any users with read access to this
+; file will be able to reveal the password as well.
+; http://php.net/mysqli.default-pw
+mysqli.default_pw =
+
+; Allow or prevent reconnect
+mysqli.reconnect = Off
+
+[mysqlnd]
+; Enable / Disable collection of general statistics by mysqlnd which can be
+; used to tune and monitor MySQL operations.
+; http://php.net/mysqlnd.collect_statistics
+mysqlnd.collect_statistics = On
+
+; Enable / Disable collection of memory usage statistics by mysqlnd which can be
+; used to tune and monitor MySQL operations.
+; http://php.net/mysqlnd.collect_memory_statistics
+mysqlnd.collect_memory_statistics = Off
+
+; Size of a pre-allocated buffer used when sending commands to MySQL in bytes.
+; http://php.net/mysqlnd.net_cmd_buffer_size
+;mysqlnd.net_cmd_buffer_size = 2048
+
+; Size of a pre-allocated buffer used for reading data sent by the server in
+; bytes.
+; http://php.net/mysqlnd.net_read_buffer_size
+;mysqlnd.net_read_buffer_size = 32768
+
+[OCI8]
+
+; Connection: Enables privileged connections using external
+; credentials (OCI_SYSOPER, OCI_SYSDBA)
+; http://php.net/oci8.privileged-connect
+;oci8.privileged_connect = Off
+
+; Connection: The maximum number of persistent OCI8 connections per
+; process. Using -1 means no limit.
+; http://php.net/oci8.max-persistent
+;oci8.max_persistent = -1
+
+; Connection: The maximum number of seconds a process is allowed to
+; maintain an idle persistent connection. Using -1 means idle
+; persistent connections will be maintained forever.
+; http://php.net/oci8.persistent-timeout
+;oci8.persistent_timeout = -1
+
+; Connection: The number of seconds that must pass before issuing a
+; ping during oci_pconnect() to check the connection validity. When
+; set to 0, each oci_pconnect() will cause a ping. Using -1 disables
+; pings completely.
+; http://php.net/oci8.ping-interval
+;oci8.ping_interval = 60
+
+; Connection: Set this to a user chosen connection class to be used
+; for all pooled server requests with Oracle 11g Database Resident
+; Connection Pooling (DRCP). To use DRCP, this value should be set to
+; the same string for all web servers running the same application,
+; the database pool must be configured, and the connection string must
+; specify to use a pooled server.
+;oci8.connection_class =
+
+; High Availability: Using On lets PHP receive Fast Application
+; Notification (FAN) events generated when a database node fails. The
+; database must also be configured to post FAN events.
+;oci8.events = Off
+
+; Tuning: This option enables statement caching, and specifies how
+; many statements to cache. Using 0 disables statement caching.
+; http://php.net/oci8.statement-cache-size
+;oci8.statement_cache_size = 20
+
+; Tuning: Enables statement prefetching and sets the default number of
+; rows that will be fetched automatically after statement execution.
+; http://php.net/oci8.default-prefetch
+;oci8.default_prefetch = 100
+
+; Compatibility. Using On means oci_close() will not close
+; oci_connect() and oci_new_connect() connections.
+; http://php.net/oci8.old-oci-close-semantics
+;oci8.old_oci_close_semantics = Off
+
+[PostgreSQL]
+; Allow or prevent persistent links.
+; http://php.net/pgsql.allow-persistent
+pgsql.allow_persistent = On
+
+; Detect broken persistent links always with pg_pconnect().
+; Auto reset feature requires a little overheads.
+; http://php.net/pgsql.auto-reset-persistent
+pgsql.auto_reset_persistent = Off
+
+; Maximum number of persistent links. -1 means no limit.
+; http://php.net/pgsql.max-persistent
+pgsql.max_persistent = -1
+
+; Maximum number of links (persistent+non persistent). -1 means no limit.
+; http://php.net/pgsql.max-links
+pgsql.max_links = -1
+
+; Ignore PostgreSQL backends Notice message or not.
+; Notice message logging require a little overheads.
+; http://php.net/pgsql.ignore-notice
+pgsql.ignore_notice = 0
+
+; Log PostgreSQL backends Notice message or not.
+; Unless pgsql.ignore_notice=0, module cannot log notice message.
+; http://php.net/pgsql.log-notice
+pgsql.log_notice = 0
+
+[Sybase-CT]
+; Allow or prevent persistent links.
+; http://php.net/sybct.allow-persistent
+sybct.allow_persistent = On
+
+; Maximum number of persistent links. -1 means no limit.
+; http://php.net/sybct.max-persistent
+sybct.max_persistent = -1
+
+; Maximum number of links (persistent + non-persistent). -1 means no limit.
+; http://php.net/sybct.max-links
+sybct.max_links = -1
+
+; Minimum server message severity to display.
+; http://php.net/sybct.min-server-severity
+sybct.min_server_severity = 10
+
+; Minimum client message severity to display.
+; http://php.net/sybct.min-client-severity
+sybct.min_client_severity = 10
+
+; Set per-context timeout
+; http://php.net/sybct.timeout
+;sybct.timeout=
+
+;sybct.packet_size
+
+; The maximum time in seconds to wait for a connection attempt to succeed before returning failure.
+; Default: one minute
+;sybct.login_timeout=
+
+; The name of the host you claim to be connecting from, for display by sp_who.
+; Default: none
+;sybct.hostname=
+
+; Allows you to define how often deadlocks are to be retried. -1 means "forever".
+; Default: 0
+;sybct.deadlock_retry_count=
+
+[bcmath]
+; Number of decimal digits for all bcmath functions.
+; http://php.net/bcmath.scale
+bcmath.scale = 0
+
+[browscap]
+; http://php.net/browscap
+;browscap = extra/browscap.ini
+
+[Session]
+; Handler used to store/retrieve data.
+; http://php.net/session.save-handler
+session.save_handler = files
+
+; Argument passed to save_handler. In the case of files, this is the path
+; where data files are stored. Note: Windows users have to change this
+; variable in order to use PHP's session functions.
+;
+; The path can be defined as:
+;
+; session.save_path = "N;/path"
+;
+; where N is an integer. Instead of storing all the session files in
+; /path, what this will do is use subdirectories N-levels deep, and
+; store the session data in those directories. This is useful if you
+; or your OS have problems with lots of files in one directory, and is
+; a more efficient layout for servers that handle lots of sessions.
+;
+; NOTE 1: PHP will not create this directory structure automatically.
+; You can use the script in the ext/session dir for that purpose.
+; NOTE 2: See the section on garbage collection below if you choose to
+; use subdirectories for session storage
+;
+; The file storage module creates files using mode 600 by default.
+; You can change that by using
+;
+; session.save_path = "N;MODE;/path"
+;
+; where MODE is the octal representation of the mode. Note that this
+; does not overwrite the process's umask.
+; http://php.net/session.save-path
+;session.save_path = "/tmp"
+
+; Whether to use cookies.
+; http://php.net/session.use-cookies
+session.use_cookies = 1
+
+; http://php.net/session.cookie-secure
+;session.cookie_secure =
+
+; This option forces PHP to fetch and use a cookie for storing and maintaining
+; the session id. We encourage this operation as it's very helpful in combating
+; session hijacking when not specifying and managing your own session id. It is
+; not the end all be all of session hijacking defense, but it's a good start.
+; http://php.net/session.use-only-cookies
+session.use_only_cookies = 1
+
+; Name of the session (used as cookie name).
+; http://php.net/session.name
+session.name = PHPSESSID
+
+; Initialize session on request startup.
+; http://php.net/session.auto-start
+session.auto_start = 0
+
+; Lifetime in seconds of cookie or, if 0, until browser is restarted.
+; http://php.net/session.cookie-lifetime
+session.cookie_lifetime = 0
+
+; The path for which the cookie is valid.
+; http://php.net/session.cookie-path
+session.cookie_path = /
+
+; The domain for which the cookie is valid.
+; http://php.net/session.cookie-domain
+session.cookie_domain =
+
+; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript.
+; http://php.net/session.cookie-httponly
+session.cookie_httponly =
+
+; Handler used to serialize data. php is the standard serializer of PHP.
+; http://php.net/session.serialize-handler
+session.serialize_handler = php
+
+; Defines the probability that the 'garbage collection' process is started
+; on every session initialization. The probability is calculated by using
+; gc_probability/gc_divisor. Where session.gc_probability is the numerator
+; and gc_divisor is the denominator in the equation. Setting this value to 1
+; when the session.gc_divisor value is 100 will give you approximately a 1% chance
+; the gc will run on any give request.
+; Default Value: 1
+; Development Value: 1
+; Production Value: 1
+; http://php.net/session.gc-probability
+session.gc_probability = 1
+
+; Defines the probability that the 'garbage collection' process is started on every
+; session initialization. The probability is calculated by using the following equation:
+; gc_probability/gc_divisor. Where session.gc_probability is the numerator and
+; session.gc_divisor is the denominator in the equation. Setting this value to 1
+; when the session.gc_divisor value is 100 will give you approximately a 1% chance
+; the gc will run on any give request. Increasing this value to 1000 will give you
+; a 0.1% chance the gc will run on any give request. For high volume production servers,
+; this is a more efficient approach.
+; Default Value: 100
+; Development Value: 1000
+; Production Value: 1000
+; http://php.net/session.gc-divisor
+session.gc_divisor = 1000
+
+; After this number of seconds, stored data will be seen as 'garbage' and
+; cleaned up by the garbage collection process.
+; http://php.net/session.gc-maxlifetime
+session.gc_maxlifetime = 1440
+
+; NOTE: If you are using the subdirectory option for storing session files
+; (see session.save_path above), then garbage collection does *not*
+; happen automatically. You will need to do your own garbage
+; collection through a shell script, cron entry, or some other method.
+; For example, the following script would is the equivalent of
+; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes):
+; find /path/to/sessions -cmin +24 -type f | xargs rm
+
+; Check HTTP Referer to invalidate externally stored URLs containing ids.
+; HTTP_REFERER has to contain this substring for the session to be
+; considered as valid.
+; http://php.net/session.referer-check
+session.referer_check =
+
+; How many bytes to read from the file.
+; http://php.net/session.entropy-length
+;session.entropy_length = 32
+
+; Specified here to create the session id.
+; http://php.net/session.entropy-file
+; Defaults to /dev/urandom
+; On systems that don't have /dev/urandom but do have /dev/arandom, this will default to /dev/arandom
+; If neither are found at compile time, the default is no entropy file.
+; On windows, setting the entropy_length setting will activate the
+; Windows random source (using the CryptoAPI)
+;session.entropy_file = /dev/urandom
+
+; Set to {nocache,private,public,} to determine HTTP caching aspects
+; or leave this empty to avoid sending anti-caching headers.
+; http://php.net/session.cache-limiter
+session.cache_limiter = nocache
+
+; Document expires after n minutes.
+; http://php.net/session.cache-expire
+session.cache_expire = 180
+
+; trans sid support is disabled by default.
+; Use of trans sid may risk your users security.
+; Use this option with caution.
+; - User may send URL contains active session ID
+; to other person via. email/irc/etc.
+; - URL that contains active session ID may be stored
+; in publicly accessible computer.
+; - User may access your site with the same session ID
+; always using URL stored in browser's history or bookmarks.
+; http://php.net/session.use-trans-sid
+session.use_trans_sid = 0
+
+; Select a hash function for use in generating session ids.
+; Possible Values
+; 0 (MD5 128 bits)
+; 1 (SHA-1 160 bits)
+; This option may also be set to the name of any hash function supported by
+; the hash extension. A list of available hashes is returned by the hash_algos()
+; function.
+; http://php.net/session.hash-function
+session.hash_function = 0
+
+; Define how many bits are stored in each character when converting
+; the binary hash data to something readable.
+; Possible values:
+; 4 (4 bits: 0-9, a-f)
+; 5 (5 bits: 0-9, a-v)
+; 6 (6 bits: 0-9, a-z, A-Z, "-", ",")
+; Default Value: 4
+; Development Value: 5
+; Production Value: 5
+; http://php.net/session.hash-bits-per-character
+session.hash_bits_per_character = 5
+
+; The URL rewriter will look for URLs in a defined set of HTML tags.
+; form/fieldset are special; if you include them here, the rewriter will
+; add a hidden field with the info which is otherwise appended
+; to URLs. If you want XHTML conformity, remove the form entry.
+; Note that all valid entries require a "=", even if no value follows.
+; Default Value: "a=href,area=href,frame=src,form=,fieldset="
+; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry"
+; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry"
+; http://php.net/url-rewriter.tags
+url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry"
+
+; Enable upload progress tracking in $_SESSION
+; Default Value: On
+; Development Value: On
+; Production Value: On
+; http://php.net/session.upload-progress.enabled
+;session.upload_progress.enabled = On
+
+; Cleanup the progress information as soon as all POST data has been read
+; (i.e. upload completed).
+; Default Value: On
+; Development Value: On
+; Production Value: On
+; http://php.net/session.upload-progress.cleanup
+;session.upload_progress.cleanup = On
+
+; A prefix used for the upload progress key in $_SESSION
+; Default Value: "upload_progress_"
+; Development Value: "upload_progress_"
+; Production Value: "upload_progress_"
+; http://php.net/session.upload-progress.prefix
+;session.upload_progress.prefix = "upload_progress_"
+
+; The index name (concatenated with the prefix) in $_SESSION
+; containing the upload progress information
+; Default Value: "PHP_SESSION_UPLOAD_PROGRESS"
+; Development Value: "PHP_SESSION_UPLOAD_PROGRESS"
+; Production Value: "PHP_SESSION_UPLOAD_PROGRESS"
+; http://php.net/session.upload-progress.name
+;session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
+
+; How frequently the upload progress should be updated.
+; Given either in percentages (per-file), or in bytes
+; Default Value: "1%"
+; Development Value: "1%"
+; Production Value: "1%"
+; http://php.net/session.upload-progress.freq
+;session.upload_progress.freq = "1%"
+
+; The minimum delay between updates, in seconds
+; Default Value: 1
+; Development Value: 1
+; Production Value: 1
+; http://php.net/session.upload-progress.min-freq
+;session.upload_progress.min_freq = "1"
+
+[MSSQL]
+; Allow or prevent persistent links.
+mssql.allow_persistent = On
+
+; Maximum number of persistent links. -1 means no limit.
+mssql.max_persistent = -1
+
+; Maximum number of links (persistent+non persistent). -1 means no limit.
+mssql.max_links = -1
+
+; Minimum error severity to display.
+mssql.min_error_severity = 10
+
+; Minimum message severity to display.
+mssql.min_message_severity = 10
+
+; Compatibility mode with old versions of PHP 3.0.
+mssql.compatability_mode = Off
+
+; Connect timeout
+;mssql.connect_timeout = 5
+
+; Query timeout
+;mssql.timeout = 60
+
+; Valid range 0 - 2147483647. Default = 4096.
+;mssql.textlimit = 4096
+
+; Valid range 0 - 2147483647. Default = 4096.
+;mssql.textsize = 4096
+
+; Limits the number of records in each batch. 0 = all records in one batch.
+;mssql.batchsize = 0
+
+; Specify how datetime and datetim4 columns are returned
+; On => Returns data converted to SQL server settings
+; Off => Returns values as YYYY-MM-DD hh:mm:ss
+;mssql.datetimeconvert = On
+
+; Use NT authentication when connecting to the server
+mssql.secure_connection = Off
+
+; Specify max number of processes. -1 = library default
+; msdlib defaults to 25
+; FreeTDS defaults to 4096
+;mssql.max_procs = -1
+
+; Specify client character set.
+; If empty or not set the client charset from freetds.conf is used
+; This is only used when compiled with FreeTDS
+;mssql.charset = "ISO-8859-1"
+
+[Assertion]
+; Assert(expr); active by default.
+; http://php.net/assert.active
+;assert.active = On
+
+; Issue a PHP warning for each failed assertion.
+; http://php.net/assert.warning
+;assert.warning = On
+
+; Don't bail out by default.
+; http://php.net/assert.bail
+;assert.bail = Off
+
+; User-function to be called if an assertion fails.
+; http://php.net/assert.callback
+;assert.callback = 0
+
+; Eval the expression with current error_reporting(). Set to true if you want
+; error_reporting(0) around the eval().
+; http://php.net/assert.quiet-eval
+;assert.quiet_eval = 0
+
+[COM]
+; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs
+; http://php.net/com.typelib-file
+;com.typelib_file =
+
+; allow Distributed-COM calls
+; http://php.net/com.allow-dcom
+;com.allow_dcom = true
+
+; autoregister constants of a components typlib on com_load()
+; http://php.net/com.autoregister-typelib
+;com.autoregister_typelib = true
+
+; register constants casesensitive
+; http://php.net/com.autoregister-casesensitive
+;com.autoregister_casesensitive = false
+
+; show warnings on duplicate constant registrations
+; http://php.net/com.autoregister-verbose
+;com.autoregister_verbose = true
+
+; The default character set code-page to use when passing strings to and from COM objects.
+; Default: system ANSI code page
+;com.code_page=
+
+[mbstring]
+; language for internal character representation.
+; http://php.net/mbstring.language
+;mbstring.language = Japanese
+
+; internal/script encoding.
+; Some encoding cannot work as internal encoding.
+; (e.g. SJIS, BIG5, ISO-2022-*)
+; http://php.net/mbstring.internal-encoding
+;mbstring.internal_encoding = EUC-JP
+
+; http input encoding.
+; http://php.net/mbstring.http-input
+;mbstring.http_input = auto
+
+; http output encoding. mb_output_handler must be
+; registered as output buffer to function
+; http://php.net/mbstring.http-output
+;mbstring.http_output = SJIS
+
+; enable automatic encoding translation according to
+; mbstring.internal_encoding setting. Input chars are
+; converted to internal encoding by setting this to On.
+; Note: Do _not_ use automatic encoding translation for
+; portable libs/applications.
+; http://php.net/mbstring.encoding-translation
+;mbstring.encoding_translation = Off
+
+; automatic encoding detection order.
+; auto means
+; http://php.net/mbstring.detect-order
+;mbstring.detect_order = auto
+
+; substitute_character used when character cannot be converted
+; one from another
+; http://php.net/mbstring.substitute-character
+;mbstring.substitute_character = none;
+
+; overload(replace) single byte functions by mbstring functions.
+; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(),
+; etc. Possible values are 0,1,2,4 or combination of them.
+; For example, 7 for overload everything.
+; 0: No overload
+; 1: Overload mail() function
+; 2: Overload str*() functions
+; 4: Overload ereg*() functions
+; http://php.net/mbstring.func-overload
+;mbstring.func_overload = 0
+
+; enable strict encoding detection.
+;mbstring.strict_detection = Off
+
+; This directive specifies the regex pattern of content types for which mb_output_handler()
+; is activated.
+; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml)
+;mbstring.http_output_conv_mimetype=
+
+[gd]
+; Tell the jpeg decode to ignore warnings and try to create
+; a gd image. The warning will then be displayed as notices
+; disabled by default
+; http://php.net/gd.jpeg-ignore-warning
+;gd.jpeg_ignore_warning = 0
+
+[exif]
+; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS.
+; With mbstring support this will automatically be converted into the encoding
+; given by corresponding encode setting. When empty mbstring.internal_encoding
+; is used. For the decode settings you can distinguish between motorola and
+; intel byte order. A decode setting cannot be empty.
+; http://php.net/exif.encode-unicode
+;exif.encode_unicode = ISO-8859-15
+
+; http://php.net/exif.decode-unicode-motorola
+;exif.decode_unicode_motorola = UCS-2BE
+
+; http://php.net/exif.decode-unicode-intel
+;exif.decode_unicode_intel = UCS-2LE
+
+; http://php.net/exif.encode-jis
+;exif.encode_jis =
+
+; http://php.net/exif.decode-jis-motorola
+;exif.decode_jis_motorola = JIS
+
+; http://php.net/exif.decode-jis-intel
+;exif.decode_jis_intel = JIS
+
+[Tidy]
+; The path to a default tidy configuration file to use when using tidy
+; http://php.net/tidy.default-config
+;tidy.default_config = /usr/local/lib/php/default.tcfg
+
+; Should tidy clean and repair output automatically?
+; WARNING: Do not use this option if you are generating non-html content
+; such as dynamic images
+; http://php.net/tidy.clean-output
+tidy.clean_output = Off
+
+[soap]
+; Enables or disables WSDL caching feature.
+; http://php.net/soap.wsdl-cache-enabled
+soap.wsdl_cache_enabled=1
+
+; Sets the directory name where SOAP extension will put cache files.
+; http://php.net/soap.wsdl-cache-dir
+soap.wsdl_cache_dir="/tmp"
+
+; (time to live) Sets the number of second while cached file will be used
+; instead of original one.
+; http://php.net/soap.wsdl-cache-ttl
+soap.wsdl_cache_ttl=86400
+
+; Sets the size of the cache limit. (Max. number of WSDL files to cache)
+soap.wsdl_cache_limit = 5
+
+[sysvshm]
+; A default size of the shared memory segment
+;sysvshm.init_mem = 10000
+
+[ldap]
+; Sets the maximum number of open links or -1 for unlimited.
+ldap.max_links = -1
+
+[mcrypt]
+; For more information about mcrypt settings see http://php.net/mcrypt-module-open
+
+; Directory where to load mcrypt algorithms
+; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt)
+;mcrypt.algorithms_dir=
+
+; Directory where to load mcrypt modes
+; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt)
+;mcrypt.modes_dir=
+
+[dba]
+;dba.default_handler=
+
+[curl]
+; A default value for the CURLOPT_CAINFO option. This is required to be an
+; absolute path.
+;curl.cainfo =
+
+; Local Variables:
+; tab-width: 4
+; End:
+
+[ZendGuardLoader]
+zend_loader.enable=1
+zend_extension=/ewomail/ZendGuardLoader/ZendGuardLoader.so
+zend_loader.disable_licensing=0
+zend_loader.obfuscation_level_support=3
diff --git a/install/soft/php-fpm.init b/install/soft/php-fpm.init
new file mode 100644
index 0000000..450ac8e
--- /dev/null
+++ b/install/soft/php-fpm.init
@@ -0,0 +1,152 @@
+#! /bin/sh
+
+### BEGIN INIT INFO
+# Provides: php-fpm
+# Required-Start: $remote_fs $network
+# Required-Stop: $remote_fs $network
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: starts php-fpm
+# Description: starts the PHP FastCGI Process Manager daemon
+### END INIT INFO
+
+prefix=/ewomail/php54
+exec_prefix=${prefix}
+
+php_fpm_BIN=${exec_prefix}/sbin/php-fpm
+php_fpm_CONF=${prefix}/etc/php-fpm.conf
+php_fpm_PID=${prefix}/var/run/php-fpm.pid
+
+
+php_opts="--fpm-config $php_fpm_CONF --pid $php_fpm_PID"
+
+
+wait_for_pid () {
+ try=0
+
+ while test $try -lt 35 ; do
+
+ case "$1" in
+ 'created')
+ if [ -f "$2" ] ; then
+ try=''
+ break
+ fi
+ ;;
+
+ 'removed')
+ if [ ! -f "$2" ] ; then
+ try=''
+ break
+ fi
+ ;;
+ esac
+
+ echo -n .
+ try=`expr $try + 1`
+ sleep 1
+
+ done
+
+}
+
+case "$1" in
+ start)
+ echo -n "Starting php-fpm "
+
+ $php_fpm_BIN --daemonize $php_opts
+
+ if [ "$?" != 0 ] ; then
+ echo " failed"
+ exit 1
+ fi
+
+ wait_for_pid created $php_fpm_PID
+
+ if [ -n "$try" ] ; then
+ echo " failed"
+ exit 1
+ else
+ echo " done"
+ fi
+ ;;
+
+ stop)
+ echo -n "Gracefully shutting down php-fpm "
+
+ if [ ! -r $php_fpm_PID ] ; then
+ echo "warning, no pid file found - php-fpm is not running ?"
+ exit 1
+ fi
+
+ kill -QUIT `cat $php_fpm_PID`
+
+ wait_for_pid removed $php_fpm_PID
+
+ if [ -n "$try" ] ; then
+ echo " failed. Use force-quit"
+ exit 1
+ else
+ echo " done"
+ fi
+ ;;
+
+ status)
+ if [ ! -r $php_fpm_PID ] ; then
+ echo "php-fpm is stopped"
+ exit 0
+ fi
+
+ PID=`cat $php_fpm_PID`
+ if ps -p $PID | grep -q $PID; then
+ echo "php-fpm (pid $PID) is running..."
+ else
+ echo "php-fpm dead but pid file exists"
+ fi
+ ;;
+
+ force-quit)
+ echo -n "Terminating php-fpm "
+
+ if [ ! -r $php_fpm_PID ] ; then
+ echo "warning, no pid file found - php-fpm is not running ?"
+ exit 1
+ fi
+
+ kill -TERM `cat $php_fpm_PID`
+
+ wait_for_pid removed $php_fpm_PID
+
+ if [ -n "$try" ] ; then
+ echo " failed"
+ exit 1
+ else
+ echo " done"
+ fi
+ ;;
+
+ restart)
+ $0 stop
+ $0 start
+ ;;
+
+ reload)
+
+ echo -n "Reload service php-fpm "
+
+ if [ ! -r $php_fpm_PID ] ; then
+ echo "warning, no pid file found - php-fpm is not running ?"
+ exit 1
+ fi
+
+ kill -USR2 `cat $php_fpm_PID`
+
+ echo " done"
+ ;;
+
+ *)
+ echo "Usage: $0 {start|stop|force-quit|restart|reload|status}"
+ exit 1
+ ;;
+
+esac
diff --git a/install/soft/php.ini b/install/soft/php.ini
new file mode 100644
index 0000000..0ec3a91
--- /dev/null
+++ b/install/soft/php.ini
@@ -0,0 +1,1837 @@
+[PHP]
+
+;;;;;;;;;;;;;;;;;;;
+; About php.ini ;
+;;;;;;;;;;;;;;;;;;;
+; PHP's initialization file, generally called php.ini, is responsible for
+; configuring many of the aspects of PHP's behavior.
+
+; PHP attempts to find and load this configuration from a number of locations.
+; The following is a summary of its search order:
+; 1. SAPI module specific location.
+; 2. The PHPRC environment variable. (As of PHP 5.2.0)
+; 3. A number of predefined registry keys on Windows (As of PHP 5.2.0)
+; 4. Current working directory (except CLI)
+; 5. The web server's directory (for SAPI modules), or directory of PHP
+; (otherwise in Windows)
+; 6. The directory from the --with-config-file-path compile time option, or the
+; Windows directory (C:\windows or C:\winnt)
+; See the PHP docs for more specific information.
+; http://php.net/configuration.file
+
+; The syntax of the file is extremely simple. Whitespace and lines
+; beginning with a semicolon are silently ignored (as you probably guessed).
+; Section headers (e.g. [Foo]) are also silently ignored, even though
+; they might mean something in the future.
+
+; Directives following the section heading [PATH=/www/mysite] only
+; apply to PHP files in the /www/mysite directory. Directives
+; following the section heading [HOST=www.example.com] only apply to
+; PHP files served from www.example.com. Directives set in these
+; special sections cannot be overridden by user-defined INI files or
+; at runtime. Currently, [PATH=] and [HOST=] sections only work under
+; CGI/FastCGI.
+; http://php.net/ini.sections
+
+; Directives are specified using the following syntax:
+; directive = value
+; Directive names are *case sensitive* - foo=bar is different from FOO=bar.
+; Directives are variables used to configure PHP or PHP extensions.
+; There is no name validation. If PHP can't find an expected
+; directive because it is not set or is mistyped, a default value will be used.
+
+; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one
+; of the INI constants (On, Off, True, False, Yes, No and None) or an expression
+; (e.g. E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a
+; previously set variable or directive (e.g. ${foo})
+
+; Expressions in the INI file are limited to bitwise operators and parentheses:
+; | bitwise OR
+; ^ bitwise XOR
+; & bitwise AND
+; ~ bitwise NOT
+; ! boolean NOT
+
+; Boolean flags can be turned on using the values 1, On, True or Yes.
+; They can be turned off using the values 0, Off, False or No.
+
+; An empty string can be denoted by simply not writing anything after the equal
+; sign, or by using the None keyword:
+
+; foo = ; sets foo to an empty string
+; foo = None ; sets foo to an empty string
+; foo = "None" ; sets foo to the string 'None'
+
+; If you use constants in your value, and these constants belong to a
+; dynamically loaded extension (either a PHP extension or a Zend extension),
+; you may only use these constants *after* the line that loads the extension.
+
+;;;;;;;;;;;;;;;;;;;
+; About this file ;
+;;;;;;;;;;;;;;;;;;;
+; PHP comes packaged with two INI files. One that is recommended to be used
+; in production environments and one that is recommended to be used in
+; development environments.
+
+; php.ini-production contains settings which hold security, performance and
+; best practices at its core. But please be aware, these settings may break
+; compatibility with older or less security conscience applications. We
+; recommending using the production ini in production and testing environments.
+
+; php.ini-development is very similar to its production variant, except it's
+; much more verbose when it comes to errors. We recommending using the
+; development version only in development environments as errors shown to
+; application users can inadvertently leak otherwise secure information.
+
+; This is php.ini-production INI file.
+
+;;;;;;;;;;;;;;;;;;;
+; Quick Reference ;
+;;;;;;;;;;;;;;;;;;;
+; The following are all the settings which are different in either the production
+; or development versions of the INIs with respect to PHP's default behavior.
+; Please see the actual settings later in the document for more details as to why
+; we recommend these changes in PHP's behavior.
+
+; display_errors
+; Default Value: On
+; Development Value: On
+; Production Value: Off
+
+; display_startup_errors
+; Default Value: Off
+; Development Value: On
+; Production Value: Off
+
+; error_reporting
+; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
+; Development Value: E_ALL
+; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT
+
+; html_errors
+; Default Value: On
+; Development Value: On
+; Production value: On
+
+; log_errors
+; Default Value: Off
+; Development Value: On
+; Production Value: On
+
+; max_input_time
+; Default Value: -1 (Unlimited)
+; Development Value: 60 (60 seconds)
+; Production Value: 60 (60 seconds)
+
+; output_buffering
+; Default Value: Off
+; Development Value: 4096
+; Production Value: 4096
+
+; register_argc_argv
+; Default Value: On
+; Development Value: Off
+; Production Value: Off
+
+; request_order
+; Default Value: None
+; Development Value: "GP"
+; Production Value: "GP"
+
+; session.gc_divisor
+; Default Value: 100
+; Development Value: 1000
+; Production Value: 1000
+
+; session.hash_bits_per_character
+; Default Value: 4
+; Development Value: 5
+; Production Value: 5
+
+; short_open_tag
+; Default Value: On
+; Development Value: Off
+; Production Value: Off
+
+; track_errors
+; Default Value: Off
+; Development Value: On
+; Production Value: Off
+
+; url_rewriter.tags
+; Default Value: "a=href,area=href,frame=src,form=,fieldset="
+; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry"
+; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry"
+
+; variables_order
+; Default Value: "EGPCS"
+; Development Value: "GPCS"
+; Production Value: "GPCS"
+
+;;;;;;;;;;;;;;;;;;;;
+; php.ini Options ;
+;;;;;;;;;;;;;;;;;;;;
+; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini"
+;user_ini.filename = ".user.ini"
+
+; To disable this feature set this option to empty value
+;user_ini.filename =
+
+; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes)
+;user_ini.cache_ttl = 300
+
+;;;;;;;;;;;;;;;;;;;;
+; Language Options ;
+;;;;;;;;;;;;;;;;;;;;
+
+; Enable the PHP scripting language engine under Apache.
+; http://php.net/engine
+engine = On
+
+; This directive determines whether or not PHP will recognize code between
+; and ?> tags as PHP source which should be processed as such. It is
+; generally recommended that should be used and that this feature
+; should be disabled, as enabling it may result in issues when generating XML
+; documents, however this remains supported for backward compatibility reasons.
+; Note that this directive does not control the = shorthand tag, which can be
+; used regardless of this directive.
+; Default Value: On
+; Development Value: Off
+; Production Value: Off
+; http://php.net/short-open-tag
+short_open_tag = On
+
+; Allow ASP-style <% %> tags.
+; http://php.net/asp-tags
+asp_tags = Off
+
+; The number of significant digits displayed in floating point numbers.
+; http://php.net/precision
+precision = 14
+
+; Output buffering is a mechanism for controlling how much output data
+; (excluding headers and cookies) PHP should keep internally before pushing that
+; data to the client. If your application's output exceeds this setting, PHP
+; will send that data in chunks of roughly the size you specify.
+; Turning on this setting and managing its maximum buffer size can yield some
+; interesting side-effects depending on your application and web server.
+; You may be able to send headers and cookies after you've already sent output
+; through print or echo. You also may see performance benefits if your server is
+; emitting less packets due to buffered output versus PHP streaming the output
+; as it gets it. On production servers, 4096 bytes is a good setting for performance
+; reasons.
+; Note: Output buffering can also be controlled via Output Buffering Control
+; functions.
+; Possible Values:
+; On = Enabled and buffer is unlimited. (Use with caution)
+; Off = Disabled
+; Integer = Enables the buffer and sets its maximum size in bytes.
+; Note: This directive is hardcoded to Off for the CLI SAPI
+; Default Value: Off
+; Development Value: 4096
+; Production Value: 4096
+; http://php.net/output-buffering
+output_buffering = 4096
+
+; You can redirect all of the output of your scripts to a function. For
+; example, if you set output_handler to "mb_output_handler", character
+; encoding will be transparently converted to the specified encoding.
+; Setting any output handler automatically turns on output buffering.
+; Note: People who wrote portable scripts should not depend on this ini
+; directive. Instead, explicitly set the output handler using ob_start().
+; Using this ini directive may cause problems unless you know what script
+; is doing.
+; Note: You cannot use both "mb_output_handler" with "ob_iconv_handler"
+; and you cannot use both "ob_gzhandler" and "zlib.output_compression".
+; Note: output_handler must be empty if this is set 'On' !!!!
+; Instead you must use zlib.output_handler.
+; http://php.net/output-handler
+;output_handler =
+
+; Transparent output compression using the zlib library
+; Valid values for this option are 'off', 'on', or a specific buffer size
+; to be used for compression (default is 4KB)
+; Note: Resulting chunk size may vary due to nature of compression. PHP
+; outputs chunks that are few hundreds bytes each as a result of
+; compression. If you prefer a larger chunk size for better
+; performance, enable output_buffering in addition.
+; Note: You need to use zlib.output_handler instead of the standard
+; output_handler, or otherwise the output will be corrupted.
+; http://php.net/zlib.output-compression
+zlib.output_compression = Off
+
+; http://php.net/zlib.output-compression-level
+;zlib.output_compression_level = -1
+
+; You cannot specify additional output handlers if zlib.output_compression
+; is activated here. This setting does the same as output_handler but in
+; a different order.
+; http://php.net/zlib.output-handler
+;zlib.output_handler =
+
+; Implicit flush tells PHP to tell the output layer to flush itself
+; automatically after every output block. This is equivalent to calling the
+; PHP function flush() after each and every call to print() or echo() and each
+; and every HTML block. Turning this option on has serious performance
+; implications and is generally recommended for debugging purposes only.
+; http://php.net/implicit-flush
+; Note: This directive is hardcoded to On for the CLI SAPI
+implicit_flush = Off
+
+; The unserialize callback function will be called (with the undefined class'
+; name as parameter), if the unserializer finds an undefined class
+; which should be instantiated. A warning appears if the specified function is
+; not defined, or if the function doesn't include/implement the missing class.
+; So only set this entry, if you really want to implement such a
+; callback-function.
+unserialize_callback_func =
+
+; When floats & doubles are serialized store serialize_precision significant
+; digits after the floating point. The default value ensures that when floats
+; are decoded with unserialize, the data will remain the same.
+serialize_precision = 17
+
+; open_basedir, if set, limits all file operations to the defined directory
+; and below. This directive makes most sense if used in a per-directory
+; or per-virtualhost web server configuration file. This directive is
+; *NOT* affected by whether Safe Mode is turned On or Off.
+; http://php.net/open-basedir
+;open_basedir =
+
+; This directive allows you to disable certain functions for security reasons.
+; It receives a comma-delimited list of function names. This directive is
+; *NOT* affected by whether Safe Mode is turned On or Off.
+; http://php.net/disable-functions
+disable_functions = dl,eval,assert,exec,popen,system,passthru,shell_exec,escapeshellarg,escapeshellcmd,proc_close,proc_open
+
+; This directive allows you to disable certain classes for security reasons.
+; It receives a comma-delimited list of class names. This directive is
+; *NOT* affected by whether Safe Mode is turned On or Off.
+; http://php.net/disable-classes
+disable_classes =
+
+; Colors for Syntax Highlighting mode. Anything that's acceptable in
+; would work.
+; http://php.net/syntax-highlighting
+;highlight.string = #DD0000
+;highlight.comment = #FF9900
+;highlight.keyword = #007700
+;highlight.default = #0000BB
+;highlight.html = #000000
+
+; If enabled, the request will be allowed to complete even if the user aborts
+; the request. Consider enabling it if executing long requests, which may end up
+; being interrupted by the user or a browser timing out. PHP's default behavior
+; is to disable this feature.
+; http://php.net/ignore-user-abort
+;ignore_user_abort = On
+
+; Determines the size of the realpath cache to be used by PHP. This value should
+; be increased on systems where PHP opens many files to reflect the quantity of
+; the file operations performed.
+; http://php.net/realpath-cache-size
+;realpath_cache_size = 16k
+
+; Duration of time, in seconds for which to cache realpath information for a given
+; file or directory. For systems with rarely changing files, consider increasing this
+; value.
+; http://php.net/realpath-cache-ttl
+;realpath_cache_ttl = 120
+
+; Enables or disables the circular reference collector.
+; http://php.net/zend.enable-gc
+zend.enable_gc = On
+
+; If enabled, scripts may be written in encodings that are incompatible with
+; the scanner. CP936, Big5, CP949 and Shift_JIS are the examples of such
+; encodings. To use this feature, mbstring extension must be enabled.
+; Default: Off
+;zend.multibyte = Off
+
+; Allows to set the default encoding for the scripts. This value will be used
+; unless "declare(encoding=...)" directive appears at the top of the script.
+; Only affects if zend.multibyte is set.
+; Default: ""
+;zend.script_encoding =
+
+;;;;;;;;;;;;;;;;;
+; Miscellaneous ;
+;;;;;;;;;;;;;;;;;
+
+; Decides whether PHP may expose the fact that it is installed on the server
+; (e.g. by adding its signature to the Web server header). It is no security
+; threat in any way, but it makes it possible to determine whether you use PHP
+; on your server or not.
+; http://php.net/expose-php
+expose_php = Off
+
+;;;;;;;;;;;;;;;;;;;
+; Resource Limits ;
+;;;;;;;;;;;;;;;;;;;
+
+; Maximum execution time of each script, in seconds
+; http://php.net/max-execution-time
+; Note: This directive is hardcoded to 0 for the CLI SAPI
+max_execution_time = 30
+
+; Maximum amount of time each script may spend parsing request data. It's a good
+; idea to limit this time on productions servers in order to eliminate unexpectedly
+; long running scripts.
+; Note: This directive is hardcoded to -1 for the CLI SAPI
+; Default Value: -1 (Unlimited)
+; Development Value: 60 (60 seconds)
+; Production Value: 60 (60 seconds)
+; http://php.net/max-input-time
+max_input_time = 60
+
+; Maximum input variable nesting level
+; http://php.net/max-input-nesting-level
+;max_input_nesting_level = 64
+
+; How many GET/POST/COOKIE input variables may be accepted
+; max_input_vars = 1000
+
+; Maximum amount of memory a script may consume (128MB)
+; http://php.net/memory-limit
+memory_limit = 128M
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Error handling and logging ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; This directive informs PHP of which errors, warnings and notices you would like
+; it to take action for. The recommended way of setting values for this
+; directive is through the use of the error level constants and bitwise
+; operators. The error level constants are below here for convenience as well as
+; some common settings and their meanings.
+; By default, PHP is set to take action on all errors, notices and warnings EXCEPT
+; those related to E_NOTICE and E_STRICT, which together cover best practices and
+; recommended coding standards in PHP. For performance reasons, this is the
+; recommend error reporting setting. Your production server shouldn't be wasting
+; resources complaining about best practices and coding standards. That's what
+; development servers and development settings are for.
+; Note: The php.ini-development file has this setting as E_ALL. This
+; means it pretty much reports everything which is exactly what you want during
+; development and early testing.
+;
+; Error Level Constants:
+; E_ALL - All errors and warnings (includes E_STRICT as of PHP 5.4.0)
+; E_ERROR - fatal run-time errors
+; E_RECOVERABLE_ERROR - almost fatal run-time errors
+; E_WARNING - run-time warnings (non-fatal errors)
+; E_PARSE - compile-time parse errors
+; E_NOTICE - run-time notices (these are warnings which often result
+; from a bug in your code, but it's possible that it was
+; intentional (e.g., using an uninitialized variable and
+; relying on the fact it's automatically initialized to an
+; empty string)
+; E_STRICT - run-time notices, enable to have PHP suggest changes
+; to your code which will ensure the best interoperability
+; and forward compatibility of your code
+; E_CORE_ERROR - fatal errors that occur during PHP's initial startup
+; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's
+; initial startup
+; E_COMPILE_ERROR - fatal compile-time errors
+; E_COMPILE_WARNING - compile-time warnings (non-fatal errors)
+; E_USER_ERROR - user-generated error message
+; E_USER_WARNING - user-generated warning message
+; E_USER_NOTICE - user-generated notice message
+; E_DEPRECATED - warn about code that will not work in future versions
+; of PHP
+; E_USER_DEPRECATED - user-generated deprecation warnings
+;
+; Common Values:
+; E_ALL (Show all errors, warnings and notices including coding standards.)
+; E_ALL & ~E_NOTICE (Show all errors, except for notices)
+; E_ALL & ~E_NOTICE & ~E_STRICT (Show all errors, except for notices and coding standards warnings.)
+; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors)
+; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
+; Development Value: E_ALL
+; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT
+; http://php.net/error-reporting
+error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
+
+; This directive controls whether or not and where PHP will output errors,
+; notices and warnings too. Error output is very useful during development, but
+; it could be very dangerous in production environments. Depending on the code
+; which is triggering the error, sensitive information could potentially leak
+; out of your application such as database usernames and passwords or worse.
+; It's recommended that errors be logged on production servers rather than
+; having the errors sent to STDOUT.
+; Possible Values:
+; Off = Do not display any errors
+; stderr = Display errors to STDERR (affects only CGI/CLI binaries!)
+; On or stdout = Display errors to STDOUT
+; Default Value: On
+; Development Value: On
+; Production Value: Off
+; http://php.net/display-errors
+display_errors = Off
+
+; The display of errors which occur during PHP's startup sequence are handled
+; separately from display_errors. PHP's default behavior is to suppress those
+; errors from clients. Turning the display of startup errors on can be useful in
+; debugging configuration problems. But, it's strongly recommended that you
+; leave this setting off on production servers.
+; Default Value: Off
+; Development Value: On
+; Production Value: Off
+; http://php.net/display-startup-errors
+display_startup_errors = Off
+
+; Besides displaying errors, PHP can also log errors to locations such as a
+; server-specific log, STDERR, or a location specified by the error_log
+; directive found below. While errors should not be displayed on productions
+; servers they should still be monitored and logging is a great way to do that.
+; Default Value: Off
+; Development Value: On
+; Production Value: On
+; http://php.net/log-errors
+log_errors = On
+
+; Set maximum length of log_errors. In error_log information about the source is
+; added. The default is 1024 and 0 allows to not apply any maximum length at all.
+; http://php.net/log-errors-max-len
+log_errors_max_len = 1024
+
+; Do not log repeated messages. Repeated errors must occur in same file on same
+; line unless ignore_repeated_source is set true.
+; http://php.net/ignore-repeated-errors
+ignore_repeated_errors = Off
+
+; Ignore source of message when ignoring repeated messages. When this setting
+; is On you will not log errors with repeated messages from different files or
+; source lines.
+; http://php.net/ignore-repeated-source
+ignore_repeated_source = Off
+
+; If this parameter is set to Off, then memory leaks will not be shown (on
+; stdout or in the log). This has only effect in a debug compile, and if
+; error reporting includes E_WARNING in the allowed list
+; http://php.net/report-memleaks
+report_memleaks = On
+
+; This setting is on by default.
+;report_zend_debug = 0
+
+; Store the last error/warning message in $php_errormsg (boolean). Setting this value
+; to On can assist in debugging and is appropriate for development servers. It should
+; however be disabled on production servers.
+; Default Value: Off
+; Development Value: On
+; Production Value: Off
+; http://php.net/track-errors
+track_errors = Off
+
+; Turn off normal error reporting and emit XML-RPC error XML
+; http://php.net/xmlrpc-errors
+;xmlrpc_errors = 0
+
+; An XML-RPC faultCode
+;xmlrpc_error_number = 0
+
+; When PHP displays or logs an error, it has the capability of formatting the
+; error message as HTML for easier reading. This directive controls whether
+; the error message is formatted as HTML or not.
+; Note: This directive is hardcoded to Off for the CLI SAPI
+; Default Value: On
+; Development Value: On
+; Production value: On
+; http://php.net/html-errors
+html_errors = On
+
+; If html_errors is set to On *and* docref_root is not empty, then PHP
+; produces clickable error messages that direct to a page describing the error
+; or function causing the error in detail.
+; You can download a copy of the PHP manual from http://php.net/docs
+; and change docref_root to the base URL of your local copy including the
+; leading '/'. You must also specify the file extension being used including
+; the dot. PHP's default behavior is to leave these settings empty, in which
+; case no links to documentation are generated.
+; Note: Never use this feature for production boxes.
+; http://php.net/docref-root
+; Examples
+;docref_root = "/phpmanual/"
+
+; http://php.net/docref-ext
+;docref_ext = .html
+
+; String to output before an error message. PHP's default behavior is to leave
+; this setting blank.
+; http://php.net/error-prepend-string
+; Example:
+;error_prepend_string = ""
+
+; String to output after an error message. PHP's default behavior is to leave
+; this setting blank.
+; http://php.net/error-append-string
+; Example:
+;error_append_string = " "
+
+; Log errors to specified file. PHP's default behavior is to leave this value
+; empty.
+; http://php.net/error-log
+; Example:
+;error_log = php_errors.log
+; Log errors to syslog (Event Log on Windows).
+;error_log = syslog
+
+;windows.show_crt_warning
+; Default value: 0
+; Development value: 0
+; Production value: 0
+
+;;;;;;;;;;;;;;;;;
+; Data Handling ;
+;;;;;;;;;;;;;;;;;
+
+; The separator used in PHP generated URLs to separate arguments.
+; PHP's default setting is "&".
+; http://php.net/arg-separator.output
+; Example:
+;arg_separator.output = "&"
+
+; List of separator(s) used by PHP to parse input URLs into variables.
+; PHP's default setting is "&".
+; NOTE: Every character in this directive is considered as separator!
+; http://php.net/arg-separator.input
+; Example:
+;arg_separator.input = ";&"
+
+; This directive determines which super global arrays are registered when PHP
+; starts up. G,P,C,E & S are abbreviations for the following respective super
+; globals: GET, POST, COOKIE, ENV and SERVER. There is a performance penalty
+; paid for the registration of these arrays and because ENV is not as commonly
+; used as the others, ENV is not recommended on productions servers. You
+; can still get access to the environment variables through getenv() should you
+; need to.
+; Default Value: "EGPCS"
+; Development Value: "GPCS"
+; Production Value: "GPCS";
+; http://php.net/variables-order
+variables_order = "GPCS"
+
+; This directive determines which super global data (G,P,C,E & S) should
+; be registered into the super global array REQUEST. If so, it also determines
+; the order in which that data is registered. The values for this directive are
+; specified in the same manner as the variables_order directive, EXCEPT one.
+; Leaving this value empty will cause PHP to use the value set in the
+; variables_order directive. It does not mean it will leave the super globals
+; array REQUEST empty.
+; Default Value: None
+; Development Value: "GP"
+; Production Value: "GP"
+; http://php.net/request-order
+request_order = "CGP"
+
+; This directive determines whether PHP registers $argv & $argc each time it
+; runs. $argv contains an array of all the arguments passed to PHP when a script
+; is invoked. $argc contains an integer representing the number of arguments
+; that were passed when the script was invoked. These arrays are extremely
+; useful when running scripts from the command line. When this directive is
+; enabled, registering these variables consumes CPU cycles and memory each time
+; a script is executed. For performance reasons, this feature should be disabled
+; on production servers.
+; Note: This directive is hardcoded to On for the CLI SAPI
+; Default Value: On
+; Development Value: Off
+; Production Value: Off
+; http://php.net/register-argc-argv
+register_argc_argv = Off
+
+; When enabled, the ENV, REQUEST and SERVER variables are created when they're
+; first used (Just In Time) instead of when the script starts. If these
+; variables are not used within a script, having this directive on will result
+; in a performance gain. The PHP directive register_argc_argv must be disabled
+; for this directive to have any affect.
+; http://php.net/auto-globals-jit
+auto_globals_jit = On
+
+; Whether PHP will read the POST data.
+; This option is enabled by default.
+; Most likely, you won't want to disable this option globally. It causes $_POST
+; and $_FILES to always be empty; the only way you will be able to read the
+; POST data will be through the php://input stream wrapper. This can be useful
+; to proxy requests or to process the POST data in a memory efficient fashion.
+; http://php.net/enable-post-data-reading
+;enable_post_data_reading = Off
+
+; Maximum size of POST data that PHP will accept.
+; Its value may be 0 to disable the limit. It is ignored if POST data reading
+; is disabled through enable_post_data_reading.
+; http://php.net/post-max-size
+post_max_size = 50M
+
+; Automatically add files before PHP document.
+; http://php.net/auto-prepend-file
+auto_prepend_file =
+
+; Automatically add files after PHP document.
+; http://php.net/auto-append-file
+auto_append_file =
+
+; By default, PHP will output a character encoding using
+; the Content-type: header. To disable sending of the charset, simply
+; set it to be empty.
+;
+; PHP's built-in default is text/html
+; http://php.net/default-mimetype
+default_mimetype = "text/html"
+
+; PHP's default character set is set to empty.
+; http://php.net/default-charset
+;default_charset = "UTF-8"
+
+; Always populate the $HTTP_RAW_POST_DATA variable. PHP's default behavior is
+; to disable this feature. If post reading is disabled through
+; enable_post_data_reading, $HTTP_RAW_POST_DATA is *NOT* populated.
+; http://php.net/always-populate-raw-post-data
+;always_populate_raw_post_data = On
+
+;;;;;;;;;;;;;;;;;;;;;;;;;
+; Paths and Directories ;
+;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; UNIX: "/path1:/path2"
+;include_path = ".:/php/includes"
+;
+; Windows: "\path1;\path2"
+;include_path = ".;c:\php\includes"
+;
+; PHP's default setting for include_path is ".;/path/to/php/pear"
+; http://php.net/include-path
+
+; The root of the PHP pages, used only if nonempty.
+; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root
+; if you are running php as a CGI under any web server (other than IIS)
+; see documentation for security issues. The alternate is to use the
+; cgi.force_redirect configuration below
+; http://php.net/doc-root
+doc_root =
+
+; The directory under which PHP opens the script using /~username used only
+; if nonempty.
+; http://php.net/user-dir
+user_dir =
+
+; Directory in which the loadable extensions (modules) reside.
+; http://php.net/extension-dir
+; extension_dir = "./"
+; On windows:
+; extension_dir = "ext"
+
+; Whether or not to enable the dl() function. The dl() function does NOT work
+; properly in multithreaded servers, such as IIS or Zeus, and is automatically
+; disabled on them.
+; http://php.net/enable-dl
+enable_dl = Off
+
+; cgi.force_redirect is necessary to provide security running PHP as a CGI under
+; most web servers. Left undefined, PHP turns this on by default. You can
+; turn it off here AT YOUR OWN RISK
+; **You CAN safely turn this off for IIS, in fact, you MUST.**
+; http://php.net/cgi.force-redirect
+;cgi.force_redirect = 1
+
+; if cgi.nph is enabled it will force cgi to always sent Status: 200 with
+; every request. PHP's default behavior is to disable this feature.
+;cgi.nph = 1
+
+; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape
+; (iPlanet) web servers, you MAY need to set an environment variable name that PHP
+; will look for to know it is OK to continue execution. Setting this variable MAY
+; cause security issues, KNOW WHAT YOU ARE DOING FIRST.
+; http://php.net/cgi.redirect-status-env
+;cgi.redirect_status_env =
+
+; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's
+; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
+; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting
+; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting
+; of zero causes PHP to behave as before. Default is 1. You should fix your scripts
+; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
+; http://php.net/cgi.fix-pathinfo
+;cgi.fix_pathinfo=1
+
+; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate
+; security tokens of the calling client. This allows IIS to define the
+; security context that the request runs under. mod_fastcgi under Apache
+; does not currently support this feature (03/17/2002)
+; Set to 1 if running under IIS. Default is zero.
+; http://php.net/fastcgi.impersonate
+;fastcgi.impersonate = 1
+
+; Disable logging through FastCGI connection. PHP's default behavior is to enable
+; this feature.
+;fastcgi.logging = 0
+
+; cgi.rfc2616_headers configuration option tells PHP what type of headers to
+; use when sending HTTP response code. If it's set 0 PHP sends Status: header that
+; is supported by Apache. When this option is set to 1 PHP will send
+; RFC2616 compliant header.
+; Default is zero.
+; http://php.net/cgi.rfc2616-headers
+;cgi.rfc2616_headers = 0
+
+;;;;;;;;;;;;;;;;
+; File Uploads ;
+;;;;;;;;;;;;;;;;
+
+; Whether to allow HTTP file uploads.
+; http://php.net/file-uploads
+file_uploads = On
+
+; Temporary directory for HTTP uploaded files (will use system default if not
+; specified).
+; http://php.net/upload-tmp-dir
+;upload_tmp_dir =
+
+; Maximum allowed size for uploaded files.
+; http://php.net/upload-max-filesize
+upload_max_filesize = 50M
+
+; Maximum number of files that can be uploaded via a single request
+max_file_uploads = 20
+
+;;;;;;;;;;;;;;;;;;
+; Fopen wrappers ;
+;;;;;;;;;;;;;;;;;;
+
+; Whether to allow the treatment of URLs (like http:// or ftp://) as files.
+; http://php.net/allow-url-fopen
+allow_url_fopen = On
+
+; Whether to allow include/require to open URLs (like http:// or ftp://) as files.
+; http://php.net/allow-url-include
+allow_url_include = Off
+
+; Define the anonymous ftp password (your email address). PHP's default setting
+; for this is empty.
+; http://php.net/from
+;from="john@doe.com"
+
+; Define the User-Agent string. PHP's default setting for this is empty.
+; http://php.net/user-agent
+;user_agent="PHP"
+
+; Default timeout for socket based streams (seconds)
+; http://php.net/default-socket-timeout
+default_socket_timeout = 60
+
+; If your scripts have to deal with files from Macintosh systems,
+; or you are running on a Mac and need to deal with files from
+; unix or win32 systems, setting this flag will cause PHP to
+; automatically detect the EOL character in those files so that
+; fgets() and file() will work regardless of the source of the file.
+; http://php.net/auto-detect-line-endings
+;auto_detect_line_endings = Off
+
+;;;;;;;;;;;;;;;;;;;;;;
+; Dynamic Extensions ;
+;;;;;;;;;;;;;;;;;;;;;;
+
+; If you wish to have an extension loaded automatically, use the following
+; syntax:
+;
+; extension=modulename.extension
+;
+; For example, on Windows:
+;
+; extension=msql.dll
+;
+; ... or under UNIX:
+;
+; extension=msql.so
+;
+; ... or with a path:
+;
+; extension=/path/to/extension/msql.so
+;
+; If you only provide the name of the extension, PHP will look for it in its
+; default extension directory.
+;
+; Windows Extensions
+; Note that ODBC support is built in, so no dll is needed for it.
+; Note that many DLL files are located in the extensions/ (PHP 4) ext/ (PHP 5)
+; extension folders as well as the separate PECL DLL download (PHP 5).
+; Be sure to appropriately set the extension_dir directive.
+;
+;extension=php_bz2.dll
+;extension=php_curl.dll
+;extension=php_fileinfo.dll
+;extension=php_gd2.dll
+;extension=php_gettext.dll
+;extension=php_gmp.dll
+;extension=php_intl.dll
+;extension=php_imap.dll
+;extension=php_interbase.dll
+;extension=php_ldap.dll
+;extension=php_mbstring.dll
+;extension=php_exif.dll ; Must be after mbstring as it depends on it
+;extension=php_mysql.dll
+;extension=php_mysqli.dll
+;extension=php_oci8.dll ; Use with Oracle 10gR2 Instant Client
+;extension=php_oci8_11g.dll ; Use with Oracle 11gR2 Instant Client
+;extension=php_openssl.dll
+;extension=php_pdo_firebird.dll
+;extension=php_pdo_mysql.dll
+;extension=php_pdo_oci.dll
+;extension=php_pdo_odbc.dll
+;extension=php_pdo_pgsql.dll
+;extension=php_pdo_sqlite.dll
+;extension=php_pgsql.dll
+;extension=php_pspell.dll
+;extension=php_shmop.dll
+
+; The MIBS data available in the PHP distribution must be installed.
+; See http://www.php.net/manual/en/snmp.installation.php
+;extension=php_snmp.dll
+
+;extension=php_soap.dll
+;extension=php_sockets.dll
+;extension=php_sqlite3.dll
+;extension=php_sybase_ct.dll
+;extension=php_tidy.dll
+;extension=php_xmlrpc.dll
+;extension=php_xsl.dll
+
+;;;;;;;;;;;;;;;;;;;
+; Module Settings ;
+;;;;;;;;;;;;;;;;;;;
+
+[CLI Server]
+; Whether the CLI web server uses ANSI color coding in its terminal output.
+cli_server.color = On
+
+[Date]
+; Defines the default timezone used by the date functions
+; http://php.net/date.timezone
+date.timezone = Asia/Shanghai
+
+; http://php.net/date.default-latitude
+;date.default_latitude = 31.7667
+
+; http://php.net/date.default-longitude
+;date.default_longitude = 35.2333
+
+; http://php.net/date.sunrise-zenith
+;date.sunrise_zenith = 90.583333
+
+; http://php.net/date.sunset-zenith
+;date.sunset_zenith = 90.583333
+
+[filter]
+; http://php.net/filter.default
+;filter.default = unsafe_raw
+
+; http://php.net/filter.default-flags
+;filter.default_flags =
+
+[iconv]
+;iconv.input_encoding = ISO-8859-1
+;iconv.internal_encoding = ISO-8859-1
+;iconv.output_encoding = ISO-8859-1
+
+[intl]
+;intl.default_locale =
+; This directive allows you to produce PHP errors when some error
+; happens within intl functions. The value is the level of the error produced.
+; Default is 0, which does not produce any errors.
+;intl.error_level = E_WARNING
+
+[sqlite]
+; http://php.net/sqlite.assoc-case
+;sqlite.assoc_case = 0
+
+[sqlite3]
+;sqlite3.extension_dir =
+
+[Pcre]
+;PCRE library backtracking limit.
+; http://php.net/pcre.backtrack-limit
+;pcre.backtrack_limit=100000
+
+;PCRE library recursion limit.
+;Please note that if you set this value to a high number you may consume all
+;the available process stack and eventually crash PHP (due to reaching the
+;stack size limit imposed by the Operating System).
+; http://php.net/pcre.recursion-limit
+;pcre.recursion_limit=100000
+
+[Pdo]
+; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off"
+; http://php.net/pdo-odbc.connection-pooling
+;pdo_odbc.connection_pooling=strict
+
+;pdo_odbc.db2_instance_name
+
+[Pdo_mysql]
+; If mysqlnd is used: Number of cache slots for the internal result set cache
+; http://php.net/pdo_mysql.cache_size
+pdo_mysql.cache_size = 2000
+
+; Default socket name for local MySQL connects. If empty, uses the built-in
+; MySQL defaults.
+; http://php.net/pdo_mysql.default-socket
+pdo_mysql.default_socket=
+
+[Phar]
+; http://php.net/phar.readonly
+;phar.readonly = On
+
+; http://php.net/phar.require-hash
+;phar.require_hash = On
+
+;phar.cache_list =
+
+[mail function]
+; For Win32 only.
+; http://php.net/smtp
+SMTP = localhost
+; http://php.net/smtp-port
+smtp_port = 25
+
+; For Win32 only.
+; http://php.net/sendmail-from
+;sendmail_from = me@example.com
+
+; For Unix only. You may supply arguments as well (default: "sendmail -t -i").
+; http://php.net/sendmail-path
+;sendmail_path =
+
+; Force the addition of the specified parameters to be passed as extra parameters
+; to the sendmail binary. These parameters will always replace the value of
+; the 5th parameter to mail(), even in safe mode.
+;mail.force_extra_parameters =
+
+; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename
+mail.add_x_header = On
+
+; The path to a log file that will log all mail() calls. Log entries include
+; the full path of the script, line number, To address and headers.
+;mail.log =
+; Log mail to syslog (Event Log on Windows).
+;mail.log = syslog
+
+[SQL]
+; http://php.net/sql.safe-mode
+sql.safe_mode = Off
+
+[ODBC]
+; http://php.net/odbc.default-db
+;odbc.default_db = Not yet implemented
+
+; http://php.net/odbc.default-user
+;odbc.default_user = Not yet implemented
+
+; http://php.net/odbc.default-pw
+;odbc.default_pw = Not yet implemented
+
+; Controls the ODBC cursor model.
+; Default: SQL_CURSOR_STATIC (default).
+;odbc.default_cursortype
+
+; Allow or prevent persistent links.
+; http://php.net/odbc.allow-persistent
+odbc.allow_persistent = On
+
+; Check that a connection is still valid before reuse.
+; http://php.net/odbc.check-persistent
+odbc.check_persistent = On
+
+; Maximum number of persistent links. -1 means no limit.
+; http://php.net/odbc.max-persistent
+odbc.max_persistent = -1
+
+; Maximum number of links (persistent + non-persistent). -1 means no limit.
+; http://php.net/odbc.max-links
+odbc.max_links = -1
+
+; Handling of LONG fields. Returns number of bytes to variables. 0 means
+; passthru.
+; http://php.net/odbc.defaultlrl
+odbc.defaultlrl = 4096
+
+; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char.
+; See the documentation on odbc_binmode and odbc_longreadlen for an explanation
+; of odbc.defaultlrl and odbc.defaultbinmode
+; http://php.net/odbc.defaultbinmode
+odbc.defaultbinmode = 1
+
+;birdstep.max_links = -1
+
+[Interbase]
+; Allow or prevent persistent links.
+ibase.allow_persistent = 1
+
+; Maximum number of persistent links. -1 means no limit.
+ibase.max_persistent = -1
+
+; Maximum number of links (persistent + non-persistent). -1 means no limit.
+ibase.max_links = -1
+
+; Default database name for ibase_connect().
+;ibase.default_db =
+
+; Default username for ibase_connect().
+;ibase.default_user =
+
+; Default password for ibase_connect().
+;ibase.default_password =
+
+; Default charset for ibase_connect().
+;ibase.default_charset =
+
+; Default timestamp format.
+ibase.timestampformat = "%Y-%m-%d %H:%M:%S"
+
+; Default date format.
+ibase.dateformat = "%Y-%m-%d"
+
+; Default time format.
+ibase.timeformat = "%H:%M:%S"
+
+[MySQL]
+; Allow accessing, from PHP's perspective, local files with LOAD DATA statements
+; http://php.net/mysql.allow_local_infile
+mysql.allow_local_infile = On
+
+; Allow or prevent persistent links.
+; http://php.net/mysql.allow-persistent
+mysql.allow_persistent = On
+
+; If mysqlnd is used: Number of cache slots for the internal result set cache
+; http://php.net/mysql.cache_size
+mysql.cache_size = 2000
+
+; Maximum number of persistent links. -1 means no limit.
+; http://php.net/mysql.max-persistent
+mysql.max_persistent = -1
+
+; Maximum number of links (persistent + non-persistent). -1 means no limit.
+; http://php.net/mysql.max-links
+mysql.max_links = -1
+
+; Default port number for mysql_connect(). If unset, mysql_connect() will use
+; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the
+; compile-time value defined MYSQL_PORT (in that order). Win32 will only look
+; at MYSQL_PORT.
+; http://php.net/mysql.default-port
+mysql.default_port =
+
+; Default socket name for local MySQL connects. If empty, uses the built-in
+; MySQL defaults.
+; http://php.net/mysql.default-socket
+mysql.default_socket =
+
+; Default host for mysql_connect() (doesn't apply in safe mode).
+; http://php.net/mysql.default-host
+mysql.default_host =
+
+; Default user for mysql_connect() (doesn't apply in safe mode).
+; http://php.net/mysql.default-user
+mysql.default_user =
+
+; Default password for mysql_connect() (doesn't apply in safe mode).
+; Note that this is generally a *bad* idea to store passwords in this file.
+; *Any* user with PHP access can run 'echo get_cfg_var("mysql.default_password")
+; and reveal this password! And of course, any users with read access to this
+; file will be able to reveal the password as well.
+; http://php.net/mysql.default-password
+mysql.default_password =
+
+; Maximum time (in seconds) for connect timeout. -1 means no limit
+; http://php.net/mysql.connect-timeout
+mysql.connect_timeout = 60
+
+; Trace mode. When trace_mode is active (=On), warnings for table/index scans and
+; SQL-Errors will be displayed.
+; http://php.net/mysql.trace-mode
+mysql.trace_mode = Off
+
+[MySQLi]
+
+; Maximum number of persistent links. -1 means no limit.
+; http://php.net/mysqli.max-persistent
+mysqli.max_persistent = -1
+
+; Allow accessing, from PHP's perspective, local files with LOAD DATA statements
+; http://php.net/mysqli.allow_local_infile
+;mysqli.allow_local_infile = On
+
+; Allow or prevent persistent links.
+; http://php.net/mysqli.allow-persistent
+mysqli.allow_persistent = On
+
+; Maximum number of links. -1 means no limit.
+; http://php.net/mysqli.max-links
+mysqli.max_links = -1
+
+; If mysqlnd is used: Number of cache slots for the internal result set cache
+; http://php.net/mysqli.cache_size
+mysqli.cache_size = 2000
+
+; Default port number for mysqli_connect(). If unset, mysqli_connect() will use
+; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the
+; compile-time value defined MYSQL_PORT (in that order). Win32 will only look
+; at MYSQL_PORT.
+; http://php.net/mysqli.default-port
+mysqli.default_port = 3306
+
+; Default socket name for local MySQL connects. If empty, uses the built-in
+; MySQL defaults.
+; http://php.net/mysqli.default-socket
+mysqli.default_socket =
+
+; Default host for mysql_connect() (doesn't apply in safe mode).
+; http://php.net/mysqli.default-host
+mysqli.default_host =
+
+; Default user for mysql_connect() (doesn't apply in safe mode).
+; http://php.net/mysqli.default-user
+mysqli.default_user =
+
+; Default password for mysqli_connect() (doesn't apply in safe mode).
+; Note that this is generally a *bad* idea to store passwords in this file.
+; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw")
+; and reveal this password! And of course, any users with read access to this
+; file will be able to reveal the password as well.
+; http://php.net/mysqli.default-pw
+mysqli.default_pw =
+
+; Allow or prevent reconnect
+mysqli.reconnect = Off
+
+[mysqlnd]
+; Enable / Disable collection of general statistics by mysqlnd which can be
+; used to tune and monitor MySQL operations.
+; http://php.net/mysqlnd.collect_statistics
+mysqlnd.collect_statistics = On
+
+; Enable / Disable collection of memory usage statistics by mysqlnd which can be
+; used to tune and monitor MySQL operations.
+; http://php.net/mysqlnd.collect_memory_statistics
+mysqlnd.collect_memory_statistics = Off
+
+; Size of a pre-allocated buffer used when sending commands to MySQL in bytes.
+; http://php.net/mysqlnd.net_cmd_buffer_size
+;mysqlnd.net_cmd_buffer_size = 2048
+
+; Size of a pre-allocated buffer used for reading data sent by the server in
+; bytes.
+; http://php.net/mysqlnd.net_read_buffer_size
+;mysqlnd.net_read_buffer_size = 32768
+
+[OCI8]
+
+; Connection: Enables privileged connections using external
+; credentials (OCI_SYSOPER, OCI_SYSDBA)
+; http://php.net/oci8.privileged-connect
+;oci8.privileged_connect = Off
+
+; Connection: The maximum number of persistent OCI8 connections per
+; process. Using -1 means no limit.
+; http://php.net/oci8.max-persistent
+;oci8.max_persistent = -1
+
+; Connection: The maximum number of seconds a process is allowed to
+; maintain an idle persistent connection. Using -1 means idle
+; persistent connections will be maintained forever.
+; http://php.net/oci8.persistent-timeout
+;oci8.persistent_timeout = -1
+
+; Connection: The number of seconds that must pass before issuing a
+; ping during oci_pconnect() to check the connection validity. When
+; set to 0, each oci_pconnect() will cause a ping. Using -1 disables
+; pings completely.
+; http://php.net/oci8.ping-interval
+;oci8.ping_interval = 60
+
+; Connection: Set this to a user chosen connection class to be used
+; for all pooled server requests with Oracle 11g Database Resident
+; Connection Pooling (DRCP). To use DRCP, this value should be set to
+; the same string for all web servers running the same application,
+; the database pool must be configured, and the connection string must
+; specify to use a pooled server.
+;oci8.connection_class =
+
+; High Availability: Using On lets PHP receive Fast Application
+; Notification (FAN) events generated when a database node fails. The
+; database must also be configured to post FAN events.
+;oci8.events = Off
+
+; Tuning: This option enables statement caching, and specifies how
+; many statements to cache. Using 0 disables statement caching.
+; http://php.net/oci8.statement-cache-size
+;oci8.statement_cache_size = 20
+
+; Tuning: Enables statement prefetching and sets the default number of
+; rows that will be fetched automatically after statement execution.
+; http://php.net/oci8.default-prefetch
+;oci8.default_prefetch = 100
+
+; Compatibility. Using On means oci_close() will not close
+; oci_connect() and oci_new_connect() connections.
+; http://php.net/oci8.old-oci-close-semantics
+;oci8.old_oci_close_semantics = Off
+
+[PostgreSQL]
+; Allow or prevent persistent links.
+; http://php.net/pgsql.allow-persistent
+pgsql.allow_persistent = On
+
+; Detect broken persistent links always with pg_pconnect().
+; Auto reset feature requires a little overheads.
+; http://php.net/pgsql.auto-reset-persistent
+pgsql.auto_reset_persistent = Off
+
+; Maximum number of persistent links. -1 means no limit.
+; http://php.net/pgsql.max-persistent
+pgsql.max_persistent = -1
+
+; Maximum number of links (persistent+non persistent). -1 means no limit.
+; http://php.net/pgsql.max-links
+pgsql.max_links = -1
+
+; Ignore PostgreSQL backends Notice message or not.
+; Notice message logging require a little overheads.
+; http://php.net/pgsql.ignore-notice
+pgsql.ignore_notice = 0
+
+; Log PostgreSQL backends Notice message or not.
+; Unless pgsql.ignore_notice=0, module cannot log notice message.
+; http://php.net/pgsql.log-notice
+pgsql.log_notice = 0
+
+[Sybase-CT]
+; Allow or prevent persistent links.
+; http://php.net/sybct.allow-persistent
+sybct.allow_persistent = On
+
+; Maximum number of persistent links. -1 means no limit.
+; http://php.net/sybct.max-persistent
+sybct.max_persistent = -1
+
+; Maximum number of links (persistent + non-persistent). -1 means no limit.
+; http://php.net/sybct.max-links
+sybct.max_links = -1
+
+; Minimum server message severity to display.
+; http://php.net/sybct.min-server-severity
+sybct.min_server_severity = 10
+
+; Minimum client message severity to display.
+; http://php.net/sybct.min-client-severity
+sybct.min_client_severity = 10
+
+; Set per-context timeout
+; http://php.net/sybct.timeout
+;sybct.timeout=
+
+;sybct.packet_size
+
+; The maximum time in seconds to wait for a connection attempt to succeed before returning failure.
+; Default: one minute
+;sybct.login_timeout=
+
+; The name of the host you claim to be connecting from, for display by sp_who.
+; Default: none
+;sybct.hostname=
+
+; Allows you to define how often deadlocks are to be retried. -1 means "forever".
+; Default: 0
+;sybct.deadlock_retry_count=
+
+[bcmath]
+; Number of decimal digits for all bcmath functions.
+; http://php.net/bcmath.scale
+bcmath.scale = 0
+
+[browscap]
+; http://php.net/browscap
+;browscap = extra/browscap.ini
+
+[Session]
+; Handler used to store/retrieve data.
+; http://php.net/session.save-handler
+session.save_handler = files
+
+; Argument passed to save_handler. In the case of files, this is the path
+; where data files are stored. Note: Windows users have to change this
+; variable in order to use PHP's session functions.
+;
+; The path can be defined as:
+;
+; session.save_path = "N;/path"
+;
+; where N is an integer. Instead of storing all the session files in
+; /path, what this will do is use subdirectories N-levels deep, and
+; store the session data in those directories. This is useful if you
+; or your OS have problems with lots of files in one directory, and is
+; a more efficient layout for servers that handle lots of sessions.
+;
+; NOTE 1: PHP will not create this directory structure automatically.
+; You can use the script in the ext/session dir for that purpose.
+; NOTE 2: See the section on garbage collection below if you choose to
+; use subdirectories for session storage
+;
+; The file storage module creates files using mode 600 by default.
+; You can change that by using
+;
+; session.save_path = "N;MODE;/path"
+;
+; where MODE is the octal representation of the mode. Note that this
+; does not overwrite the process's umask.
+; http://php.net/session.save-path
+;session.save_path = "/tmp"
+
+; Whether to use cookies.
+; http://php.net/session.use-cookies
+session.use_cookies = 1
+
+; http://php.net/session.cookie-secure
+;session.cookie_secure =
+
+; This option forces PHP to fetch and use a cookie for storing and maintaining
+; the session id. We encourage this operation as it's very helpful in combating
+; session hijacking when not specifying and managing your own session id. It is
+; not the end all be all of session hijacking defense, but it's a good start.
+; http://php.net/session.use-only-cookies
+session.use_only_cookies = 1
+
+; Name of the session (used as cookie name).
+; http://php.net/session.name
+session.name = PHPSESSID
+
+; Initialize session on request startup.
+; http://php.net/session.auto-start
+session.auto_start = 0
+
+; Lifetime in seconds of cookie or, if 0, until browser is restarted.
+; http://php.net/session.cookie-lifetime
+session.cookie_lifetime = 0
+
+; The path for which the cookie is valid.
+; http://php.net/session.cookie-path
+session.cookie_path = /
+
+; The domain for which the cookie is valid.
+; http://php.net/session.cookie-domain
+session.cookie_domain =
+
+; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript.
+; http://php.net/session.cookie-httponly
+session.cookie_httponly =
+
+; Handler used to serialize data. php is the standard serializer of PHP.
+; http://php.net/session.serialize-handler
+session.serialize_handler = php
+
+; Defines the probability that the 'garbage collection' process is started
+; on every session initialization. The probability is calculated by using
+; gc_probability/gc_divisor. Where session.gc_probability is the numerator
+; and gc_divisor is the denominator in the equation. Setting this value to 1
+; when the session.gc_divisor value is 100 will give you approximately a 1% chance
+; the gc will run on any give request.
+; Default Value: 1
+; Development Value: 1
+; Production Value: 1
+; http://php.net/session.gc-probability
+session.gc_probability = 1
+
+; Defines the probability that the 'garbage collection' process is started on every
+; session initialization. The probability is calculated by using the following equation:
+; gc_probability/gc_divisor. Where session.gc_probability is the numerator and
+; session.gc_divisor is the denominator in the equation. Setting this value to 1
+; when the session.gc_divisor value is 100 will give you approximately a 1% chance
+; the gc will run on any give request. Increasing this value to 1000 will give you
+; a 0.1% chance the gc will run on any give request. For high volume production servers,
+; this is a more efficient approach.
+; Default Value: 100
+; Development Value: 1000
+; Production Value: 1000
+; http://php.net/session.gc-divisor
+session.gc_divisor = 1000
+
+; After this number of seconds, stored data will be seen as 'garbage' and
+; cleaned up by the garbage collection process.
+; http://php.net/session.gc-maxlifetime
+session.gc_maxlifetime = 1440
+
+; NOTE: If you are using the subdirectory option for storing session files
+; (see session.save_path above), then garbage collection does *not*
+; happen automatically. You will need to do your own garbage
+; collection through a shell script, cron entry, or some other method.
+; For example, the following script would is the equivalent of
+; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes):
+; find /path/to/sessions -cmin +24 -type f | xargs rm
+
+; Check HTTP Referer to invalidate externally stored URLs containing ids.
+; HTTP_REFERER has to contain this substring for the session to be
+; considered as valid.
+; http://php.net/session.referer-check
+session.referer_check =
+
+; How many bytes to read from the file.
+; http://php.net/session.entropy-length
+;session.entropy_length = 32
+
+; Specified here to create the session id.
+; http://php.net/session.entropy-file
+; Defaults to /dev/urandom
+; On systems that don't have /dev/urandom but do have /dev/arandom, this will default to /dev/arandom
+; If neither are found at compile time, the default is no entropy file.
+; On windows, setting the entropy_length setting will activate the
+; Windows random source (using the CryptoAPI)
+;session.entropy_file = /dev/urandom
+
+; Set to {nocache,private,public,} to determine HTTP caching aspects
+; or leave this empty to avoid sending anti-caching headers.
+; http://php.net/session.cache-limiter
+session.cache_limiter = nocache
+
+; Document expires after n minutes.
+; http://php.net/session.cache-expire
+session.cache_expire = 180
+
+; trans sid support is disabled by default.
+; Use of trans sid may risk your users security.
+; Use this option with caution.
+; - User may send URL contains active session ID
+; to other person via. email/irc/etc.
+; - URL that contains active session ID may be stored
+; in publicly accessible computer.
+; - User may access your site with the same session ID
+; always using URL stored in browser's history or bookmarks.
+; http://php.net/session.use-trans-sid
+session.use_trans_sid = 0
+
+; Select a hash function for use in generating session ids.
+; Possible Values
+; 0 (MD5 128 bits)
+; 1 (SHA-1 160 bits)
+; This option may also be set to the name of any hash function supported by
+; the hash extension. A list of available hashes is returned by the hash_algos()
+; function.
+; http://php.net/session.hash-function
+session.hash_function = 0
+
+; Define how many bits are stored in each character when converting
+; the binary hash data to something readable.
+; Possible values:
+; 4 (4 bits: 0-9, a-f)
+; 5 (5 bits: 0-9, a-v)
+; 6 (6 bits: 0-9, a-z, A-Z, "-", ",")
+; Default Value: 4
+; Development Value: 5
+; Production Value: 5
+; http://php.net/session.hash-bits-per-character
+session.hash_bits_per_character = 5
+
+; The URL rewriter will look for URLs in a defined set of HTML tags.
+; form/fieldset are special; if you include them here, the rewriter will
+; add a hidden field with the info which is otherwise appended
+; to URLs. If you want XHTML conformity, remove the form entry.
+; Note that all valid entries require a "=", even if no value follows.
+; Default Value: "a=href,area=href,frame=src,form=,fieldset="
+; Development Value: "a=href,area=href,frame=src,input=src,form=fakeentry"
+; Production Value: "a=href,area=href,frame=src,input=src,form=fakeentry"
+; http://php.net/url-rewriter.tags
+url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry"
+
+; Enable upload progress tracking in $_SESSION
+; Default Value: On
+; Development Value: On
+; Production Value: On
+; http://php.net/session.upload-progress.enabled
+;session.upload_progress.enabled = On
+
+; Cleanup the progress information as soon as all POST data has been read
+; (i.e. upload completed).
+; Default Value: On
+; Development Value: On
+; Production Value: On
+; http://php.net/session.upload-progress.cleanup
+;session.upload_progress.cleanup = On
+
+; A prefix used for the upload progress key in $_SESSION
+; Default Value: "upload_progress_"
+; Development Value: "upload_progress_"
+; Production Value: "upload_progress_"
+; http://php.net/session.upload-progress.prefix
+;session.upload_progress.prefix = "upload_progress_"
+
+; The index name (concatenated with the prefix) in $_SESSION
+; containing the upload progress information
+; Default Value: "PHP_SESSION_UPLOAD_PROGRESS"
+; Development Value: "PHP_SESSION_UPLOAD_PROGRESS"
+; Production Value: "PHP_SESSION_UPLOAD_PROGRESS"
+; http://php.net/session.upload-progress.name
+;session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"
+
+; How frequently the upload progress should be updated.
+; Given either in percentages (per-file), or in bytes
+; Default Value: "1%"
+; Development Value: "1%"
+; Production Value: "1%"
+; http://php.net/session.upload-progress.freq
+;session.upload_progress.freq = "1%"
+
+; The minimum delay between updates, in seconds
+; Default Value: 1
+; Development Value: 1
+; Production Value: 1
+; http://php.net/session.upload-progress.min-freq
+;session.upload_progress.min_freq = "1"
+
+[MSSQL]
+; Allow or prevent persistent links.
+mssql.allow_persistent = On
+
+; Maximum number of persistent links. -1 means no limit.
+mssql.max_persistent = -1
+
+; Maximum number of links (persistent+non persistent). -1 means no limit.
+mssql.max_links = -1
+
+; Minimum error severity to display.
+mssql.min_error_severity = 10
+
+; Minimum message severity to display.
+mssql.min_message_severity = 10
+
+; Compatibility mode with old versions of PHP 3.0.
+mssql.compatability_mode = Off
+
+; Connect timeout
+;mssql.connect_timeout = 5
+
+; Query timeout
+;mssql.timeout = 60
+
+; Valid range 0 - 2147483647. Default = 4096.
+;mssql.textlimit = 4096
+
+; Valid range 0 - 2147483647. Default = 4096.
+;mssql.textsize = 4096
+
+; Limits the number of records in each batch. 0 = all records in one batch.
+;mssql.batchsize = 0
+
+; Specify how datetime and datetim4 columns are returned
+; On => Returns data converted to SQL server settings
+; Off => Returns values as YYYY-MM-DD hh:mm:ss
+;mssql.datetimeconvert = On
+
+; Use NT authentication when connecting to the server
+mssql.secure_connection = Off
+
+; Specify max number of processes. -1 = library default
+; msdlib defaults to 25
+; FreeTDS defaults to 4096
+;mssql.max_procs = -1
+
+; Specify client character set.
+; If empty or not set the client charset from freetds.conf is used
+; This is only used when compiled with FreeTDS
+;mssql.charset = "ISO-8859-1"
+
+[Assertion]
+; Assert(expr); active by default.
+; http://php.net/assert.active
+;assert.active = On
+
+; Issue a PHP warning for each failed assertion.
+; http://php.net/assert.warning
+;assert.warning = On
+
+; Don't bail out by default.
+; http://php.net/assert.bail
+;assert.bail = Off
+
+; User-function to be called if an assertion fails.
+; http://php.net/assert.callback
+;assert.callback = 0
+
+; Eval the expression with current error_reporting(). Set to true if you want
+; error_reporting(0) around the eval().
+; http://php.net/assert.quiet-eval
+;assert.quiet_eval = 0
+
+[COM]
+; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs
+; http://php.net/com.typelib-file
+;com.typelib_file =
+
+; allow Distributed-COM calls
+; http://php.net/com.allow-dcom
+;com.allow_dcom = true
+
+; autoregister constants of a components typlib on com_load()
+; http://php.net/com.autoregister-typelib
+;com.autoregister_typelib = true
+
+; register constants casesensitive
+; http://php.net/com.autoregister-casesensitive
+;com.autoregister_casesensitive = false
+
+; show warnings on duplicate constant registrations
+; http://php.net/com.autoregister-verbose
+;com.autoregister_verbose = true
+
+; The default character set code-page to use when passing strings to and from COM objects.
+; Default: system ANSI code page
+;com.code_page=
+
+[mbstring]
+; language for internal character representation.
+; http://php.net/mbstring.language
+;mbstring.language = Japanese
+
+; internal/script encoding.
+; Some encoding cannot work as internal encoding.
+; (e.g. SJIS, BIG5, ISO-2022-*)
+; http://php.net/mbstring.internal-encoding
+;mbstring.internal_encoding = EUC-JP
+
+; http input encoding.
+; http://php.net/mbstring.http-input
+;mbstring.http_input = auto
+
+; http output encoding. mb_output_handler must be
+; registered as output buffer to function
+; http://php.net/mbstring.http-output
+;mbstring.http_output = SJIS
+
+; enable automatic encoding translation according to
+; mbstring.internal_encoding setting. Input chars are
+; converted to internal encoding by setting this to On.
+; Note: Do _not_ use automatic encoding translation for
+; portable libs/applications.
+; http://php.net/mbstring.encoding-translation
+;mbstring.encoding_translation = Off
+
+; automatic encoding detection order.
+; auto means
+; http://php.net/mbstring.detect-order
+;mbstring.detect_order = auto
+
+; substitute_character used when character cannot be converted
+; one from another
+; http://php.net/mbstring.substitute-character
+;mbstring.substitute_character = none;
+
+; overload(replace) single byte functions by mbstring functions.
+; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(),
+; etc. Possible values are 0,1,2,4 or combination of them.
+; For example, 7 for overload everything.
+; 0: No overload
+; 1: Overload mail() function
+; 2: Overload str*() functions
+; 4: Overload ereg*() functions
+; http://php.net/mbstring.func-overload
+;mbstring.func_overload = 0
+
+; enable strict encoding detection.
+;mbstring.strict_detection = Off
+
+; This directive specifies the regex pattern of content types for which mb_output_handler()
+; is activated.
+; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml)
+;mbstring.http_output_conv_mimetype=
+
+[gd]
+; Tell the jpeg decode to ignore warnings and try to create
+; a gd image. The warning will then be displayed as notices
+; disabled by default
+; http://php.net/gd.jpeg-ignore-warning
+;gd.jpeg_ignore_warning = 0
+
+[exif]
+; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS.
+; With mbstring support this will automatically be converted into the encoding
+; given by corresponding encode setting. When empty mbstring.internal_encoding
+; is used. For the decode settings you can distinguish between motorola and
+; intel byte order. A decode setting cannot be empty.
+; http://php.net/exif.encode-unicode
+;exif.encode_unicode = ISO-8859-15
+
+; http://php.net/exif.decode-unicode-motorola
+;exif.decode_unicode_motorola = UCS-2BE
+
+; http://php.net/exif.decode-unicode-intel
+;exif.decode_unicode_intel = UCS-2LE
+
+; http://php.net/exif.encode-jis
+;exif.encode_jis =
+
+; http://php.net/exif.decode-jis-motorola
+;exif.decode_jis_motorola = JIS
+
+; http://php.net/exif.decode-jis-intel
+;exif.decode_jis_intel = JIS
+
+[Tidy]
+; The path to a default tidy configuration file to use when using tidy
+; http://php.net/tidy.default-config
+;tidy.default_config = /usr/local/lib/php/default.tcfg
+
+; Should tidy clean and repair output automatically?
+; WARNING: Do not use this option if you are generating non-html content
+; such as dynamic images
+; http://php.net/tidy.clean-output
+tidy.clean_output = Off
+
+[soap]
+; Enables or disables WSDL caching feature.
+; http://php.net/soap.wsdl-cache-enabled
+soap.wsdl_cache_enabled=1
+
+; Sets the directory name where SOAP extension will put cache files.
+; http://php.net/soap.wsdl-cache-dir
+soap.wsdl_cache_dir="/tmp"
+
+; (time to live) Sets the number of second while cached file will be used
+; instead of original one.
+; http://php.net/soap.wsdl-cache-ttl
+soap.wsdl_cache_ttl=86400
+
+; Sets the size of the cache limit. (Max. number of WSDL files to cache)
+soap.wsdl_cache_limit = 5
+
+[sysvshm]
+; A default size of the shared memory segment
+;sysvshm.init_mem = 10000
+
+[ldap]
+; Sets the maximum number of open links or -1 for unlimited.
+ldap.max_links = -1
+
+[mcrypt]
+; For more information about mcrypt settings see http://php.net/mcrypt-module-open
+
+; Directory where to load mcrypt algorithms
+; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt)
+;mcrypt.algorithms_dir=
+
+; Directory where to load mcrypt modes
+; Default: Compiled in into libmcrypt (usually /usr/local/lib/libmcrypt)
+;mcrypt.modes_dir=
+
+[dba]
+;dba.default_handler=
+
+[curl]
+; A default value for the CURLOPT_CAINFO option. This is required to be an
+; absolute path.
+;curl.cainfo =
+
+; Local Variables:
+; tab-width: 4
+; End:
+
+[ZendGuardLoader]
+zend_loader.enable=1
+zend_extension=/ewomail/ZendGuardLoader/ZendGuardLoader.so
+zend_loader.disable_licensing=0
+zend_loader.obfuscation_level_support=3
diff --git a/install/soft/phpMyAdmin.tar.gz b/install/soft/phpMyAdmin.tar.gz
new file mode 100644
index 0000000..2af1fa3
Binary files /dev/null and b/install/soft/phpMyAdmin.tar.gz differ
diff --git a/install/soft/postfix-policyd-spf-perl b/install/soft/postfix-policyd-spf-perl
new file mode 100644
index 0000000..df248d5
--- /dev/null
+++ b/install/soft/postfix-policyd-spf-perl
@@ -0,0 +1,397 @@
+#!/usr/bin/perl
+
+# postfix-policyd-spf-perl
+# http://www.openspf.org/Software
+# version 2.010
+#
+# (C) 2007-2008,2012 Scott Kitterman
+# (C) 2012 Allison Randal
+# (C) 2007 Julian Mehnle
+# (C) 2003-2004 Meng Weng Wong
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use version; our $VERSION = qv('2.010');
+
+use strict;
+
+use IO::Handle;
+use Sys::Syslog qw(:DEFAULT setlogsock);
+use NetAddr::IP;
+use Mail::SPF;
+use Sys::Hostname::Long 'hostname_long';
+
+# ----------------------------------------------------------
+# configuration
+# ----------------------------------------------------------
+
+my $resolver = Net::DNS::Resolver->new(
+ retrans => 5, # Net::DNS::Resolver default: 5
+ retry => 2, # Net::DNS::Resolver default: 4
+ # Makes for a total timeout for UDP queries of 5s * 2 = 10s.
+);
+
+# query_rr_type_all will query both type TXT and type SPF. This upstream
+# default is changed due to there being essentiall no type SPF deployment.
+my $spf_server = Mail::SPF::Server->new(
+ dns_resolver => $resolver,
+ query_rr_types => Mail::SPF::Server->query_rr_type_txt,
+ default_authority_explanation =>
+ 'Please see http://www.openspf.net/Why?s=%{_scope};id=%{S};ip=%{C};r=%{R}'
+);
+
+# Adding more handlers is easy:
+my @HANDLERS = (
+ {
+ name => 'exempt_localhost',
+ code => \&exempt_localhost
+ },
+ {
+ name => 'exempt_relay',
+ code => \&exempt_relay
+ },
+ {
+ name => 'sender_policy_framework',
+ code => \&sender_policy_framework
+ }
+);
+
+my $VERBOSE = 0;
+
+my $DEFAULT_RESPONSE = 'DUNNO';
+
+#
+# Syslogging options for verbose mode and for fatal errors.
+# NOTE: comment out the $syslog_socktype line if syslogging does not
+# work on your system.
+#
+
+my $syslog_socktype = 'unix'; # inet, unix, stream, console
+my $syslog_facility = 'mail';
+my $syslog_options = 'pid';
+my $syslog_ident = 'postfix/policy-spf';
+
+use constant localhost_addresses => map(
+ NetAddr::IP->new($_),
+ qw( 127.0.0.0/8 ::ffff:127.0.0.0/104 ::1 )
+); # Does Postfix ever say "client_address=::ffff:"?
+
+use constant relay_addresses => map(
+ NetAddr::IP->new($_),
+ qw( )
+); # add addresses to qw ( ) above separated by spaces using CIDR notation.
+
+# Fully qualified hostname, if available, for use in authentication results
+# headers now provided by the localhost and whitelist checks.
+my $host = hostname_long;
+
+my %results_cache; # by message instance
+
+# ----------------------------------------------------------
+# initialization
+# ----------------------------------------------------------
+
+#
+# Log an error and abort.
+#
+sub fatal_exit {
+ syslog(err => "fatal_exit: @_");
+ syslog(warning => "fatal_exit: @_");
+ syslog(info => "fatal_exit: @_");
+ die("fatal: @_");
+}
+
+#
+# Unbuffer standard output.
+#
+STDOUT->autoflush(1);
+
+#
+# This process runs as a daemon, so it can't log to a terminal. Use
+# syslog so that people can actually see our messages.
+#
+setlogsock($syslog_socktype);
+openlog($syslog_ident, $syslog_options, $syslog_facility);
+
+# ----------------------------------------------------------
+# main
+# ----------------------------------------------------------
+
+#
+# Receive a bunch of attributes, evaluate the policy, send the result.
+#
+my %attr;
+while () {
+ chomp;
+
+ if (/=/) {
+ my ($key, $value) =split (/=/, $_, 2);
+ $attr{$key} = $value;
+ next;
+ }
+ elsif (length) {
+ syslog(warning => sprintf("warning: ignoring garbage: %.100s", $_));
+ next;
+ }
+
+ if ($VERBOSE) {
+ for (sort keys %attr) {
+ syslog(debug => "Attribute: %s=%s", $_ || '', $attr{$_} || '');
+ }
+ };
+
+ my $message_instance = $attr{instance};
+ my $cache = defined($message_instance) ? $results_cache{$message_instance} ||= {} : {};
+
+ my $action = $DEFAULT_RESPONSE;
+
+ foreach my $handler (@HANDLERS) {
+ my $handler_name = $handler->{name};
+ my $handler_code = $handler->{code};
+
+ my $response = $handler_code->(attr => \%attr, cache => $cache);
+
+ if ($VERBOSE) {
+ syslog(debug => "handler %s: %s", $handler_name || '', $response || '');
+ };
+
+ # Pick whatever response is not 'DUNNO'
+ if ($response and $response !~ /^DUNNO/i) {
+ if ($VERBOSE) {
+ syslog(info => "handler %s: is decisive.", $handler_name || '');
+ }
+ $action = $response;
+ last;
+ }
+ }
+
+ syslog(info => "Policy action=%s", $action || '');
+
+ STDOUT->print("action=$action\n\n");
+ %attr = ();
+}
+
+# ----------------------------------------------------------
+# handler: localhost exemption
+# ----------------------------------------------------------
+
+sub exempt_localhost {
+ my %options = @_;
+ my $attr = $options{attr};
+ if ($attr->{client_address} ne '') {
+ my $client_address = NetAddr::IP->new($attr->{client_address});
+ return "PREPEND Authentication-Results: $host; none (SPF not checked for localhost)"
+ if grep($_->contains($client_address), localhost_addresses);
+ };
+ return 'DUNNO';
+}
+
+# ----------------------------------------------------------
+# handler: relay exemption
+# ----------------------------------------------------------
+
+sub exempt_relay {
+ my %options = @_;
+ my $attr = $options{attr};
+ if ($attr->{client_address} ne '') {
+ my $client_address = NetAddr::IP->new($attr->{client_address});
+ return "PREPEND Authentication-Results: $host; none (SPF not checked for whitelisted relay)"
+ if grep($_->contains($client_address), relay_addresses);
+ };
+ return 'DUNNO';
+}
+
+# ----------------------------------------------------------
+# handler: SPF
+# ----------------------------------------------------------
+
+sub sender_policy_framework {
+ my %options = @_;
+ my $attr = $options{attr};
+ my $cache = $options{cache};
+
+ # -------------------------------------------------------------------------
+ # Always do HELO check first. If no HELO policy, it's only one lookup.
+ # This avoids the need to do any MAIL FROM processing for null sender.
+ # -------------------------------------------------------------------------
+
+ my $helo_result = $cache->{helo_result};
+
+ if (not defined($helo_result)) {
+ # No HELO result has been cached from earlier checks on this message.
+
+ my $helo_request = eval {
+ Mail::SPF::Request->new(
+ scope => 'helo',
+ identity => $attr->{helo_name},
+ ip_address => $attr->{client_address}
+ );
+ };
+
+ if ($@) {
+ # An unexpected error occurred during request creation,
+ # probably due to invalid input data!
+ my $errmsg = $@;
+ $errmsg = $errmsg->text if UNIVERSAL::isa($@, 'Mail::SPF::Exception');
+ if ($VERBOSE) {
+ syslog(
+ info => "HELO check failed - Mail::SPF->new(%s, %s, %s) failed: %s",
+ $attr->{client_address} || '',
+ $attr->{sender} || '', $attr->{helo_name} || '',
+ $errmsg || ''
+ );
+ };
+ return;
+ }
+
+ $helo_result = $cache->{helo_result} = $spf_server->process($helo_request);
+ }
+
+ my $helo_result_code = $helo_result->code; # 'pass', 'fail', etc.
+ my $helo_local_exp = nullchomp($helo_result->local_explanation);
+ my $helo_authority_exp = nullchomp($helo_result->authority_explanation)
+ if $helo_result->is_code('fail');
+ my $helo_spf_header = $helo_result->received_spf_header;
+
+ if ($VERBOSE) {
+ syslog(
+ info => "SPF %s: HELO/EHLO: %s, IP Address: %s, Recipient: %s",
+ $helo_result || '',
+ $attr->{helo_name} || '', $attr->{client_address} || '',
+ $attr->{recipient} || ''
+ );
+ };
+
+ # Reject on HELO fail. Defer on HELO temperror if message would otherwise
+ # be accepted. Use the HELO result and return for null sender.
+ if ($helo_result->is_code('fail')) {
+ if ($VERBOSE) {
+ syslog(
+ info => "SPF %s: HELO/EHLO: %s",
+ $helo_result || '',
+ $attr->{helo_name} || ''
+ );
+ };
+ return "550 $helo_authority_exp";
+ }
+ elsif ($helo_result->is_code('temperror')) {
+ if ($VERBOSE) {
+ syslog(
+ info => "SPF %s: HELO/EHLO: %s",
+ $helo_result || '',
+ $attr->{helo_name} || ''
+ );
+ };
+ #return "DEFER_IF_PERMIT SPF-Result=$helo_local_exp";
+ return "PREPEND Received-SPF: none";
+ }
+ elsif ($attr->{sender} eq '') {
+ if ($VERBOSE) {
+ syslog(
+ info => "SPF %s: HELO/EHLO (Null Sender): %s",
+ $helo_result || '',
+ $attr->{helo_name} || ''
+ );
+ };
+ return "PREPEND $helo_spf_header"
+ unless $cache->{added_spf_header}++;
+ }
+
+ # -------------------------------------------------------------------------
+ # Do MAIL FROM check (as HELO did not give a definitive result)
+ # -------------------------------------------------------------------------
+
+ my $mfrom_result = $cache->{mfrom_result};
+
+ if (not defined($mfrom_result)) {
+ # No MAIL FROM result has been cached from earlier checks on this message.
+
+ my $mfrom_request = eval {
+ Mail::SPF::Request->new(
+ scope => 'mfrom',
+ identity => $attr->{sender},
+ ip_address => $attr->{client_address},
+ helo_identity => $attr->{helo_name} # for %{h} macro expansion
+ );
+ };
+
+ if ($@) {
+ # An unexpected error occurred during request creation,
+ # probably due to invalid input data!
+ my $errmsg = $@;
+ $errmsg = $errmsg->text if UNIVERSAL::isa($@, 'Mail::SPF::Exception');
+ if ($VERBOSE) {
+ syslog(
+ info => "Mail From (sender) check failed - Mail::SPF->new(%s, %s, %s) failed: %s",
+ $attr->{client_address} || '',
+ $attr->{sender} || '', $attr->{helo_name} || '', $errmsg || ''
+ );
+ };
+ return;
+ }
+
+ $mfrom_result = $cache->{mfrom_result} = $spf_server->process($mfrom_request);
+ }
+
+ my $mfrom_result_code = $mfrom_result->code; # 'pass', 'fail', etc.
+ my $mfrom_local_exp = nullchomp($mfrom_result->local_explanation);
+ my $mfrom_authority_exp = nullchomp($mfrom_result->authority_explanation)
+ if $mfrom_result->is_code('fail');
+ my $mfrom_spf_header = $mfrom_result->received_spf_header;
+
+ if ($VERBOSE) {
+ syslog(
+ info => "SPF %s: Envelope-from: %s, IP Address: %s, Recipient: %s",
+ $mfrom_result || '',
+ $attr->{sender} || '', $attr->{client_address} || '',
+ $attr->{recipient} || ''
+ );
+ };
+
+ # Same approach as HELO....
+ if ($VERBOSE) {
+ syslog(
+ info => "SPF %s: Envelope-from: %s",
+ $mfrom_result || '',
+ $attr->{sender} || ''
+ );
+ };
+ if ($mfrom_result->is_code('fail')) {
+ return "550 $mfrom_authority_exp";
+ }
+ elsif ($mfrom_result->is_code('temperror')) {
+ #return "DEFER_IF_PERMIT SPF-Result=$mfrom_local_exp";
+ return "PREPEND Received-SPF: none";
+ }
+ else {
+ return "PREPEND $mfrom_spf_header"
+ unless $cache->{added_spf_header}++;
+ }
+
+ return;
+}
+
+# ----------------------------------------------------------
+# utility, string cleaning
+# ----------------------------------------------------------
+
+sub nullchomp {
+ my $value = shift;
+
+ # Remove one or more null characters from the
+ # end of the input.
+ $value =~ s/\0+$//;
+ return $value;
+}
diff --git a/install/start.sh b/install/start.sh
new file mode 100644
index 0000000..e36f76d
--- /dev/null
+++ b/install/start.sh
@@ -0,0 +1,238 @@
+# +----------------------------------------------------------------------
+# | EwoMail
+# +----------------------------------------------------------------------
+# | Copyright (c) 2016 http://ewomail.com All rights reserved.
+# +----------------------------------------------------------------------
+# | Licensed ( http://ewomail.com/license.html)
+# +----------------------------------------------------------------------
+# | Author: Jun
+# +----------------------------------------------------------------------
+#!/bin/bash
+cur_dir=`pwd`
+domain=$1
+df=$2
+set -o pipefail
+stty erase ^h
+setenforce 0
+
+centos7=false
+
+if [ -f "/usr/lib/systemd/system/network.target" ]; then
+ centos7=true
+fi
+
+dovecot_install(){
+ if [ $centos7 = true ] ; then
+ rpm -ivh $cur_dir/soft/centos7-dovecot-2.2.24-el6.x86_64.rpm
+ else
+ rpm -ivh $cur_dir/soft/dovecot-2.2.24-el6.x86_64.rpm
+ fi
+
+}
+
+spf_install(){
+ cp -f $cur_dir/soft/postfix-policyd-spf-perl /usr/libexec/postfix/
+ chmod -R 755 /usr/libexec/postfix/postfix-policyd-spf-perl
+}
+
+amavis_install(){
+ if [ $centos7 = true ] ; then
+ yum -y install amavisd-new clamav-server clamav-server-systemd iptables-services
+ cp -rf $cur_dir/config/clamav/clamd.amavisd /etc/sysconfig
+ cp -rf $cur_dir/config/clamav/clamd.amavisd.conf /etc/tmpfiles.d
+ cp -rf $cur_dir/config/clamav/clamd@.service /usr/lib/systemd/system
+ else
+ yum -y install amavisd-new
+ chmod -R 770 /var/spool/amavisd/tmp
+ usermod -G amavis clam
+ ln -s /etc/amavisd/amavisd.conf /etc
+ mv /etc/clamd.conf /etc/clamd.conf.backup
+ cp -rf /etc/clamd.d/amavisd.conf /etc/clamd.conf
+ fi
+
+}
+
+epel_install(){
+ if [ $centos7 = true ] ; then
+ rpm -ivh $cur_dir/soft/epel-release-latest-7.noarch.rpm
+ else
+ cp -f $cur_dir/soft/epel-6.repo /etc/yum.repos.d/epel-6.repo
+ fi
+}
+
+config_file(){
+
+ if [ $centos7 = true ] ; then
+ mv /etc/my.cnf /etc/my.cnf.backup
+ ln -s /ewomail/mysql/etc/my.cnf /etc
+ cp -rf $cur_dir/soft/dovecot.service /usr/lib/systemd/system
+ else
+ cp -rf $cur_dir/soft/dovecot.init /etc/rc.d/init.d/dovecot
+ chmod -R 755 /etc/rc.d/init.d/dovecot
+ fi
+
+ cp -rf $cur_dir/soft/httpd.conf /ewomail/apache/conf
+
+ cp -rf $cur_dir/config/dovecot /etc
+ cp -rf $cur_dir/config/postfix /etc
+
+ mv /etc/sysconfig/iptables /etc/sysconfig/iptables.backup
+ cp -rf $cur_dir/soft/iptables /etc/sysconfig/iptables
+ chmod -R 600 /etc/sysconfig/iptables
+
+ mkdir -p /etc/ssl/certs
+ mkdir -p /etc/ssl/private
+
+ cp -rf $cur_dir/soft/httpd.init /etc/rc.d/init.d/httpd
+ chmod -R 755 /etc/rc.d/init.d/httpd
+
+ cp -rf $cur_dir/soft/nginx.init /etc/rc.d/init.d/nginx
+ chmod -R 755 /etc/rc.d/init.d/nginx
+
+ cp -rf $cur_dir/soft/php.ini /ewomail/php54/etc
+ cp -rf $cur_dir/soft/php-cli.ini /ewomail/php54/etc
+
+ cp -rf $cur_dir/soft/php-fpm.init /etc/rc.d/init.d/php-fpm
+ chmod -R 755 /etc/rc.d/init.d/php-fpm
+
+ cp -rf $cur_dir/config/fail2ban/jail.local /etc/fail2ban
+ cp -rf $cur_dir/config/fail2ban/postfix.ewomail.conf /etc/fail2ban/filter.d
+
+ cd /usr/local/dovecot/share/doc/dovecot
+ sh mkcert.sh
+}
+
+check_install(){
+ if ! rpm -qa | grep ewomail > /dev/null;then
+ echo "ewomail Installation failed"
+ exit 1
+ fi
+
+ if ! rpm -qa | grep postfix > /dev/null;then
+ echo "postfix Installation failed"
+ exit 1
+ fi
+
+ if ! rpm -qa | grep dovecot > /dev/null;then
+ echo "dovecot Installation failed"
+ exit 1
+ fi
+
+ if ! rpm -qa | grep amavisd-new > /dev/null;then
+ echo "amavisd Installation failed"
+ exit 1
+ fi
+
+ if ! rpm -qa | grep clamav > /dev/null;then
+ echo "clamav Installation failed"
+ exit 1
+ fi
+
+ if ! rpm -qa | grep spamassassin > /dev/null;then
+ echo "spamassassin Installation failed"
+ exit 1
+ fi
+
+}
+
+
+init(){
+ if [ -z $domain ];then
+ echo "Missing domain parameter"
+ exit 1
+ fi
+
+ yum remove sendmail
+ epel_install
+ yum -y install postfix perl-DBI perl-JSON-XS perl-NetAddr-IP perl-Mail-SPF perl-Sys-Hostname-Long freetype* libpng* libjpeg* iptables fail2ban
+
+ if [ $df = "-f" ] ; then
+ rpm -ivh $cur_dir/soft/ewomail-lamp-1.0-el6.x86_64.rpm --force --nodeps
+ else
+ rpm -ivh $cur_dir/soft/ewomail-lamp-1.0-el6.x86_64.rpm
+ fi
+
+
+ if [ $? != 0 ] ; then echo "ewomail-lamp install failed" >&2 ; exit 1 ; fi
+
+ mkdir -p /ewomail/www/default
+ cp -rf $cur_dir/../ewomail-admin /ewomail/www/
+ cp -rf $cur_dir/../rainloop /ewomail/www/
+
+ cd /ewomail/www
+ tar zxvf $cur_dir/soft/phpMyAdmin.tar.gz
+
+ cd $cur_dir
+
+ dovecot_install
+ amavis_install
+ spf_install
+ config_file
+ check_install
+
+ groupadd -g 5000 vmail
+ useradd -M -u 5000 -g vmail -s /sbin/nologin vmail
+
+ cp -rf $cur_dir/config/mail /ewomail
+
+ chown -R vmail:vmail /ewomail/mail
+ chmod -R 700 /ewomail/mail
+
+ chown -R www:www /ewomail/www
+ chmod -R 770 /ewomail/www
+
+ mkdir -p /ewomail/dkim
+ chown -R amavis:amavis /ewomail/dkim
+ amavisd genrsa /ewomail/dkim/mail.pem
+ chown -R amavis:amavis /ewomail/dkim
+
+ service mysqld start
+
+ cd $cur_dir
+ chmod -R 700 ./init.php
+ ./init.php $domain > init_php.log
+
+ chmod -R 440 /ewomail/config.ini
+
+ rm -rf /ewomail/www/tz.php
+
+
+ if [ $centos7 = true ] ; then
+ chkconfig mysqld on
+ chkconfig httpd on
+ systemctl enable postfix dovecot amavisd spamassassin fail2ban clamd@amavisd iptables
+
+
+ service httpd start
+ systemctl restart amavisd spamassassin clamd@amavisd
+ systemctl restart postfix dovecot fail2ban
+
+ systemctl mask firewalld.service
+ systemctl stop firewalld.service
+ systemctl restart iptables
+
+ else
+ chkconfig mysqld on
+ chkconfig clamd on
+ chkconfig spamassassin on
+ chkconfig amavisd on
+ chkconfig postfix on
+ chkconfig dovecot on
+ chkconfig httpd on
+ chkconfig fail2ban on
+
+ service iptables restart
+ service clamd start
+ service spamassassin start
+ service amavisd start
+ service dovecot start
+ service httpd start
+ service postfix restart
+ service fail2ban start
+ fi
+
+
+ echo "Complete installation"
+}
+
+init
diff --git a/rainloop/data/.htaccess b/rainloop/data/.htaccess
new file mode 100644
index 0000000..c59c358
--- /dev/null
+++ b/rainloop/data/.htaccess
@@ -0,0 +1,4 @@
+Deny from all
+
+Options -Indexes
+
\ No newline at end of file
diff --git a/rainloop/data/EMPTY b/rainloop/data/EMPTY
new file mode 100644
index 0000000..0c8ed4c
--- /dev/null
+++ b/rainloop/data/EMPTY
@@ -0,0 +1 @@
+1.10.0.103
\ No newline at end of file
diff --git a/rainloop/data/INSTALLED b/rainloop/data/INSTALLED
new file mode 100644
index 0000000..0c8ed4c
--- /dev/null
+++ b/rainloop/data/INSTALLED
@@ -0,0 +1 @@
+1.10.0.103
\ No newline at end of file
diff --git a/rainloop/data/SALT.php b/rainloop/data/SALT.php
new file mode 100644
index 0000000..8748470
--- /dev/null
+++ b/rainloop/data/SALT.php
@@ -0,0 +1 @@
+sAllowedEmails = $sAllowedEmails;
+ return $this;
+ }
+
+ /**
+ * @param \MailSo\Log\Logger $oLogger
+ *
+ * @return \IspConfigChangePasswordDriver
+ */
+ public function SetLogger($oLogger)
+ {
+ if ($oLogger instanceof \MailSo\Log\Logger)
+ {
+ $this->oLogger = $oLogger;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param \RainLoop\Account $oAccount
+ *
+ * @return bool
+ */
+ public function PasswordChangePossibility($oAccount)
+ {
+ return $oAccount && $oAccount->Email() &&
+ \RainLoop\Plugins\Helper::ValidateWildcardValues($oAccount->Email(), $this->sAllowedEmails);
+ }
+
+ /**
+ * @param \RainLoop\Account $oAccount
+ * @param string $sPrevPassword
+ * @param string $sNewPassword
+ *
+ * @return bool
+ */
+ public function ChangePassword(\RainLoop\Account $oAccount, $sPrevPassword, $sNewPassword)
+ {
+ $ewomail = new \RainLoop\EwoMail();
+ $data = $ewomail->updatePassword($oAccount->Email(),$sPrevPassword,$sNewPassword);
+ if($data['status']){
+ return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/rainloop/data/_data_/_default_/plugins/ewomail-password/index.php b/rainloop/data/_data_/_default_/plugins/ewomail-password/index.php
new file mode 100644
index 0000000..367fc50
--- /dev/null
+++ b/rainloop/data/_data_/_default_/plugins/ewomail-password/index.php
@@ -0,0 +1,47 @@
+addHook('main.fabrica', 'MainFabrica');
+ }
+
+ /**
+ * @return string
+ */
+ public function Supported()
+ {
+
+ return '';
+ }
+
+ /**
+ * @param string $sName
+ * @param mixed $oProvider
+ */
+ public function MainFabrica($sName, &$oProvider)
+ {
+ switch ($sName)
+ {
+ case 'change-password':
+
+ include_once __DIR__.'/EwoMailPasswordDriver.php';
+
+ $oProvider = new EwoMailPasswordDriver();
+ $oProvider->SetLogger($this->Manager()->Actions()->Logger());
+ //$oProvider->SetConfig($sDsn, $sUser, $sPassword);
+ $oProvider->SetAllowedEmails(\strtolower(\trim($this->Config()->Get('plugin', 'allowed_emails', ''))));
+
+ break;
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function configMapping()
+ {
+ return [];
+ }
+}
\ No newline at end of file
diff --git a/rainloop/data/_data_/_default_/storage/cfg/index.html b/rainloop/data/_data_/_default_/storage/cfg/index.html
new file mode 100644
index 0000000..e69de29
diff --git a/rainloop/data/_data_/_default_/storage/data/__nobody__/index.html b/rainloop/data/_data_/_default_/storage/data/__nobody__/index.html
new file mode 100644
index 0000000..e69de29
diff --git a/rainloop/data/index.html b/rainloop/data/index.html
new file mode 100644
index 0000000..c466910
--- /dev/null
+++ b/rainloop/data/index.html
@@ -0,0 +1 @@
+Forbidden
\ No newline at end of file
diff --git a/rainloop/data/index.php b/rainloop/data/index.php
new file mode 100644
index 0000000..c466910
--- /dev/null
+++ b/rainloop/data/index.php
@@ -0,0 +1 @@
+Forbidden
\ No newline at end of file
diff --git a/rainloop/index.php b/rainloop/index.php
new file mode 100644
index 0000000..5f77db1
--- /dev/null
+++ b/rainloop/index.php
@@ -0,0 +1,18 @@
+accessToken = $accessToken;
+ if ($expiresAt) {
+ $this->setExpiresAtFromTimeStamp($expiresAt);
+ }
+ $this->machineId = $machineId;
+ }
+
+ /**
+ * Setter for expires_at.
+ *
+ * @param int $timeStamp
+ */
+ protected function setExpiresAtFromTimeStamp($timeStamp)
+ {
+ $dt = new \DateTime();
+ $dt->setTimestamp($timeStamp);
+ $this->expiresAt = $dt;
+ }
+
+ /**
+ * Getter for expiresAt.
+ *
+ * @return \DateTime|null
+ */
+ public function getExpiresAt()
+ {
+ return $this->expiresAt;
+ }
+
+ /**
+ * Getter for machineId.
+ *
+ * @return string|null
+ */
+ public function getMachineId()
+ {
+ return $this->machineId;
+ }
+
+ /**
+ * Determines whether or not this is a long-lived token.
+ *
+ * @return bool
+ */
+ public function isLongLived()
+ {
+ if ($this->expiresAt) {
+ return $this->expiresAt->getTimestamp() > time() + (60 * 60 * 2);
+ }
+ return false;
+ }
+
+ /**
+ * Checks the validity of the access token.
+ *
+ * @param string|null $appId Application ID to use
+ * @param string|null $appSecret App secret value to use
+ * @param string|null $machineId
+ *
+ * @return boolean
+ */
+ public function isValid($appId = null, $appSecret = null, $machineId = null)
+ {
+ $accessTokenInfo = $this->getInfo($appId, $appSecret);
+ $machineId = $machineId ?: $this->machineId;
+ return static::validateAccessToken($accessTokenInfo, $appId, $machineId);
+ }
+
+ /**
+ * Ensures the provided GraphSessionInfo object is valid,
+ * throwing an exception if not. Ensures the appId matches,
+ * that the machineId matches if it's being used,
+ * that the token is valid and has not expired.
+ *
+ * @param GraphSessionInfo $tokenInfo
+ * @param string|null $appId Application ID to use
+ * @param string|null $machineId
+ *
+ * @return boolean
+ */
+ public static function validateAccessToken(GraphSessionInfo $tokenInfo,
+ $appId = null, $machineId = null)
+ {
+ $targetAppId = FacebookSession::_getTargetAppId($appId);
+
+ $appIdIsValid = $tokenInfo->getAppId() == $targetAppId;
+ $machineIdIsValid = $tokenInfo->getProperty('machine_id') == $machineId;
+ $accessTokenIsValid = $tokenInfo->isValid();
+
+ // Not all access tokens return an expiration. E.g. an app access token.
+ if ($tokenInfo->getExpiresAt() instanceof \DateTime) {
+ $accessTokenIsStillAlive = $tokenInfo->getExpiresAt()->getTimestamp() >= time();
+ } else {
+ $accessTokenIsStillAlive = true;
+ }
+
+ return $appIdIsValid && $machineIdIsValid && $accessTokenIsValid && $accessTokenIsStillAlive;
+ }
+
+ /**
+ * Get a valid access token from a code.
+ *
+ * @param string $code
+ * @param string|null $appId
+ * @param string|null $appSecret
+ * @param string|null $machineId
+ *
+ * @return AccessToken
+ */
+ public static function getAccessTokenFromCode($code, $appId = null, $appSecret = null, $machineId = null)
+ {
+ $params = array(
+ 'code' => $code,
+ 'redirect_uri' => '',
+ );
+
+ if ($machineId) {
+ $params['machine_id'] = $machineId;
+ }
+
+ return static::requestAccessToken($params, $appId, $appSecret);
+ }
+
+ /**
+ * Get a valid code from an access token.
+ *
+ * @param AccessToken|string $accessToken
+ * @param string|null $appId
+ * @param string|null $appSecret
+ *
+ * @return AccessToken
+ */
+ public static function getCodeFromAccessToken($accessToken, $appId = null, $appSecret = null)
+ {
+ $accessToken = (string) $accessToken;
+
+ $params = array(
+ 'access_token' => $accessToken,
+ 'redirect_uri' => '',
+ );
+
+ return static::requestCode($params, $appId, $appSecret);
+ }
+
+ /**
+ * Exchanges a short lived access token with a long lived access token.
+ *
+ * @param string|null $appId
+ * @param string|null $appSecret
+ *
+ * @return AccessToken
+ */
+ public function extend($appId = null, $appSecret = null)
+ {
+ $params = array(
+ 'grant_type' => 'fb_exchange_token',
+ 'fb_exchange_token' => $this->accessToken,
+ );
+
+ return static::requestAccessToken($params, $appId, $appSecret);
+ }
+
+ /**
+ * Request an access token based on a set of params.
+ *
+ * @param array $params
+ * @param string|null $appId
+ * @param string|null $appSecret
+ *
+ * @return AccessToken
+ *
+ * @throws FacebookRequestException
+ */
+ public static function requestAccessToken(array $params, $appId = null, $appSecret = null)
+ {
+ $response = static::request('/oauth/access_token', $params, $appId, $appSecret);
+ $data = $response->getResponse();
+
+ /**
+ * @TODO fix this malarkey - getResponse() should always return an object
+ * @see https://github.com/facebook/facebook-php-sdk-v4/issues/36
+ */
+ if (is_array($data)) {
+ if (isset($data['access_token'])) {
+ $expiresAt = isset($data['expires']) ? time() + $data['expires'] : 0;
+ return new static($data['access_token'], $expiresAt);
+ }
+ } elseif($data instanceof \stdClass) {
+ if (isset($data->access_token)) {
+ $expiresAt = isset($data->expires_in) ? time() + $data->expires_in : 0;
+ $machineId = isset($data->machine_id) ? (string) $data->machine_id : null;
+ return new static((string) $data->access_token, $expiresAt, $machineId);
+ }
+ }
+
+ throw FacebookRequestException::create(
+ $response->getRawResponse(),
+ $data,
+ 401
+ );
+ }
+
+ /**
+ * Request a code from a long lived access token.
+ *
+ * @param array $params
+ * @param string|null $appId
+ * @param string|null $appSecret
+ *
+ * @return string
+ *
+ * @throws FacebookRequestException
+ */
+ public static function requestCode(array $params, $appId = null, $appSecret = null)
+ {
+ $response = static::request('/oauth/client_code', $params, $appId, $appSecret);
+ $data = $response->getResponse();
+
+ if (isset($data->code)) {
+ return (string) $data->code;
+ }
+
+ throw FacebookRequestException::create(
+ $response->getRawResponse(),
+ $data,
+ 401
+ );
+ }
+
+ /**
+ * Send a request to Graph with an app access token.
+ *
+ * @param string $endpoint
+ * @param array $params
+ * @param string|null $appId
+ * @param string|null $appSecret
+ *
+ * @return \Facebook\FacebookResponse
+ *
+ * @throws FacebookRequestException
+ */
+ protected static function request($endpoint, array $params, $appId = null, $appSecret = null)
+ {
+ $targetAppId = FacebookSession::_getTargetAppId($appId);
+ $targetAppSecret = FacebookSession::_getTargetAppSecret($appSecret);
+
+ if (!isset($params['client_id'])) {
+ $params['client_id'] = $targetAppId;
+ }
+ if (!isset($params['client_secret'])) {
+ $params['client_secret'] = $targetAppSecret;
+ }
+
+ // The response for this endpoint is not JSON, so it must be handled
+ // differently, not as a GraphObject.
+ $request = new FacebookRequest(
+ FacebookSession::newAppSession($targetAppId, $targetAppSecret),
+ 'GET',
+ $endpoint,
+ $params
+ );
+ return $request->execute();
+ }
+
+ /**
+ * Get more info about an access token.
+ *
+ * @param string|null $appId
+ * @param string|null $appSecret
+ *
+ * @return GraphSessionInfo
+ */
+ public function getInfo($appId = null, $appSecret = null)
+ {
+ $params = array('input_token' => $this->accessToken);
+
+ $request = new FacebookRequest(
+ FacebookSession::newAppSession($appId, $appSecret),
+ 'GET',
+ '/debug_token',
+ $params
+ );
+ $response = $request->execute()->getGraphObject(GraphSessionInfo::className());
+
+ // Update the data on this token
+ if ($response->getExpiresAt()) {
+ $this->expiresAt = $response->getExpiresAt();
+ }
+
+ return $response;
+ }
+
+ /**
+ * Returns the access token as a string.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->accessToken;
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/Entities/SignedRequest.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/Entities/SignedRequest.php
new file mode 100644
index 0000000..09134c5
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/Entities/SignedRequest.php
@@ -0,0 +1,386 @@
+rawSignedRequest = $rawSignedRequest;
+ $this->payload = static::parse($rawSignedRequest, $state, $appSecret);
+ }
+
+ /**
+ * Returns the raw signed request data.
+ *
+ * @return string|null
+ */
+ public function getRawSignedRequest()
+ {
+ return $this->rawSignedRequest;
+ }
+
+ /**
+ * Returns the parsed signed request data.
+ *
+ * @return array|null
+ */
+ public function getPayload()
+ {
+ return $this->payload;
+ }
+
+ /**
+ * Returns a property from the signed request data if available.
+ *
+ * @param string $key
+ * @param mixed|null $default
+ *
+ * @return mixed|null
+ */
+ public function get($key, $default = null)
+ {
+ if (isset($this->payload[$key])) {
+ return $this->payload[$key];
+ }
+ return $default;
+ }
+
+ /**
+ * Returns user_id from signed request data if available.
+ *
+ * @return string|null
+ */
+ public function getUserId()
+ {
+ return $this->get('user_id');
+ }
+
+ /**
+ * Checks for OAuth data in the payload.
+ *
+ * @return boolean
+ */
+ public function hasOAuthData()
+ {
+ return isset($this->payload['oauth_token']) || isset($this->payload['code']);
+ }
+
+ /**
+ * Creates a signed request from an array of data.
+ *
+ * @param array $payload
+ * @param string|null $appSecret
+ *
+ * @return string
+ */
+ public static function make(array $payload, $appSecret = null)
+ {
+ $payload['algorithm'] = 'HMAC-SHA256';
+ $payload['issued_at'] = time();
+ $encodedPayload = static::base64UrlEncode(json_encode($payload));
+
+ $hashedSig = static::hashSignature($encodedPayload, $appSecret);
+ $encodedSig = static::base64UrlEncode($hashedSig);
+
+ return $encodedSig.'.'.$encodedPayload;
+ }
+
+ /**
+ * Validates and decodes a signed request and returns
+ * the payload as an array.
+ *
+ * @param string $signedRequest
+ * @param string|null $state
+ * @param string|null $appSecret
+ *
+ * @return array
+ */
+ public static function parse($signedRequest, $state = null, $appSecret = null)
+ {
+ list($encodedSig, $encodedPayload) = static::split($signedRequest);
+
+ // Signature validation
+ $sig = static::decodeSignature($encodedSig);
+ $hashedSig = static::hashSignature($encodedPayload, $appSecret);
+ static::validateSignature($hashedSig, $sig);
+
+ // Payload validation
+ $data = static::decodePayload($encodedPayload);
+ static::validateAlgorithm($data);
+ if ($state) {
+ static::validateCsrf($data, $state);
+ }
+
+ return $data;
+ }
+
+ /**
+ * Validates the format of a signed request.
+ *
+ * @param string $signedRequest
+ *
+ * @throws FacebookSDKException
+ */
+ public static function validateFormat($signedRequest)
+ {
+ if (strpos($signedRequest, '.') !== false) {
+ return;
+ }
+
+ throw new FacebookSDKException(
+ 'Malformed signed request.', 606
+ );
+ }
+
+ /**
+ * Decodes a raw valid signed request.
+ *
+ * @param string $signedRequest
+ *
+ * @returns array
+ */
+ public static function split($signedRequest)
+ {
+ static::validateFormat($signedRequest);
+
+ return explode('.', $signedRequest, 2);
+ }
+
+ /**
+ * Decodes the raw signature from a signed request.
+ *
+ * @param string $encodedSig
+ *
+ * @returns string
+ *
+ * @throws FacebookSDKException
+ */
+ public static function decodeSignature($encodedSig)
+ {
+ $sig = static::base64UrlDecode($encodedSig);
+
+ if ($sig) {
+ return $sig;
+ }
+
+ throw new FacebookSDKException(
+ 'Signed request has malformed encoded signature data.', 607
+ );
+ }
+
+ /**
+ * Decodes the raw payload from a signed request.
+ *
+ * @param string $encodedPayload
+ *
+ * @returns array
+ *
+ * @throws FacebookSDKException
+ */
+ public static function decodePayload($encodedPayload)
+ {
+ $payload = static::base64UrlDecode($encodedPayload);
+
+ if ($payload) {
+ $payload = json_decode($payload, true);
+ }
+
+ if (is_array($payload)) {
+ return $payload;
+ }
+
+ throw new FacebookSDKException(
+ 'Signed request has malformed encoded payload data.', 607
+ );
+ }
+
+ /**
+ * Validates the algorithm used in a signed request.
+ *
+ * @param array $data
+ *
+ * @throws FacebookSDKException
+ */
+ public static function validateAlgorithm(array $data)
+ {
+ if (isset($data['algorithm']) && $data['algorithm'] === 'HMAC-SHA256') {
+ return;
+ }
+
+ throw new FacebookSDKException(
+ 'Signed request is using the wrong algorithm.', 605
+ );
+ }
+
+ /**
+ * Hashes the signature used in a signed request.
+ *
+ * @param string $encodedData
+ * @param string|null $appSecret
+ *
+ * @return string
+ *
+ * @throws FacebookSDKException
+ */
+ public static function hashSignature($encodedData, $appSecret = null)
+ {
+ $hashedSig = hash_hmac(
+ 'sha256', $encodedData, FacebookSession::_getTargetAppSecret($appSecret), $raw_output = true
+ );
+
+ if ($hashedSig) {
+ return $hashedSig;
+ }
+
+ throw new FacebookSDKException(
+ 'Unable to hash signature from encoded payload data.', 602
+ );
+ }
+
+ /**
+ * Validates the signature used in a signed request.
+ *
+ * @param string $hashedSig
+ * @param string $sig
+ *
+ * @throws FacebookSDKException
+ */
+ public static function validateSignature($hashedSig, $sig)
+ {
+ if (mb_strlen($hashedSig) === mb_strlen($sig)) {
+ $validate = 0;
+ for ($i = 0; $i < mb_strlen($sig); $i++) {
+ $validate |= ord($hashedSig[$i]) ^ ord($sig[$i]);
+ }
+ if ($validate === 0) {
+ return;
+ }
+ }
+
+ throw new FacebookSDKException(
+ 'Signed request has an invalid signature.', 602
+ );
+ }
+
+ /**
+ * Validates a signed request against CSRF.
+ *
+ * @param array $data
+ * @param string $state
+ *
+ * @throws FacebookSDKException
+ */
+ public static function validateCsrf(array $data, $state)
+ {
+ if (isset($data['state']) && $data['state'] === $state) {
+ return;
+ }
+
+ throw new FacebookSDKException(
+ 'Signed request did not pass CSRF validation.', 604
+ );
+ }
+
+ /**
+ * Base64 decoding which replaces characters:
+ * + instead of -
+ * / instead of _
+ * @link http://en.wikipedia.org/wiki/Base64#URL_applications
+ *
+ * @param string $input base64 url encoded input
+ *
+ * @return string decoded string
+ */
+ public static function base64UrlDecode($input)
+ {
+ $urlDecodedBase64 = strtr($input, '-_', '+/');
+ static::validateBase64($urlDecodedBase64);
+ return base64_decode($urlDecodedBase64);
+ }
+
+ /**
+ * Base64 encoding which replaces characters:
+ * + instead of -
+ * / instead of _
+ * @link http://en.wikipedia.org/wiki/Base64#URL_applications
+ *
+ * @param string $input string to encode
+ *
+ * @return string base64 url encoded input
+ */
+ public static function base64UrlEncode($input)
+ {
+ return strtr(base64_encode($input), '+/', '-_');
+ }
+
+ /**
+ * Validates a base64 string.
+ *
+ * @param string $input base64 value to validate
+ *
+ * @throws FacebookSDKException
+ */
+ public static function validateBase64($input)
+ {
+ $pattern = '/^[a-zA-Z0-9\/\r\n+]*={0,2}$/';
+ if (preg_match($pattern, $input)) {
+ return;
+ }
+
+ throw new FacebookSDKException(
+ 'Signed request contains malformed base64 encoding.', 608
+ );
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookAuthorizationException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookAuthorizationException.php
new file mode 100644
index 0000000..8a3a15c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookAuthorizationException.php
@@ -0,0 +1,33 @@
+
+ * @author David Poll
+ */
+class FacebookCanvasLoginHelper extends FacebookSignedRequestFromInputHelper
+{
+
+ /**
+ * Returns the app data value.
+ *
+ * @return mixed|null
+ */
+ public function getAppData()
+ {
+ return $this->signedRequest ? $this->signedRequest->get('app_data') : null;
+ }
+
+ /**
+ * Get raw signed request from either GET or POST.
+ *
+ * @return string|null
+ */
+ public function getRawSignedRequest()
+ {
+ /**
+ * v2.0 apps use GET for Canvas signed requests.
+ */
+ $rawSignedRequest = $this->getRawSignedRequestFromGet();
+ if ($rawSignedRequest) {
+ return $rawSignedRequest;
+ }
+
+ /**
+ * v1.0 apps use POST for Canvas signed requests, will eventually be
+ * deprecated.
+ */
+ $rawSignedRequest = $this->getRawSignedRequestFromPost();
+ if ($rawSignedRequest) {
+ return $rawSignedRequest;
+ }
+
+ return null;
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookClientException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookClientException.php
new file mode 100644
index 0000000..0eaadae
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookClientException.php
@@ -0,0 +1,33 @@
+
+ * @author David Poll
+ */
+class FacebookJavaScriptLoginHelper extends FacebookSignedRequestFromInputHelper
+{
+
+ /**
+ * Get raw signed request from the cookie.
+ *
+ * @return string|null
+ */
+ public function getRawSignedRequest()
+ {
+ return $this->getRawSignedRequestFromCookie();
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookOtherException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookOtherException.php
new file mode 100644
index 0000000..7d6fdf4
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookOtherException.php
@@ -0,0 +1,33 @@
+
+ */
+class FacebookPageTabHelper extends FacebookCanvasLoginHelper
+{
+
+ /**
+ * @var array|null
+ */
+ protected $pageData;
+
+ /**
+ * Initialize the helper and process available signed request data.
+ *
+ * @param string|null $appId
+ * @param string|null $appSecret
+ */
+ public function __construct($appId = null, $appSecret = null)
+ {
+ parent::__construct($appId, $appSecret);
+
+ if (!$this->signedRequest) {
+ return;
+ }
+
+ $this->pageData = $this->signedRequest->get('page');
+ }
+
+ /**
+ * Returns a value from the page data.
+ *
+ * @param string $key
+ * @param mixed|null $default
+ *
+ * @return mixed|null
+ */
+ public function getPageData($key, $default = null)
+ {
+ if (isset($this->pageData[$key])) {
+ return $this->pageData[$key];
+ }
+ return $default;
+ }
+
+ /**
+ * Returns true if the page is liked by the user.
+ *
+ * @return boolean
+ */
+ public function isLiked()
+ {
+ return $this->getPageData('liked') === true;
+ }
+
+ /**
+ * Returns true if the user is an admin.
+ *
+ * @return boolean
+ */
+ public function isAdmin()
+ {
+ return $this->getPageData('admin') === true;
+ }
+
+ /**
+ * Returns the page id if available.
+ *
+ * @return string|null
+ */
+ public function getPageId()
+ {
+ return $this->getPageData('id');
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookPermissionException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookPermissionException.php
new file mode 100644
index 0000000..7fe970c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookPermissionException.php
@@ -0,0 +1,33 @@
+
+ * @author David Poll
+ */
+class FacebookRedirectLoginHelper
+{
+
+ /**
+ * @var string The application id
+ */
+ private $appId;
+
+ /**
+ * @var string The application secret
+ */
+ private $appSecret;
+
+ /**
+ * @var string The redirect URL for the application
+ */
+ private $redirectUrl;
+
+ /**
+ * @var string Prefix to use for session variables
+ */
+ private $sessionPrefix = 'FBRLH_';
+
+ /**
+ * @var string State token for CSRF validation
+ */
+ protected $state;
+
+ /**
+ * @var boolean Toggle for PHP session status check
+ */
+ protected $checkForSessionStatus = true;
+
+ /**
+ * Constructs a RedirectLoginHelper for a given appId and redirectUrl.
+ *
+ * @param string $redirectUrl The URL Facebook should redirect users to
+ * after login
+ * @param string $appId The application id
+ * @param string $appSecret The application secret
+ */
+ public function __construct($redirectUrl, $appId = null, $appSecret = null)
+ {
+ $this->appId = FacebookSession::_getTargetAppId($appId);
+ $this->appSecret = FacebookSession::_getTargetAppSecret($appSecret);
+ $this->redirectUrl = $redirectUrl;
+ }
+
+ /**
+ * Stores CSRF state and returns a URL to which the user should be sent to
+ * in order to continue the login process with Facebook. The
+ * provided redirectUrl should invoke the handleRedirect method.
+ *
+ * @param array $scope List of permissions to request during login
+ * @param string $version Optional Graph API version if not default (v2.0)
+ *
+ * @return string
+ */
+ public function getLoginUrl($scope = array(), $version = null)
+ {
+ $version = ($version ?: FacebookRequest::GRAPH_API_VERSION);
+ $this->state = $this->random(16);
+ $this->storeState($this->state);
+ $params = array(
+ 'client_id' => $this->appId,
+ 'redirect_uri' => $this->redirectUrl,
+ 'state' => $this->state,
+ 'sdk' => 'php-sdk-' . FacebookRequest::VERSION,
+ 'scope' => implode(',', $scope)
+ );
+ return 'https://www.facebook.com/' . $version . '/dialog/oauth?' .
+ http_build_query($params, null, '&');
+ }
+
+ /**
+ * Returns the URL to send the user in order to log out of Facebook.
+ *
+ * @param FacebookSession $session The session that will be logged out
+ * @param string $next The url Facebook should redirect the user to after
+ * a successful logout
+ *
+ * @return string
+ */
+ public function getLogoutUrl(FacebookSession $session, $next)
+ {
+ $params = array(
+ 'next' => $next,
+ 'access_token' => $session->getToken()
+ );
+ return 'https://www.facebook.com/logout.php?' . http_build_query($params, null, '&');
+ }
+
+ /**
+ * Handles a response from Facebook, including a CSRF check, and returns a
+ * FacebookSession.
+ *
+ * @return FacebookSession|null
+ */
+ public function getSessionFromRedirect()
+ {
+ $this->loadState();
+ if ($this->isValidRedirect()) {
+ $params = array(
+ 'client_id' => FacebookSession::_getTargetAppId($this->appId),
+ 'redirect_uri' => $this->redirectUrl,
+ 'client_secret' =>
+ FacebookSession::_getTargetAppSecret($this->appSecret),
+ 'code' => $this->getCode()
+ );
+ $response = (new FacebookRequest(
+ FacebookSession::newAppSession($this->appId, $this->appSecret),
+ 'GET',
+ '/oauth/access_token',
+ $params
+ ))->execute()->getResponse();
+ if (isset($response['access_token'])) {
+ return new FacebookSession($response['access_token']);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Check if a redirect has a valid state.
+ *
+ * @return bool
+ */
+ protected function isValidRedirect()
+ {
+ return $this->getCode() && isset($_GET['state'])
+ && $_GET['state'] == $this->state;
+ }
+
+ /**
+ * Return the code.
+ *
+ * @return string|null
+ */
+ protected function getCode()
+ {
+ return isset($_GET['code']) ? $_GET['code'] : null;
+ }
+
+ /**
+ * Stores a state string in session storage for CSRF protection.
+ * Developers should subclass and override this method if they want to store
+ * this state in a different location.
+ *
+ * @param string $state
+ *
+ * @throws FacebookSDKException
+ */
+ protected function storeState($state)
+ {
+ if ($this->checkForSessionStatus === true
+ && session_status() !== PHP_SESSION_ACTIVE) {
+ throw new FacebookSDKException(
+ 'Session not active, could not store state.', 720
+ );
+ }
+ $_SESSION[$this->sessionPrefix . 'state'] = $state;
+ }
+
+ /**
+ * Loads a state string from session storage for CSRF validation. May return
+ * null if no object exists. Developers should subclass and override this
+ * method if they want to load the state from a different location.
+ *
+ * @return string|null
+ *
+ * @throws FacebookSDKException
+ */
+ protected function loadState()
+ {
+ if ($this->checkForSessionStatus === true
+ && session_status() !== PHP_SESSION_ACTIVE) {
+ throw new FacebookSDKException(
+ 'Session not active, could not load state.', 721
+ );
+ }
+ if (isset($_SESSION[$this->sessionPrefix . 'state'])) {
+ $this->state = $_SESSION[$this->sessionPrefix . 'state'];
+ return $this->state;
+ }
+ return null;
+ }
+
+ /**
+ * Generate a cryptographically secure pseudrandom number
+ *
+ * @param integer $bytes - number of bytes to return
+ *
+ * @return string
+ *
+ * @throws FacebookSDKException
+ *
+ * @todo Support Windows platforms
+ */
+ public function random($bytes)
+ {
+ if (!is_numeric($bytes)) {
+ throw new FacebookSDKException(
+ "random() expects an integer"
+ );
+ }
+ if ($bytes < 1) {
+ throw new FacebookSDKException(
+ "random() expects an integer greater than zero"
+ );
+ }
+ $buf = '';
+ // http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/
+ if (false && is_readable('/dev/urandom')) {
+// if (is_readable('/dev/urandom')) {
+ $fp = fopen('/dev/urandom', 'rb');
+ if ($fp !== FALSE) {
+ $buf = fread($fp, $bytes);
+ fclose($fp);
+ if($buf !== FALSE) {
+ return bin2hex($buf);
+ }
+ }
+ }
+
+ if (function_exists('mcrypt_create_iv')) {
+ $buf = mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM);
+ if ($buf !== FALSE) {
+ return bin2hex($buf);
+ }
+ }
+
+ while (strlen($buf) < $bytes) {
+ $buf .= md5(uniqid(mt_rand(), true), true);
+ // We are appending raw binary
+ }
+ return bin2hex(substr($buf, 0, $bytes));
+ }
+
+ /**
+ * Disables the session_status() check when using $_SESSION
+ */
+ public function disableSessionStatusCheck()
+ {
+ $this->checkForSessionStatus = false;
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookRequest.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookRequest.php
new file mode 100644
index 0000000..bab9466
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookRequest.php
@@ -0,0 +1,313 @@
+
+ * @author David Poll
+ */
+class FacebookRequest
+{
+
+ /**
+ * @const string Version number of the Facebook PHP SDK.
+ */
+ const VERSION = '4.0.9';
+
+ /**
+ * @const string Default Graph API version for requests
+ */
+ const GRAPH_API_VERSION = 'v2.0';
+
+ /**
+ * @const string Graph API URL
+ */
+ const BASE_GRAPH_URL = 'https://graph.facebook.com';
+
+ /**
+ * @var FacebookSession The session used for this request
+ */
+ private $session;
+
+ /**
+ * @var string The HTTP method for the request
+ */
+ private $method;
+
+ /**
+ * @var string The path for the request
+ */
+ private $path;
+
+ /**
+ * @var array The parameters for the request
+ */
+ private $params;
+
+ /**
+ * @var string The Graph API version for the request
+ */
+ private $version;
+
+ /**
+ * @var string ETag sent with the request
+ */
+ private $etag;
+
+ /**
+ * @var FacebookHttpable HTTP client handler
+ */
+ private static $httpClientHandler;
+
+ /**
+ * @var int The number of calls that have been made to Graph.
+ */
+ public static $requestCount = 0;
+
+ /**
+ * getSession - Returns the associated FacebookSession.
+ *
+ * @return FacebookSession
+ */
+ public function getSession()
+ {
+ return $this->session;
+ }
+
+ /**
+ * getPath - Returns the associated path.
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ /**
+ * getParameters - Returns the associated parameters.
+ *
+ * @return array
+ */
+ public function getParameters()
+ {
+ return $this->params;
+ }
+
+ /**
+ * getMethod - Returns the associated method.
+ *
+ * @return string
+ */
+ public function getMethod()
+ {
+ return $this->method;
+ }
+
+ /**
+ * getETag - Returns the ETag sent with the request.
+ *
+ * @return string
+ */
+ public function getETag()
+ {
+ return $this->etag;
+ }
+
+ /**
+ * setHttpClientHandler - Returns an instance of the HTTP client
+ * handler
+ *
+ * @param \Facebook\HttpClients\FacebookHttpable
+ */
+ public static function setHttpClientHandler(FacebookHttpable $handler)
+ {
+ static::$httpClientHandler = $handler;
+ }
+
+ /**
+ * getHttpClientHandler - Returns an instance of the HTTP client
+ * data handler
+ *
+ * @return FacebookHttpable
+ */
+ public static function getHttpClientHandler()
+ {
+ if (static::$httpClientHandler) {
+ return static::$httpClientHandler;
+ }
+ return function_exists('curl_init') ? new FacebookCurlHttpClient() : new FacebookStreamHttpClient();
+ }
+
+ /**
+ * FacebookRequest - Returns a new request using the given session. optional
+ * parameters hash will be sent with the request. This object is
+ * immutable.
+ *
+ * @param FacebookSession $session
+ * @param string $method
+ * @param string $path
+ * @param array|null $parameters
+ * @param string|null $version
+ * @param string|null $etag
+ */
+ public function __construct(
+ FacebookSession $session, $method, $path, $parameters = null, $version = null, $etag = null
+ )
+ {
+ $this->session = $session;
+ $this->method = $method;
+ $this->path = $path;
+ if ($version) {
+ $this->version = $version;
+ } else {
+ $this->version = static::GRAPH_API_VERSION;
+ }
+ $this->etag = $etag;
+
+ $params = ($parameters ?: array());
+ if ($session
+ && !isset($params["access_token"])) {
+ $params["access_token"] = $session->getToken();
+ }
+ if (FacebookSession::useAppSecretProof()
+ && !isset($params["appsecret_proof"])) {
+ $params["appsecret_proof"] = $this->getAppSecretProof(
+ $params["access_token"]
+ );
+ }
+ $this->params = $params;
+ }
+
+ /**
+ * Returns the base Graph URL.
+ *
+ * @return string
+ */
+ protected function getRequestURL()
+ {
+ return static::BASE_GRAPH_URL . '/' . $this->version . $this->path;
+ }
+
+ /**
+ * execute - Makes the request to Facebook and returns the result.
+ *
+ * @return FacebookResponse
+ *
+ * @throws FacebookSDKException
+ * @throws FacebookRequestException
+ */
+ public function execute()
+ {
+ $url = $this->getRequestURL();
+ $params = $this->getParameters();
+
+ if ($this->method === "GET") {
+ $url = self::appendParamsToUrl($url, $params);
+ $params = array();
+ }
+
+ $connection = self::getHttpClientHandler();
+ $connection->addRequestHeader('User-Agent', 'fb-php-' . self::VERSION);
+ $connection->addRequestHeader('Accept-Encoding', '*'); // Support all available encodings.
+
+ // ETag
+ if (isset($this->etag)) {
+ $connection->addRequestHeader('If-None-Match', $this->etag);
+ }
+
+ // Should throw `FacebookSDKException` exception on HTTP client error.
+ // Don't catch to allow it to bubble up.
+ $result = $connection->send($url, $this->method, $params);
+
+ static::$requestCount++;
+
+ $etagHit = 304 == $connection->getResponseHttpStatusCode();
+
+ $headers = $connection->getResponseHeaders();
+ $etagReceived = isset($headers['ETag']) ? $headers['ETag'] : null;
+
+ $decodedResult = json_decode($result);
+ if ($decodedResult === null) {
+ $out = array();
+ parse_str($result, $out);
+ return new FacebookResponse($this, $out, $result, $etagHit, $etagReceived);
+ }
+ if (isset($decodedResult->error)) {
+ throw FacebookRequestException::create(
+ $result,
+ $decodedResult->error,
+ $connection->getResponseHttpStatusCode()
+ );
+ }
+
+ return new FacebookResponse($this, $decodedResult, $result, $etagHit, $etagReceived);
+ }
+
+ /**
+ * Generate and return the appsecret_proof value for an access_token
+ *
+ * @param string $token
+ *
+ * @return string
+ */
+ public function getAppSecretProof($token)
+ {
+ return hash_hmac('sha256', $token, FacebookSession::_getTargetAppSecret());
+ }
+
+ /**
+ * appendParamsToUrl - Gracefully appends params to the URL.
+ *
+ * @param string $url
+ * @param array $params
+ *
+ * @return string
+ */
+ public static function appendParamsToUrl($url, $params = array())
+ {
+ if (!$params) {
+ return $url;
+ }
+
+ if (strpos($url, '?') === false) {
+ return $url . '?' . http_build_query($params, null, '&');
+ }
+
+ list($path, $query_string) = explode('?', $url, 2);
+ parse_str($query_string, $query_array);
+
+ // Favor params from the original URL over $params
+ $params = array_merge($params, $query_array);
+
+ return $path . '?' . http_build_query($params, null, '&');
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookRequestException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookRequestException.php
new file mode 100644
index 0000000..8d3fe71
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookRequestException.php
@@ -0,0 +1,222 @@
+
+ * @author David Poll
+ */
+class FacebookRequestException extends FacebookSDKException
+{
+
+ /**
+ * @var int Status code for the response causing the exception
+ */
+ private $statusCode;
+
+ /**
+ * @var string Raw response
+ */
+ private $rawResponse;
+
+ /**
+ * @var array Decoded response
+ */
+ private $responseData;
+
+ /**
+ * Creates a FacebookRequestException.
+ *
+ * @param string $rawResponse The raw response from the Graph API
+ * @param array $responseData The decoded response from the Graph API
+ * @param int $statusCode
+ */
+ public function __construct($rawResponse, $responseData, $statusCode)
+ {
+ $this->rawResponse = $rawResponse;
+ $this->statusCode = $statusCode;
+ $this->responseData = self::convertToArray($responseData);
+ parent::__construct(
+ $this->get('message', 'Unknown Exception'), $this->get('code', -1), null
+ );
+ }
+
+ /**
+ * Process an error payload from the Graph API and return the appropriate
+ * exception subclass.
+ *
+ * @param string $raw the raw response from the Graph API
+ * @param array $data the decoded response from the Graph API
+ * @param int $statusCode the HTTP response code
+ *
+ * @return FacebookRequestException
+ */
+ public static function create($raw, $data, $statusCode)
+ {
+ $data = self::convertToArray($data);
+ if (!isset($data['error']['code']) && isset($data['code'])) {
+ $data = array('error' => $data);
+ }
+ $code = (isset($data['error']['code']) ? $data['error']['code'] : null);
+
+ if (isset($data['error']['error_subcode'])) {
+ switch ($data['error']['error_subcode']) {
+ // Other authentication issues
+ case 458:
+ case 459:
+ case 460:
+ case 463:
+ case 464:
+ case 467:
+ return new FacebookAuthorizationException($raw, $data, $statusCode);
+ break;
+ }
+ }
+
+ switch ($code) {
+ // Login status or token expired, revoked, or invalid
+ case 100:
+ case 102:
+ case 190:
+ return new FacebookAuthorizationException($raw, $data, $statusCode);
+ break;
+
+ // Server issue, possible downtime
+ case 1:
+ case 2:
+ return new FacebookServerException($raw, $data, $statusCode);
+ break;
+
+ // API Throttling
+ case 4:
+ case 17:
+ case 341:
+ return new FacebookThrottleException($raw, $data, $statusCode);
+ break;
+
+ // Duplicate Post
+ case 506:
+ return new FacebookClientException($raw, $data, $statusCode);
+ break;
+ }
+
+ // Missing Permissions
+ if ($code == 10 || ($code >= 200 && $code <= 299)) {
+ return new FacebookPermissionException($raw, $data, $statusCode);
+ }
+
+ // OAuth authentication error
+ if (isset($data['error']['type'])
+ and $data['error']['type'] === 'OAuthException') {
+ return new FacebookAuthorizationException($raw, $data, $statusCode);
+ }
+
+ // All others
+ return new FacebookOtherException($raw, $data, $statusCode);
+ }
+
+ /**
+ * Checks isset and returns that or a default value.
+ *
+ * @param string $key
+ * @param mixed $default
+ *
+ * @return mixed
+ */
+ private function get($key, $default = null)
+ {
+ if (isset($this->responseData['error'][$key])) {
+ return $this->responseData['error'][$key];
+ }
+ return $default;
+ }
+
+ /**
+ * Returns the HTTP status code
+ *
+ * @return int
+ */
+ public function getHttpStatusCode()
+ {
+ return $this->statusCode;
+ }
+
+ /**
+ * Returns the sub-error code
+ *
+ * @return int
+ */
+ public function getSubErrorCode()
+ {
+ return $this->get('error_subcode', -1);
+ }
+
+ /**
+ * Returns the error type
+ *
+ * @return string
+ */
+ public function getErrorType()
+ {
+ return $this->get('type', '');
+ }
+
+ /**
+ * Returns the raw response used to create the exception.
+ *
+ * @return string
+ */
+ public function getRawResponse()
+ {
+ return $this->rawResponse;
+ }
+
+ /**
+ * Returns the decoded response used to create the exception.
+ *
+ * @return array
+ */
+ public function getResponse()
+ {
+ return $this->responseData;
+ }
+
+ /**
+ * Converts a stdClass object to an array
+ *
+ * @param mixed $object
+ *
+ * @return array
+ */
+ private static function convertToArray($object)
+ {
+ if ($object instanceof \stdClass) {
+ return get_object_vars($object);
+ }
+ return $object;
+ }
+
+}
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookResponse.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookResponse.php
new file mode 100644
index 0000000..e174a94
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookResponse.php
@@ -0,0 +1,202 @@
+
+ * @author David Poll
+ */
+class FacebookResponse
+{
+
+ /**
+ * @var FacebookRequest The request which produced this response
+ */
+ private $request;
+
+ /**
+ * @var array The decoded response from the Graph API
+ */
+ private $responseData;
+
+ /**
+ * @var string The raw response from the Graph API
+ */
+ private $rawResponse;
+
+ /**
+ * @var bool Indicates whether sent ETag matched the one on the FB side
+ */
+ private $etagHit;
+
+ /**
+ * @var string ETag received with the response. `null` in case of ETag hit.
+ */
+ private $etag;
+
+ /**
+ * Creates a FacebookResponse object for a given request and response.
+ *
+ * @param FacebookRequest $request
+ * @param array $responseData JSON Decoded response data
+ * @param string $rawResponse Raw string response
+ * @param bool $etagHit Indicates whether sent ETag matched the one on the FB side
+ * @param string|null $etag ETag received with the response. `null` in case of ETag hit.
+ */
+ public function __construct($request, $responseData, $rawResponse, $etagHit = false, $etag = null)
+ {
+ $this->request = $request;
+ $this->responseData = $responseData;
+ $this->rawResponse = $rawResponse;
+ $this->etagHit = $etagHit;
+ $this->etag = $etag;
+ }
+
+ /**
+ * Returns the request which produced this response.
+ *
+ * @return FacebookRequest
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+ /**
+ * Returns the decoded response data.
+ *
+ * @return array
+ */
+ public function getResponse()
+ {
+ return $this->responseData;
+ }
+
+ /**
+ * Returns the raw response
+ *
+ * @return string
+ */
+ public function getRawResponse()
+ {
+ return $this->rawResponse;
+ }
+
+ /**
+ * Returns true if ETag matched the one sent with a request
+ *
+ * @return bool
+ */
+ public function isETagHit()
+ {
+ return $this->etagHit;
+ }
+
+ /**
+ * Returns the ETag
+ *
+ * @return string
+ */
+ public function getETag()
+ {
+ return $this->etag;
+ }
+
+ /**
+ * Gets the result as a GraphObject. If a type is specified, returns the
+ * strongly-typed subclass of GraphObject for the data.
+ *
+ * @param string $type
+ *
+ * @return mixed
+ */
+ public function getGraphObject($type = 'Facebook\GraphObject') {
+ return (new GraphObject($this->responseData))->cast($type);
+ }
+
+ /**
+ * Returns an array of GraphObject returned by the request. If a type is
+ * specified, returns the strongly-typed subclass of GraphObject for the data.
+ *
+ * @param string $type
+ *
+ * @return mixed
+ */
+ public function getGraphObjectList($type = 'Facebook\GraphObject') {
+ $out = array();
+ $data = $this->responseData->data;
+ for ($i = 0; $i < count($data); $i++) {
+ $out[] = (new GraphObject($data[$i]))->cast($type);
+ }
+ return $out;
+ }
+
+ /**
+ * If this response has paginated data, returns the FacebookRequest for the
+ * next page, or null.
+ *
+ * @return FacebookRequest|null
+ */
+ public function getRequestForNextPage()
+ {
+ return $this->handlePagination('next');
+ }
+
+ /**
+ * If this response has paginated data, returns the FacebookRequest for the
+ * previous page, or null.
+ *
+ * @return FacebookRequest|null
+ */
+ public function getRequestForPreviousPage()
+ {
+ return $this->handlePagination('previous');
+ }
+
+ /**
+ * Returns the FacebookRequest for the previous or next page, or null.
+ *
+ * @param string $direction
+ *
+ * @return FacebookRequest|null
+ */
+ private function handlePagination($direction) {
+ if (isset($this->responseData->paging->$direction)) {
+ $url = parse_url($this->responseData->paging->$direction);
+ parse_str($url['query'], $params);
+
+ return new FacebookRequest(
+ $this->request->getSession(),
+ $this->request->getMethod(),
+ $this->request->getPath(),
+ $params
+ );
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookSDKException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookSDKException.php
new file mode 100644
index 0000000..92d1412
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookSDKException.php
@@ -0,0 +1,33 @@
+
+ * @author David Poll
+ */
+class FacebookSession
+{
+
+ /**
+ * @var string
+ */
+ private static $defaultAppId;
+
+ /**
+ * @var string
+ */
+ private static $defaultAppSecret;
+
+ /**
+ * @var AccessToken The AccessToken entity for this connection.
+ */
+ private $accessToken;
+
+ /**
+ * @var SignedRequest
+ */
+ private $signedRequest;
+
+ /**
+ * @var bool
+ */
+ private static $useAppSecretProof = true;
+
+ /**
+ * When creating a Session from an access_token, use:
+ * var $session = new FacebookSession($accessToken);
+ * This will validate the token and provide a Session object ready for use.
+ * It will throw a SessionException in case of error.
+ *
+ * @param AccessToken|string $accessToken
+ * @param SignedRequest $signedRequest The SignedRequest entity
+ */
+ public function __construct($accessToken, SignedRequest $signedRequest = null)
+ {
+ $this->accessToken = $accessToken instanceof AccessToken ? $accessToken : new AccessToken($accessToken);
+ $this->signedRequest = $signedRequest;
+ }
+
+ /**
+ * Returns the access token.
+ *
+ * @return string
+ */
+ public function getToken()
+ {
+ return (string) $this->accessToken;
+ }
+
+ /**
+ * Returns the access token entity.
+ *
+ * @return AccessToken
+ */
+ public function getAccessToken()
+ {
+ return $this->accessToken;
+ }
+
+ /**
+ * Returns the SignedRequest entity.
+ *
+ * @return SignedRequest
+ */
+ public function getSignedRequest()
+ {
+ return $this->signedRequest;
+ }
+
+ /**
+ * Returns the signed request payload.
+ *
+ * @return null|array
+ */
+ public function getSignedRequestData()
+ {
+ return $this->signedRequest ? $this->signedRequest->getPayload() : null;
+ }
+
+ /**
+ * Returns a property from the signed request data if available.
+ *
+ * @param string $key
+ *
+ * @return null|mixed
+ */
+ public function getSignedRequestProperty($key)
+ {
+ return $this->signedRequest ? $this->signedRequest->get($key) : null;
+ }
+
+ /**
+ * Returns user_id from signed request data if available.
+ *
+ * @return null|string
+ */
+ public function getUserId()
+ {
+ return $this->signedRequest ? $this->signedRequest->getUserId() : null;
+ }
+
+ // @TODO Remove getSessionInfo() in 4.1: can be accessed from AccessToken directly
+ /**
+ * getSessionInfo - Makes a request to /debug_token with the appropriate
+ * arguments to get debug information about the sessions token.
+ *
+ * @param string|null $appId
+ * @param string|null $appSecret
+ *
+ * @return GraphSessionInfo
+ */
+ public function getSessionInfo($appId = null, $appSecret = null)
+ {
+ return $this->accessToken->getInfo($appId, $appSecret);
+ }
+
+ // @TODO Remove getLongLivedSession() in 4.1: can be accessed from AccessToken directly
+ /**
+ * getLongLivedSession - Returns a new Facebook session resulting from
+ * extending a short-lived access token. If this session is not
+ * short-lived, returns $this.
+ *
+ * @param string|null $appId
+ * @param string|null $appSecret
+ *
+ * @return FacebookSession
+ */
+ public function getLongLivedSession($appId = null, $appSecret = null)
+ {
+ $longLivedAccessToken = $this->accessToken->extend($appId, $appSecret);
+ return new static($longLivedAccessToken);
+ }
+
+ // @TODO Remove getExchangeToken() in 4.1: can be accessed from AccessToken directly
+ /**
+ * getExchangeToken - Returns an exchange token string which can be sent
+ * back to clients and exchanged for a device-linked access token.
+ *
+ * @param string|null $appId
+ * @param string|null $appSecret
+ *
+ * @return string
+ */
+ public function getExchangeToken($appId = null, $appSecret = null)
+ {
+ return AccessToken::getCodeFromAccessToken($this->accessToken, $appId, $appSecret);
+ }
+
+ // @TODO Remove validate() in 4.1: can be accessed from AccessToken directly
+ /**
+ * validate - Ensures the current session is valid, throwing an exception if
+ * not. Fetches token info from Facebook.
+ *
+ * @param string|null $appId Application ID to use
+ * @param string|null $appSecret App secret value to use
+ * @param string|null $machineId
+ *
+ * @return boolean
+ *
+ * @throws FacebookSDKException
+ */
+ public function validate($appId = null, $appSecret = null, $machineId = null)
+ {
+ if ($this->accessToken->isValid($appId, $appSecret, $machineId)) {
+ return true;
+ }
+
+ // @TODO For v4.1 this should not throw an exception, but just return false.
+ throw new FacebookSDKException(
+ 'Session has expired, or is not valid for this app.', 601
+ );
+ }
+
+ // @TODO Remove validateSessionInfo() in 4.1: can be accessed from AccessToken directly
+ /**
+ * validateTokenInfo - Ensures the provided GraphSessionInfo object is valid,
+ * throwing an exception if not. Ensures the appId matches,
+ * that the token is valid and has not expired.
+ *
+ * @param GraphSessionInfo $tokenInfo
+ * @param string|null $appId Application ID to use
+ * @param string|null $machineId
+ *
+ * @return boolean
+ *
+ * @throws FacebookSDKException
+ */
+ public static function validateSessionInfo(GraphSessionInfo $tokenInfo,
+ $appId = null,
+ $machineId = null)
+ {
+ if (AccessToken::validateAccessToken($tokenInfo, $appId, $machineId)) {
+ return true;
+ }
+
+ // @TODO For v4.1 this should not throw an exception, but just return false.
+ throw new FacebookSDKException(
+ 'Session has expired, or is not valid for this app.', 601
+ );
+ }
+
+ /**
+ * newSessionFromSignedRequest - Returns a FacebookSession for a
+ * given signed request.
+ *
+ * @param SignedRequest $signedRequest
+ *
+ * @return FacebookSession
+ */
+ public static function newSessionFromSignedRequest(SignedRequest $signedRequest)
+ {
+ if ($signedRequest->get('code')
+ && !$signedRequest->get('oauth_token')) {
+ return self::newSessionAfterValidation($signedRequest);
+ }
+ $accessToken = $signedRequest->get('oauth_token');
+ $expiresAt = $signedRequest->get('expires', 0);
+ $accessToken = new AccessToken($accessToken, $expiresAt);
+ return new static($accessToken, $signedRequest);
+ }
+
+ /**
+ * newSessionAfterValidation - Returns a FacebookSession for a
+ * validated & parsed signed request.
+ *
+ * @param SignedRequest $signedRequest
+ *
+ * @return FacebookSession
+ */
+ protected static function newSessionAfterValidation(SignedRequest $signedRequest)
+ {
+ $code = $signedRequest->get('code');
+ $accessToken = AccessToken::getAccessTokenFromCode($code);
+ return new static($accessToken, $signedRequest);
+ }
+
+ /**
+ * newAppSession - Returns a FacebookSession configured with a token for the
+ * application which can be used for publishing and requesting app-level
+ * information.
+ *
+ * @param string|null $appId Application ID to use
+ * @param string|null $appSecret App secret value to use
+ *
+ * @return FacebookSession
+ */
+ public static function newAppSession($appId = null, $appSecret = null)
+ {
+ $targetAppId = static::_getTargetAppId($appId);
+ $targetAppSecret = static::_getTargetAppSecret($appSecret);
+ return new FacebookSession(
+ $targetAppId . '|' . $targetAppSecret
+ );
+ }
+
+ /**
+ * setDefaultApplication - Will set the static default appId and appSecret
+ * to be used for API requests.
+ *
+ * @param string $appId Application ID to use by default
+ * @param string $appSecret App secret value to use by default
+ */
+ public static function setDefaultApplication($appId, $appSecret)
+ {
+ self::$defaultAppId = $appId;
+ self::$defaultAppSecret = $appSecret;
+ }
+
+ /**
+ * _getTargetAppId - Will return either the provided app Id or the default,
+ * throwing if neither are populated.
+ *
+ * @param string $appId
+ *
+ * @return string
+ *
+ * @throws FacebookSDKException
+ */
+ public static function _getTargetAppId($appId = null) {
+ $target = ($appId ?: self::$defaultAppId);
+ if (!$target) {
+ throw new FacebookSDKException(
+ 'You must provide or set a default application id.', 700
+ );
+ }
+ return $target;
+ }
+
+ /**
+ * _getTargetAppSecret - Will return either the provided app secret or the
+ * default, throwing if neither are populated.
+ *
+ * @param string $appSecret
+ *
+ * @return string
+ *
+ * @throws FacebookSDKException
+ */
+ public static function _getTargetAppSecret($appSecret = null) {
+ $target = ($appSecret ?: self::$defaultAppSecret);
+ if (!$target) {
+ throw new FacebookSDKException(
+ 'You must provide or set a default application secret.', 701
+ );
+ }
+ return $target;
+ }
+
+ /**
+ * Enable or disable sending the appsecret_proof with requests.
+ *
+ * @param bool $on
+ */
+ public static function enableAppSecretProof($on = true)
+ {
+ static::$useAppSecretProof = ($on ? true : false);
+ }
+
+ /**
+ * Get whether or not appsecret_proof should be sent with requests.
+ *
+ * @return bool
+ */
+ public static function useAppSecretProof()
+ {
+ return static::$useAppSecretProof;
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookSignedRequestFromInputHelper.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookSignedRequestFromInputHelper.php
new file mode 100644
index 0000000..c497246
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookSignedRequestFromInputHelper.php
@@ -0,0 +1,166 @@
+appId = FacebookSession::_getTargetAppId($appId);
+ $this->appSecret = FacebookSession::_getTargetAppSecret($appSecret);
+
+ $this->instantiateSignedRequest();
+ }
+
+ /**
+ * Instantiates a new SignedRequest entity.
+ *
+ * @param string|null
+ */
+ public function instantiateSignedRequest($rawSignedRequest = null)
+ {
+ $rawSignedRequest = $rawSignedRequest ?: $this->getRawSignedRequest();
+
+ if (!$rawSignedRequest) {
+ return;
+ }
+
+ $this->signedRequest = new SignedRequest($rawSignedRequest, $this->state, $this->appSecret);
+ }
+
+ /**
+ * Instantiates a FacebookSession from the signed request from input.
+ *
+ * @return FacebookSession|null
+ */
+ public function getSession()
+ {
+ if ($this->signedRequest && $this->signedRequest->hasOAuthData()) {
+ return FacebookSession::newSessionFromSignedRequest($this->signedRequest);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the SignedRequest entity.
+ *
+ * @return \Facebook\Entities\SignedRequest|null
+ */
+ public function getSignedRequest()
+ {
+ return $this->signedRequest;
+ }
+
+ /**
+ * Returns the user_id if available.
+ *
+ * @return string|null
+ */
+ public function getUserId()
+ {
+ return $this->signedRequest ? $this->signedRequest->getUserId() : null;
+ }
+
+ /**
+ * Get raw signed request from input.
+ *
+ * @return string|null
+ */
+ abstract public function getRawSignedRequest();
+
+ /**
+ * Get raw signed request from GET input.
+ *
+ * @return string|null
+ */
+ public function getRawSignedRequestFromGet()
+ {
+ if (isset($_GET['signed_request'])) {
+ return $_GET['signed_request'];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get raw signed request from POST input.
+ *
+ * @return string|null
+ */
+ public function getRawSignedRequestFromPost()
+ {
+ if (isset($_POST['signed_request'])) {
+ return $_POST['signed_request'];
+ }
+
+ return null;
+ }
+
+ /**
+ * Get raw signed request from cookie set from the Javascript SDK.
+ *
+ * @return string|null
+ */
+ public function getRawSignedRequestFromCookie()
+ {
+ if (isset($_COOKIE['fbsr_' . $this->appId])) {
+ return $_COOKIE['fbsr_' . $this->appId];
+ }
+ return null;
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookThrottleException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookThrottleException.php
new file mode 100644
index 0000000..a1b2f09
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/FacebookThrottleException.php
@@ -0,0 +1,33 @@
+
+ */
+
+class GraphAlbum extends GraphObject
+{
+ /**
+ * Returns the ID for the album.
+ *
+ * @return string|null
+ */
+ public function getId()
+ {
+ return $this->getProperty('id');
+ }
+
+ /**
+ * Returns whether the viewer can upload photos to this album.
+ *
+ * @return boolean|null
+ */
+ public function canUpload()
+ {
+ return $this->getProperty('can_upload');
+ }
+
+ /**
+ * Returns the number of photos in this album.
+ *
+ * @return int|null
+ */
+ public function getCount()
+ {
+ return$this->getProperty('count');
+ }
+
+ /**
+ * Returns the ID of the album's cover photo.
+ *
+ * @return string|null
+ */
+ public function getCoverPhoto()
+ {
+ return$this->getProperty('cover_photo');
+ }
+
+ /**
+ * Returns the time the album was initially created.
+ *
+ * @return \DateTime|null
+ */
+ public function getCreatedTime()
+ {
+ $value = $this->getProperty('created_time');
+ if ($value) {
+ return new \DateTime($value);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the time the album was updated.
+ *
+ * @return \DateTime|null
+ */
+ public function getUpdatedTime()
+ {
+ $value = $this->getProperty('updated_time');
+ if ($value) {
+ return new \DateTime($value);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the description of the album.
+ *
+ * @return string|null
+ */
+ public function getDescription()
+ {
+ return$this->getProperty('description');
+ }
+
+ /**
+ * Returns profile that created the album.
+ *
+ * @return GraphUser|null
+ */
+ public function getFrom()
+ {
+ return $this->getProperty('from', GraphUser::className());
+ }
+
+ /**
+ * Returns a link to this album on Facebook.
+ *
+ * @return string|null
+ */
+ public function getLink()
+ {
+ return$this->getProperty('link');
+ }
+
+ /**
+ * Returns the textual location of the album.
+ *
+ * @return string|null
+ */
+ public function getLocation()
+ {
+ return$this->getProperty('location');
+ }
+
+ /**
+ * Returns the title of the album.
+ *
+ * @return string|null
+ */
+ public function getName()
+ {
+ return$this->getProperty('name');
+ }
+
+ /**
+ * Returns the privacy settings for the album.
+ *
+ * @return string|null
+ */
+ public function getPrivacy()
+ {
+ return$this->getProperty('privacy');
+ }
+
+ /**
+ * Returns the type of the album. enum{profile, mobile, wall, normal, album}
+ *
+ * @return string|null
+ */
+ public function getType()
+ {
+ return$this->getProperty('type');
+ }
+
+ //TODO: public function getPlace() that should return GraphPage
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphLocation.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphLocation.php
new file mode 100644
index 0000000..5326ea5
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphLocation.php
@@ -0,0 +1,105 @@
+
+ * @author David Poll
+ */
+class GraphLocation extends GraphObject
+{
+
+ /**
+ * Returns the street component of the location
+ *
+ * @return string|null
+ */
+ public function getStreet()
+ {
+ return $this->getProperty('street');
+ }
+
+ /**
+ * Returns the city component of the location
+ *
+ * @return string|null
+ */
+ public function getCity()
+ {
+ return $this->getProperty('city');
+ }
+
+ /**
+ * Returns the state component of the location
+ *
+ * @return string|null
+ */
+ public function getState()
+ {
+ return $this->getProperty('state');
+ }
+
+ /**
+ * Returns the country component of the location
+ *
+ * @return string|null
+ */
+ public function getCountry()
+ {
+ return $this->getProperty('country');
+ }
+
+ /**
+ * Returns the zipcode component of the location
+ *
+ * @return string|null
+ */
+ public function getZip()
+ {
+ return $this->getProperty('zip');
+ }
+
+ /**
+ * Returns the latitude component of the location
+ *
+ * @return float|null
+ */
+ public function getLatitude()
+ {
+ return $this->getProperty('latitude');
+ }
+
+ /**
+ * Returns the street component of the location
+ *
+ * @return float|null
+ */
+ public function getLongitude()
+ {
+ return $this->getProperty('longitude');
+ }
+
+}
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphObject.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphObject.php
new file mode 100644
index 0000000..4f22d2b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphObject.php
@@ -0,0 +1,167 @@
+
+ * @author David Poll
+ */
+class GraphObject
+{
+
+ /**
+ * @var array - Holds the raw associative data for this object
+ */
+ protected $backingData;
+
+ /**
+ * Creates a GraphObject using the data provided.
+ *
+ * @param array $raw
+ */
+ public function __construct($raw)
+ {
+ if ($raw instanceof \stdClass) {
+ $raw = get_object_vars($raw);
+ }
+ $this->backingData = $raw;
+
+ if (isset($this->backingData['data']) && count($this->backingData) === 1) {
+ $this->backingData = $this->backingData['data'];
+ }
+ }
+
+ /**
+ * cast - Return a new instance of a FacebookGraphObject subclass for this
+ * objects underlying data.
+ *
+ * @param string $type The GraphObject subclass to cast to
+ *
+ * @return GraphObject
+ *
+ * @throws FacebookSDKException
+ */
+ public function cast($type)
+ {
+ if ($this instanceof $type) {
+ return $this;
+ }
+ if (is_subclass_of($type, GraphObject::className())) {
+ return new $type($this->backingData);
+ } else {
+ throw new FacebookSDKException(
+ 'Cannot cast to an object that is not a GraphObject subclass', 620
+ );
+ }
+ }
+
+ /**
+ * asArray - Return a key-value associative array for the given graph object.
+ *
+ * @return array
+ */
+ public function asArray()
+ {
+ return $this->backingData;
+ }
+
+ /**
+ * getProperty - Gets the value of the named property for this graph object,
+ * cast to the appropriate subclass type if provided.
+ *
+ * @param string $name The property to retrieve
+ * @param string $type The subclass of GraphObject, optionally
+ *
+ * @return mixed
+ */
+ public function getProperty($name, $type = 'Facebook\GraphObject')
+ {
+ if (isset($this->backingData[$name])) {
+ $value = $this->backingData[$name];
+ if (is_scalar($value)) {
+ return $value;
+ } else {
+ return (new GraphObject($value))->cast($type);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * getPropertyAsArray - Get the list value of a named property for this graph
+ * object, where each item has been cast to the appropriate subclass type
+ * if provided.
+ *
+ * Calling this for a property that is not an array, the behavior
+ * is undefined, so don’t do this.
+ *
+ * @param string $name The property to retrieve
+ * @param string $type The subclass of GraphObject, optionally
+ *
+ * @return array
+ */
+ public function getPropertyAsArray($name, $type = 'Facebook\GraphObject')
+ {
+ $target = array();
+ if (isset($this->backingData[$name]['data'])) {
+ $target = $this->backingData[$name]['data'];
+ } else if (isset($this->backingData[$name])
+ && !is_scalar($this->backingData[$name])) {
+ $target = $this->backingData[$name];
+ }
+ $out = array();
+ foreach ($target as $key => $value) {
+ if (is_scalar($value)) {
+ $out[$key] = $value;
+ } else {
+ $out[$key] = (new GraphObject($value))->cast($type);
+ }
+ }
+ return $out;
+ }
+
+ /**
+ * getPropertyNames - Returns a list of all properties set on the object.
+ *
+ * @return array
+ */
+ public function getPropertyNames()
+ {
+ return array_keys($this->backingData);
+ }
+
+ /**
+ * Returns the string class name of the GraphObject or subclass.
+ *
+ * @return string
+ */
+ public static function className()
+ {
+ return get_called_class();
+ }
+
+}
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphPage.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphPage.php
new file mode 100644
index 0000000..a66068e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphPage.php
@@ -0,0 +1,64 @@
+
+ */
+class GraphPage extends GraphObject
+{
+
+ /**
+ * Returns the ID for the user's page as a string if present.
+ *
+ * @return string|null
+ */
+ public function getId()
+ {
+ return $this->getProperty('id');
+ }
+
+ /**
+ * Returns the Category for the user's page as a string if present.
+ *
+ * @return string|null
+ */
+ public function getCategory()
+ {
+ return $this->getProperty('category');
+ }
+
+ /**
+ * Returns the Name of the user's page as a string if present.
+ *
+ * @return string|null
+ */
+ public function getName()
+ {
+ return $this->getProperty('name');
+ }
+
+}
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphSessionInfo.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphSessionInfo.php
new file mode 100644
index 0000000..4b97580
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphSessionInfo.php
@@ -0,0 +1,115 @@
+
+ * @author David Poll
+ */
+class GraphSessionInfo extends GraphObject
+{
+
+ /**
+ * Returns the application id the token was issued for.
+ *
+ * @return string|null
+ */
+ public function getAppId()
+ {
+ return $this->getProperty('app_id');
+ }
+
+ /**
+ * Returns the application name the token was issued for.
+ *
+ * @return string|null
+ */
+ public function getApplication()
+ {
+ return $this->getProperty('application');
+ }
+
+ /**
+ * Returns the date & time that the token expires.
+ *
+ * @return \DateTime|null
+ */
+ public function getExpiresAt()
+ {
+ $stamp = $this->getProperty('expires_at');
+ if ($stamp) {
+ return (new \DateTime())->setTimestamp($stamp);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns whether the token is valid.
+ *
+ * @return boolean
+ */
+ public function isValid()
+ {
+ return $this->getProperty('is_valid');
+ }
+
+ /**
+ * Returns the date & time the token was issued at.
+ *
+ * @return \DateTime|null
+ */
+ public function getIssuedAt()
+ {
+ $stamp = $this->getProperty('issued_at');
+ if ($stamp) {
+ return (new \DateTime())->setTimestamp($stamp);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the scope permissions associated with the token.
+ *
+ * @return array
+ */
+ public function getScopes()
+ {
+ return $this->getPropertyAsArray('scopes');
+ }
+
+ /**
+ * Returns the login id of the user associated with the token.
+ *
+ * @return string|null
+ */
+ public function getId()
+ {
+ return $this->getProperty('user_id');
+ }
+
+}
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphUser.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphUser.php
new file mode 100644
index 0000000..8da369f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphUser.php
@@ -0,0 +1,120 @@
+
+ * @author David Poll
+ */
+class GraphUser extends GraphObject
+{
+
+ /**
+ * Returns the ID for the user as a string if present.
+ *
+ * @return string|null
+ */
+ public function getId()
+ {
+ return $this->getProperty('id');
+ }
+
+ /**
+ * Returns the name for the user as a string if present.
+ *
+ * @return string|null
+ */
+ public function getName()
+ {
+ return $this->getProperty('name');
+ }
+
+ /**
+ * Returns the first name for the user as a string if present.
+ *
+ * @return string|null
+ */
+ public function getFirstName()
+ {
+ return $this->getProperty('first_name');
+ }
+
+ /**
+ * Returns the middle name for the user as a string if present.
+ *
+ * @return string|null
+ */
+ public function getMiddleName()
+ {
+ return $this->getProperty('middle_name');
+ }
+
+ /**
+ * Returns the last name for the user as a string if present.
+ *
+ * @return string|null
+ */
+ public function getLastName()
+ {
+ return $this->getProperty('last_name');
+ }
+
+ /**
+ * Returns the Facebook URL for the user as a string if available.
+ *
+ * @return string|null
+ */
+ public function getLink()
+ {
+ return $this->getProperty('link');
+ }
+
+ /**
+ * Returns the users birthday, if available.
+ *
+ * @return \DateTime|null
+ */
+ public function getBirthday()
+ {
+ $value = $this->getProperty('birthday');
+ if ($value) {
+ return new \DateTime($value);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the current location of the user as a FacebookGraphLocation
+ * if available.
+ *
+ * @return GraphLocation|null
+ */
+ public function getLocation()
+ {
+ return $this->getProperty('location', GraphLocation::className());
+ }
+
+}
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphUserPage.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphUserPage.php
new file mode 100644
index 0000000..9115da1
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/GraphUserPage.php
@@ -0,0 +1,84 @@
+
+ */
+class GraphUserPage extends GraphObject
+{
+
+ /**
+ * Returns the ID for the user's page as a string if present.
+ *
+ * @return string|null
+ */
+ public function getId()
+ {
+ return $this->getProperty('id');
+ }
+
+ /**
+ * Returns the Category for the user's page as a string if present.
+ *
+ * @return string|null
+ */
+ public function getCategory()
+ {
+ return $this->getProperty('category');
+ }
+
+ /**
+ * Returns the Name of the user's page as a string if present.
+ *
+ * @return string|null
+ */
+ public function getName()
+ {
+ return $this->getProperty('name');
+ }
+
+ /**
+ * Returns the Access Token used to access the user's page as a string if present.
+ *
+ * @return string|null
+ */
+ public function getAccessToken()
+ {
+ return $this->getProperty('access_token');
+ }
+
+ /**
+ * Returns the Permissions for the user's page as an array if present.
+ *
+ * @return array|null
+ */
+ public function getPermissions()
+ {
+ return $this->getProperty('perms');
+ }
+
+}
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/FacebookCurl.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/FacebookCurl.php
new file mode 100644
index 0000000..5b20e92
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/FacebookCurl.php
@@ -0,0 +1,129 @@
+curl = curl_init();
+ }
+
+ /**
+ * Set a curl option
+ *
+ * @param $key
+ * @param $value
+ */
+ public function setopt($key, $value)
+ {
+ curl_setopt($this->curl, $key, $value);
+ }
+
+ /**
+ * Set an array of options to a curl resource
+ *
+ * @param array $options
+ */
+ public function setopt_array(array $options)
+ {
+ curl_setopt_array($this->curl, $options);
+ }
+
+ /**
+ * Send a curl request
+ *
+ * @return mixed
+ */
+ public function exec()
+ {
+ return curl_exec($this->curl);
+ }
+
+ /**
+ * Return the curl error number
+ *
+ * @return int
+ */
+ public function errno()
+ {
+ return curl_errno($this->curl);
+ }
+
+ /**
+ * Return the curl error message
+ *
+ * @return string
+ */
+ public function error()
+ {
+ return curl_error($this->curl);
+ }
+
+ /**
+ * Get info from a curl reference
+ *
+ * @param $type
+ *
+ * @return mixed
+ */
+ public function getinfo($type)
+ {
+ return curl_getinfo($this->curl, $type);
+ }
+
+ /**
+ * Get the currently installed curl version
+ *
+ * @return array
+ */
+ public function version()
+ {
+ return curl_version();
+ }
+
+ /**
+ * Close the resource connection to curl
+ */
+ public function close()
+ {
+ curl_close($this->curl);
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/FacebookCurlHttpClient.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/FacebookCurlHttpClient.php
new file mode 100644
index 0000000..bfe3fce
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/FacebookCurlHttpClient.php
@@ -0,0 +1,323 @@
+requestHeaders[$key] = $value;
+ }
+
+ /**
+ * The headers returned in the response
+ *
+ * @return array
+ */
+ public function getResponseHeaders()
+ {
+ return $this->responseHeaders;
+ }
+
+ /**
+ * The HTTP status response code
+ *
+ * @return int
+ */
+ public function getResponseHttpStatusCode()
+ {
+ return $this->responseHttpStatusCode;
+ }
+
+ /**
+ * Sends a request to the server
+ *
+ * @param string $url The endpoint to send the request to
+ * @param string $method The request method
+ * @param array $parameters The key value pairs to be sent in the body
+ *
+ * @return string Raw response from the server
+ *
+ * @throws \Facebook\FacebookSDKException
+ */
+ public function send($url, $method = 'GET', $parameters = array())
+ {
+ $this->openConnection($url, $method, $parameters);
+ $this->tryToSendRequest();
+
+ // Need to verify the peer
+ if ($this->curlErrorCode == 60 || $this->curlErrorCode == 77) {
+ $this->addBundledCert();
+ $this->tryToSendRequest();
+ }
+
+ if ($this->curlErrorCode) {
+ throw new FacebookSDKException($this->curlErrorMessage, $this->curlErrorCode);
+ }
+
+ // Separate the raw headers from the raw body
+ list($rawHeaders, $rawBody) = $this->extractResponseHeadersAndBody();
+
+ $this->responseHeaders = self::headersToArray($rawHeaders);
+
+ $this->closeConnection();
+
+ return $rawBody;
+ }
+
+ /**
+ * Opens a new curl connection
+ *
+ * @param string $url The endpoint to send the request to
+ * @param string $method The request method
+ * @param array $parameters The key value pairs to be sent in the body
+ */
+ public function openConnection($url, $method = 'GET', $parameters = array())
+ {
+ $options = array(
+ CURLOPT_URL => $url,
+ CURLOPT_CONNECTTIMEOUT => 10,
+ CURLOPT_TIMEOUT => 60,
+ CURLOPT_RETURNTRANSFER => true, // Follow 301 redirects
+ CURLOPT_HEADER => true, // Enable header processing
+ );
+
+ if ($method !== "GET") {
+ $options[CURLOPT_POSTFIELDS] = $parameters;
+ }
+ if ($method === 'DELETE' || $method === 'PUT') {
+ $options[CURLOPT_CUSTOMREQUEST] = $method;
+ }
+
+ if (!empty($this->requestHeaders)) {
+ $options[CURLOPT_HTTPHEADER] = $this->compileRequestHeaders();
+ }
+
+ self::$facebookCurl->init();
+ self::$facebookCurl->setopt_array($options);
+ }
+
+ /**
+ * Add a bundled cert to the connection
+ */
+ public function addBundledCert()
+ {
+ self::$facebookCurl->setopt(CURLOPT_CAINFO,
+ dirname(__FILE__) . DIRECTORY_SEPARATOR . 'fb_ca_chain_bundle.crt');
+ }
+
+ /**
+ * Closes an existing curl connection
+ */
+ public function closeConnection()
+ {
+ self::$facebookCurl->close();
+ }
+
+ /**
+ * Try to send the request
+ */
+ public function tryToSendRequest()
+ {
+ $this->sendRequest();
+ $this->curlErrorMessage = self::$facebookCurl->error();
+ $this->curlErrorCode = self::$facebookCurl->errno();
+ $this->responseHttpStatusCode = self::$facebookCurl->getinfo(CURLINFO_HTTP_CODE);
+ }
+
+ /**
+ * Send the request and get the raw response from curl
+ */
+ public function sendRequest()
+ {
+ $this->rawResponse = self::$facebookCurl->exec();
+ }
+
+ /**
+ * Compiles the request headers into a curl-friendly format
+ *
+ * @return array
+ */
+ public function compileRequestHeaders()
+ {
+ $return = array();
+
+ foreach ($this->requestHeaders as $key => $value) {
+ $return[] = $key . ': ' . $value;
+ }
+
+ return $return;
+ }
+
+ /**
+ * Extracts the headers and the body into a two-part array
+ *
+ * @return array
+ */
+ public function extractResponseHeadersAndBody()
+ {
+ $headerSize = self::getHeaderSize();
+
+ $rawHeaders = mb_substr($this->rawResponse, 0, $headerSize);
+ $rawBody = mb_substr($this->rawResponse, $headerSize);
+
+ return array(trim($rawHeaders), trim($rawBody));
+ }
+
+ /**
+ * Converts raw header responses into an array
+ *
+ * @param string $rawHeaders
+ *
+ * @return array
+ */
+ public static function headersToArray($rawHeaders)
+ {
+ $headers = array();
+
+ // Normalize line breaks
+ $rawHeaders = str_replace("\r\n", "\n", $rawHeaders);
+
+ // There will be multiple headers if a 301 was followed
+ // or a proxy was followed, etc
+ $headerCollection = explode("\n\n", trim($rawHeaders));
+ // We just want the last response (at the end)
+ $rawHeader = array_pop($headerCollection);
+
+ $headerComponents = explode("\n", $rawHeader);
+ foreach ($headerComponents as $line) {
+ if (strpos($line, ': ') === false) {
+ $headers['http_code'] = $line;
+ } else {
+ list ($key, $value) = explode(': ', $line);
+ $headers[$key] = $value;
+ }
+ }
+
+ return $headers;
+ }
+
+ /**
+ * Return proper header size
+ *
+ * @return integer
+ */
+ private function getHeaderSize()
+ {
+ $headerSize = self::$facebookCurl->getinfo(CURLINFO_HEADER_SIZE);
+ // This corrects a Curl bug where header size does not account
+ // for additional Proxy headers.
+ if ( self::needsCurlProxyFix() ) {
+ // Additional way to calculate the request body size.
+ if (preg_match('/Content-Length: (\d+)/', $this->rawResponse, $m)) {
+ $headerSize = mb_strlen($this->rawResponse) - $m[1];
+ } elseif (stripos($this->rawResponse, self::CONNECTION_ESTABLISHED) !== false) {
+ $headerSize += mb_strlen(self::CONNECTION_ESTABLISHED);
+ }
+ }
+
+ return $headerSize;
+ }
+
+ /**
+ * Detect versions of Curl which report incorrect header lengths when
+ * using Proxies.
+ *
+ * @return boolean
+ */
+ private static function needsCurlProxyFix()
+ {
+ $ver = self::$facebookCurl->version();
+ $version = $ver['version_number'];
+
+ return $version < self::CURL_PROXY_QUIRK_VER;
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/FacebookGuzzleHttpClient.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/FacebookGuzzleHttpClient.php
new file mode 100644
index 0000000..de69773
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/FacebookGuzzleHttpClient.php
@@ -0,0 +1,132 @@
+requestHeaders[$key] = $value;
+ }
+
+ /**
+ * The headers returned in the response
+ *
+ * @return array
+ */
+ public function getResponseHeaders()
+ {
+ return $this->responseHeaders;
+ }
+
+ /**
+ * The HTTP status response code
+ *
+ * @return int
+ */
+ public function getResponseHttpStatusCode()
+ {
+ return $this->responseHttpStatusCode;
+ }
+
+ /**
+ * Sends a request to the server
+ *
+ * @param string $url The endpoint to send the request to
+ * @param string $method The request method
+ * @param array $parameters The key value pairs to be sent in the body
+ *
+ * @return string Raw response from the server
+ *
+ * @throws \Facebook\FacebookSDKException
+ */
+ public function send($url, $method = 'GET', $parameters = array())
+ {
+ $options = array();
+ if ($parameters) {
+ $options = array('body' => $parameters);
+ }
+
+ $request = self::$guzzleClient->createRequest($method, $url, $options);
+
+ foreach($this->requestHeaders as $k => $v) {
+ $request->setHeader($k, $v);
+ }
+
+ try {
+ $rawResponse = self::$guzzleClient->send($request);
+ } catch (RequestException $e) {
+ if ($e->getPrevious() instanceof AdapterException) {
+ throw new FacebookSDKException($e->getMessage(), $e->getCode());
+ }
+ $rawResponse = $e->getResponse();
+ }
+
+ $this->responseHttpStatusCode = $rawResponse->getStatusCode();
+ $this->responseHeaders = $rawResponse->getHeaders();
+
+ return $rawResponse->getBody();
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/FacebookHttpable.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/FacebookHttpable.php
new file mode 100644
index 0000000..e3afaf3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/FacebookHttpable.php
@@ -0,0 +1,68 @@
+stream = stream_context_create($options);
+ }
+
+ /**
+ * The response headers from the stream wrapper
+ *
+ * @return array|null
+ */
+ public function getResponseHeaders()
+ {
+ return $this->responseHeaders;
+ }
+
+ /**
+ * Send a stream wrapped request
+ *
+ * @param string $url
+ *
+ * @return mixed
+ */
+ public function fileGetContents($url)
+ {
+ $rawResponse = file_get_contents($url, false, $this->stream);
+ $this->responseHeaders = $http_response_header;
+ return $rawResponse;
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/FacebookStreamHttpClient.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/FacebookStreamHttpClient.php
new file mode 100644
index 0000000..006d103
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/FacebookStreamHttpClient.php
@@ -0,0 +1,188 @@
+requestHeaders[$key] = $value;
+ }
+
+ /**
+ * The headers returned in the response
+ *
+ * @return array
+ */
+ public function getResponseHeaders()
+ {
+ return $this->responseHeaders;
+ }
+
+ /**
+ * The HTTP status response code
+ *
+ * @return int
+ */
+ public function getResponseHttpStatusCode()
+ {
+ return $this->responseHttpStatusCode;
+ }
+
+ /**
+ * Sends a request to the server
+ *
+ * @param string $url The endpoint to send the request to
+ * @param string $method The request method
+ * @param array $parameters The key value pairs to be sent in the body
+ *
+ * @return string Raw response from the server
+ *
+ * @throws \Facebook\FacebookSDKException
+ */
+ public function send($url, $method = 'GET', $parameters = array())
+ {
+ $options = array(
+ 'http' => array(
+ 'method' => $method,
+ 'timeout' => 60,
+ 'ignore_errors' => true
+ ),
+ 'ssl' => array(
+ 'verify_peer' => true,
+ 'cafile' => dirname(__FILE__) . DIRECTORY_SEPARATOR . 'fb_ca_chain_bundle.crt',
+ ),
+ );
+
+ if ($parameters) {
+ $options['http']['content'] = http_build_query($parameters, null, '&');
+
+ $this->addRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+ }
+
+ $options['http']['header'] = $this->compileHeader();
+
+ self::$facebookStream->streamContextCreate($options);
+ $rawResponse = self::$facebookStream->fileGetContents($url);
+ $rawHeaders = self::$facebookStream->getResponseHeaders();
+
+ if ($rawResponse === false || !$rawHeaders) {
+ throw new FacebookSDKException('Stream returned an empty response', 660);
+ }
+
+ $this->responseHeaders = self::formatHeadersToArray($rawHeaders);
+ $this->responseHttpStatusCode = self::getStatusCodeFromHeader($this->responseHeaders['http_code']);
+
+ return $rawResponse;
+ }
+
+ /**
+ * Formats the headers for use in the stream wrapper
+ *
+ * @return string
+ */
+ public function compileHeader()
+ {
+ $header = [];
+ foreach($this->requestHeaders as $k => $v) {
+ $header[] = $k . ': ' . $v;
+ }
+
+ return implode("\r\n", $header);
+ }
+
+ /**
+ * Converts array of headers returned from the wrapper into
+ * something standard
+ *
+ * @param array $rawHeaders
+ *
+ * @return array
+ */
+ public static function formatHeadersToArray(array $rawHeaders)
+ {
+ $headers = array();
+
+ foreach ($rawHeaders as $line) {
+ if (strpos($line, ':') === false) {
+ $headers['http_code'] = $line;
+ } else {
+ list ($key, $value) = explode(': ', $line);
+ $headers[$key] = $value;
+ }
+ }
+
+ return $headers;
+ }
+
+ /**
+ * Pulls out the HTTP status code from a response header
+ *
+ * @param string $header
+ *
+ * @return int
+ */
+ public static function getStatusCodeFromHeader($header)
+ {
+ preg_match('|HTTP/\d\.\d\s+(\d+)\s+.*|', $header, $match);
+ return (int) $match[1];
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/fb_ca_chain_bundle.crt b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/fb_ca_chain_bundle.crt
new file mode 100644
index 0000000..969239f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Facebook/HttpClients/fb_ca_chain_bundle.crt
@@ -0,0 +1,3920 @@
+##
+## ca-bundle.crt -- Bundle of CA Root Certificates
+##
+## Certificate data from Mozilla as of: Thu Oct 18 19:05:59 2012
+##
+## This is a bundle of X.509 certificates of public Certificate Authorities
+## (CA). These were automatically extracted from Mozilla's root certificates
+## file (certdata.txt). This file can be found in the mozilla source tree:
+## http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1
+##
+## It contains the certificates in PEM format and therefore
+## can be directly used with curl / libcurl / php_curl, or with
+## an Apache+mod_ssl webserver for SSL client authentication.
+## Just configure this file as the SSLCACertificateFile.
+##
+
+# @(#) $RCSfile: certdata.txt,v $ $Revision: 1.86 $ $Date: 2012/10/18 16:26:52 $
+
+GTE CyberTrust Global Root
+==========================
+-----BEGIN CERTIFICATE-----
+MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg
+Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG
+A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz
+MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL
+Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0
+IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u
+sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql
+HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID
+AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW
+M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF
+NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
+-----END CERTIFICATE-----
+
+Thawte Server CA
+================
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
+DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs
+dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE
+AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j
+b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV
+BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u
+c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG
+A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0
+ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl
+/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7
+1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR
+MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J
+GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ
+GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc=
+-----END CERTIFICATE-----
+
+Thawte Premium Server CA
+========================
+-----BEGIN CERTIFICATE-----
+MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT
+DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs
+dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE
+AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl
+ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT
+AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU
+VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2
+aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ
+cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2
+aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh
+Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/
+qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm
+SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf
+8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t
+UCemDaYj+bvLpgcUQg==
+-----END CERTIFICATE-----
+
+Equifax Secure CA
+=================
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE
+ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
+MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT
+B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB
+nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR
+fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW
+8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG
+A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE
+CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG
+A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS
+spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB
+Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961
+zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB
+BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95
+70+sB3c4
+-----END CERTIFICATE-----
+
+Digital Signature Trust Co. Global CA 1
+=======================================
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE
+ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMTAeFw05ODEy
+MTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs
+IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUA
+A4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJE
+NySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2i
+o74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo
+BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0
+dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw
+IoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQY
+MBaAFGp5fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAM
+BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB
+ACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lNQseSJqBcNJo4cvj9axY+IO6CizEq
+kzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4
+RbyhkwS7hp86W0N6w4pl
+-----END CERTIFICATE-----
+
+Digital Signature Trust Co. Global CA 3
+=======================================
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE
+ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMjAeFw05ODEy
+MDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs
+IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUA
+A4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGOD
+VvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JS
+xhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo
+BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0
+dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw
+IoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQY
+MBaAFB6CTShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAM
+BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB
+AEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHRxdf0CiUPPXiBng+xZ8SQTGPdXqfi
+up/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1
+mPnHfxsb1gYgAlihw6ID
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx
+FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5
+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow
+XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz
+IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94
+f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol
+hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA
+TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah
+WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf
+Tqj/ZA1k
+-----END CERTIFICATE-----
+
+Verisign Class 1 Public Primary Certification Authority - G2
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT
+MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFy
+eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
+dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT
+MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFy
+eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
+dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgd
+k4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIq
+WpDBucSmFc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQAB
+MA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9ZrbWB85a7FkCMM
+XErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2uluIncrKTdcu1OofdPvAbT6shkdHvC
+lUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68DzFc6PLZ
+-----END CERTIFICATE-----
+
+Verisign Class 2 Public Primary Certification Authority - G2
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1h
+cnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNp
+Z24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1
+c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1h
+cnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNp
+Z24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1
+c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjx
+nNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRC
+wiNPStjwDqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEA
+ATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/7aHmZuovCfTK
+1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAXrXfMSTWqz9iP0b63GJZHc2pUIjRk
+LbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnInjBJ7xUS0rg==
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority - G2
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT
+MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy
+eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
+dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT
+MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy
+eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
+dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO
+FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71
+lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB
+MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT
+1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD
+Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9
+-----END CERTIFICATE-----
+
+GlobalSign Root CA
+==================
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx
+GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds
+b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV
+BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD
+VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
+DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc
+THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb
+Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP
+c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX
+gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF
+AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj
+Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG
+j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH
+hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC
+X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----
+
+GlobalSign Root CA - R2
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv
+YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
+bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
+aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
+bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6
+ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp
+s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN
+S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL
+TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C
+ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i
+YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN
+BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp
+9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu
+01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7
+9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+-----END CERTIFICATE-----
+
+ValiCert Class 1 VA
+===================
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp
+b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh
+bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIy
+MjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0
+d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEg
+UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0
+LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIi
+GQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCm
+DuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwG
+lN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkX
+icnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nP
+Orf1LXLI
+-----END CERTIFICATE-----
+
+ValiCert Class 2 VA
+===================
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp
+b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh
+bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw
+MTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0
+d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIg
+UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0
+LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVC
+CSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7Rf
+ZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZ
+SWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbV
+UjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8
+W9ViH0Pd
+-----END CERTIFICATE-----
+
+RSA Root Certificate 1
+======================
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp
+b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh
+bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw
+MjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0
+d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMg
+UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0
+LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td
+3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89H
+BFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs
+3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjF
+V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r
+on+jjBXu
+-----END CERTIFICATE-----
+
+Verisign Class 1 Public Primary Certification Authority - G3
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
+cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
+dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/E
+bRrsC+MO8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJ
+rKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7PoBMAGrgnoeS+
+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP26KbqxzcSXKMpHgLZ2x87tNcPVkeB
+FQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
+q2aN17O6x5q25lXQBfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/N
+y9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3
+ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrspSCAaWihT37h
+a88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/Pc
+D98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g==
+-----END CERTIFICATE-----
+
+Verisign Class 2 Public Primary Certification Authority - G3
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJBgNVBAYTAlVT
+MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29y
+azE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ug
+b25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0
+aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1
+c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y
+aXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6
+tW8UvxDOJxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7
+C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQHgiBVrKtaaNS
+0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjNqWm6o+sdDZykIKbBoMXRRkwXbdKs
+Zj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0
+JhU8wI1NQ0kdvekhktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf
+0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU
+sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RIsH/7NiXaldDx
+JBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//j
+GHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority - G3
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
+cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
+dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1
+EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc
+cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw
+EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj
+055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
+ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f
+j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
+/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0
+xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa
+t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
+-----END CERTIFICATE-----
+
+Verisign Class 4 Public Primary Certification Authority - G3
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
+cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
+dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS
+tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM
+8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW
+Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX
+Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
+j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt
+mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
+fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd
+RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG
+UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
+-----END CERTIFICATE-----
+
+Entrust.net Secure Server CA
+============================
+-----BEGIN CERTIFICATE-----
+MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV
+BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg
+cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl
+ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv
+cml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIG
+A1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi
+eSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1p
+dGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQ
+aO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5
+gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcw
+ggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQsw
+CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5l
+dC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
+bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
+dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkw
+NTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow
+HQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA
+BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyN
+Ewr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9
+n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
+-----END CERTIFICATE-----
+
+Entrust.net Premium 2048 Secure Server CA
+=========================================
+-----BEGIN CERTIFICATE-----
+MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u
+ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp
+bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
+BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx
+NzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3
+d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
+MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u
+ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL
+Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr
+hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW
+nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi
+VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo3QwcjARBglghkgBhvhC
+AQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdER
+gL7YibkIozH5oSQJFrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B
+AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo
+oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQh7A6tcOdBTcS
+o8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z
+2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjX
+OP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ==
+-----END CERTIFICATE-----
+
+Baltimore CyberTrust Root
+=========================
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE
+ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li
+ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC
+SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs
+dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME
+uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB
+UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C
+G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9
+XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr
+l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI
+VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB
+BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh
+cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5
+hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa
+Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
+RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+-----END CERTIFICATE-----
+
+Equifax Secure Global eBusiness CA
+==================================
+-----BEGIN CERTIFICATE-----
+MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
+RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp
+bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx
+HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds
+b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV
+PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN
+qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn
+hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j
+BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs
+MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN
+I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY
+NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
+-----END CERTIFICATE-----
+
+Equifax Secure eBusiness CA 1
+=============================
+-----BEGIN CERTIFICATE-----
+MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
+RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB
+LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE
+ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz
+IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ
+1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a
+IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk
+MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW
+Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF
+AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5
+lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+
+KpYrtWKmpj29f5JZzVoqgrI3eQ==
+-----END CERTIFICATE-----
+
+Equifax Secure eBusiness CA 2
+=============================
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEXMBUGA1UE
+ChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y
+MB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoT
+DkVxdWlmYXggU2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCB
+nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn
+2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5
+BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAG
+A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUx
+JjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoG
+A1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9e
+uSBIplBqy/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMB
+Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAAyGgq3oThr1
+jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia
+78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUm
+V+GRMOrN
+-----END CERTIFICATE-----
+
+AddTrust Low-Value Services Root
+================================
+-----BEGIN CERTIFICATE-----
+MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU
+cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw
+CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO
+ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6
+54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr
+oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1
+Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui
+GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w
+HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD
+AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT
+RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw
+HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt
+ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph
+iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
+eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr
+mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj
+ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
+-----END CERTIFICATE-----
+
+AddTrust External Root
+======================
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD
+VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw
+NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU
+cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg
+Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821
++iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw
+Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo
+aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy
+2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7
+7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P
+BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL
+VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk
+VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB
+IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl
+j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355
+e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u
+G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----
+
+AddTrust Public Services Root
+=============================
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU
+cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ
+BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l
+dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu
+nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i
+d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG
+Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw
+HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G
+A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux
+FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G
+A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4
+JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL
++YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao
+GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9
+Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H
+EufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
+-----END CERTIFICATE-----
+
+AddTrust Qualified Certificates Root
+====================================
+-----BEGIN CERTIFICATE-----
+MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU
+cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx
+CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ
+IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx
+64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3
+KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o
+L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR
+wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU
+MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE
+BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y
+azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD
+ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG
+GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X
+dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze
+RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB
+iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE=
+-----END CERTIFICATE-----
+
+Entrust Root Certification Authority
+====================================
+-----BEGIN CERTIFICATE-----
+MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV
+BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw
+b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG
+A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0
+MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu
+MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu
+Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v
+dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz
+A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww
+Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68
+j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN
+rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw
+DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1
+MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH
+hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
+A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM
+Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa
+v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS
+W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
+tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
+-----END CERTIFICATE-----
+
+RSA Security 2048 v3
+====================
+-----BEGIN CERTIFICATE-----
+MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK
+ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy
+MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb
+BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7
+Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb
+WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH
+KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP
++Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/
+MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E
+FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY
+v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj
+0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj
+VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395
+nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA
+pKnXwiJPZ9d37CAFYd4=
+-----END CERTIFICATE-----
+
+GeoTrust Global CA
+==================
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
+Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw
+MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j
+LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo
+BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet
+8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc
+T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU
+vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk
+DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q
+zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4
+d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2
+mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p
+XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm
+Mw==
+-----END CERTIFICATE-----
+
+GeoTrust Global CA 2
+====================
+-----BEGIN CERTIFICATE-----
+MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
+R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw
+MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j
+LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/
+NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k
+LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA
+Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b
+HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH
+K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7
+srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh
+ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL
+OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC
+x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF
+H4z1Ir+rzoPz4iIprn2DQKi6bA==
+-----END CERTIFICATE-----
+
+GeoTrust Universal CA
+=====================
+-----BEGIN CERTIFICATE-----
+MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
+R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1
+MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu
+Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t
+JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e
+RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs
+7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d
+8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V
+qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga
+Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB
+Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu
+KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08
+ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0
+XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB
+hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
+aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2
+qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL
+oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK
+xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF
+KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2
+DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK
+xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU
+p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI
+P/rmMuGNG2+k5o7Y+SlIis5z/iw=
+-----END CERTIFICATE-----
+
+GeoTrust Universal CA 2
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
+R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0
+MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg
+SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0
+DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17
+j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q
+JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a
+QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2
+WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP
+20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn
+ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC
+SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG
+8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2
++/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E
+BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
+dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ
+4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+
+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq
+A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg
+Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP
+pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d
+FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp
+gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm
+X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
+-----END CERTIFICATE-----
+
+UTN-USER First-Network Applications
+===================================
+-----BEGIN CERTIFICATE-----
+MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCBozELMAkGA1UE
+BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
+IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzAp
+BgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5
+WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5T
+YWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBB
+cHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZVhawGNFug
+mliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4Cj
+DUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXu
+Ozr0hAReYFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwi
+P8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7igEL66S/ozjIE
+j3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8w
+HQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9j
+cmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G
+CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y
+IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6LzsQCv4AdRWOOTK
+RIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4Qp
+xFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAq
+DbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjisH8SE
+-----END CERTIFICATE-----
+
+America Online Root Certification Authority 1
+=============================================
+-----BEGIN CERTIFICATE-----
+MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
+QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG
+A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg
+T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG
+v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z
+DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh
+sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP
+8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T
+AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z
+o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf
+GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF
+VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft
+3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g
+Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds
+sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
+-----END CERTIFICATE-----
+
+America Online Root Certification Authority 2
+=============================================
+-----BEGIN CERTIFICATE-----
+MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
+QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkG
+A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg
+T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC206B89en
+fHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8
+f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE18aO6lhO
+qKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JN
+RvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0
+gBe4lL8BPeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn
+6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897Gqid
+FEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6
+Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnj
+B453cMor9H124HhnAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op
+aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE
+AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FY
+T15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p
++DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXg
+JXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//Zoy
+zH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgO
+ZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh
+1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZZLF0Kjhf
+GEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y3WRayhgoPmMEEf0cjQAPuDff
+Z4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuP
+cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk=
+-----END CERTIFICATE-----
+
+Visa eCommerce Root
+===================
+-----BEGIN CERTIFICATE-----
+MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG
+EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug
+QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2
+WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm
+VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv
+bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL
+F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b
+RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0
+TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI
+/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs
+GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG
+MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc
+CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW
+YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz
+zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu
+YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt
+398znM/jra6O1I7mT1GvFpLgXPYHDw==
+-----END CERTIFICATE-----
+
+Certum Root CA
+==============
+-----BEGIN CERTIFICATE-----
+MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK
+ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla
+Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u
+by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x
+wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL
+kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ
+89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K
+Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P
+NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq
+hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+
+GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg
+GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/
+0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS
+qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw==
+-----END CERTIFICATE-----
+
+Comodo AAA Services root
+========================
+-----BEGIN CERTIFICATE-----
+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
+TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw
+MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl
+c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
+BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG
+C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs
+i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW
+Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH
+Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK
+Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f
+BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl
+cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz
+LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm
+7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z
+8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C
+12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+-----END CERTIFICATE-----
+
+Comodo Secure Services root
+===========================
+-----BEGIN CERTIFICATE-----
+MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
+TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw
+MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu
+Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi
+BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP
+9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc
+rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC
+oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V
+p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E
+FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
+gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj
+YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm
+aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm
+4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
+Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL
+DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw
+pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H
+RR3B7Hzs/Sk=
+-----END CERTIFICATE-----
+
+Comodo Trusted Services root
+============================
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
+TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw
+MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h
+bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw
+IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7
+3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y
+/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6
+juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS
+ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud
+DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp
+ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl
+cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw
+uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
+pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA
+BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l
+R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O
+9y5Xt5hwXsjEeLBi
+-----END CERTIFICATE-----
+
+QuoVadis Root CA
+================
+-----BEGIN CERTIFICATE-----
+MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE
+ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz
+MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp
+cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD
+EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk
+J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL
+F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL
+YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen
+AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w
+PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y
+ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7
+MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj
+YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs
+ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
+Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW
+Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu
+BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw
+FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6
+tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo
+fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul
+LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x
+gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi
+5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi
+5nrQNiOKSnQ2+Q==
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 2
+==================
+-----BEGIN CERTIFICATE-----
+MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
+EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx
+ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
+aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6
+XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk
+lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB
+lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy
+lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt
+66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn
+wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh
+D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy
+BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie
+J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud
+DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU
+a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
+ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv
+Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3
+UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm
+VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK
++JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW
+IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1
+WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X
+f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II
+4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8
+VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 3
+==================
+-----BEGIN CERTIFICATE-----
+MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
+EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx
+OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
+aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg
+DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij
+KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K
+DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv
+BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp
+p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8
+nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX
+MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM
+Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz
+uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT
+BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj
+YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
+aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB
+BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD
+VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4
+ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE
+AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV
+qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s
+hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z
+POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2
+Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp
+8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC
+bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu
+g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p
+vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr
+qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=
+-----END CERTIFICATE-----
+
+Security Communication Root CA
+==============================
+-----BEGIN CERTIFICATE-----
+MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
+U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
+HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
+U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw
+8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM
+DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX
+5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd
+DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2
+JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw
+DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g
+0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a
+mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ
+s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ
+6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi
+FL39vmwLAw==
+-----END CERTIFICATE-----
+
+Sonera Class 1 Root CA
+======================
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG
+U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAxMDQwNjEwNDkxM1oXDTIxMDQw
+NjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh
+IENsYXNzMSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H88
+7dF+2rDNbS82rDTG29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9
+EJUkoVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk3w0LBUXl
+0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBLqdReLjVQCfOAl/QMF645
+2F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIINnvmLVz5MxxftLItyM19yejhW1ebZrgUa
+HXVFsculJRwSVzb9IjcCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZT
+iFIwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE9
+28Jj2VuXZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0HDjxV
+yhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VOTzF2nBBhjrZTOqMR
+vq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2UvkVrCqIexVmiUefkl98HVrhq4uz2P
+qYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4wzMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9Z
+IRlXvVWa
+-----END CERTIFICATE-----
+
+Sonera Class 2 Root CA
+======================
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG
+U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw
+NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh
+IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3
+/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT
+dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG
+f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P
+tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH
+nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT
+XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt
+0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI
+cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph
+Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx
+EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH
+llpwrN9M
+-----END CERTIFICATE-----
+
+Staat der Nederlanden Root CA
+=============================
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE
+ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g
+Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w
+HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh
+bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt
+vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P
+jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca
+C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth
+vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6
+22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV
+HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v
+dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN
+BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR
+EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw
+MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y
+nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR
+iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==
+-----END CERTIFICATE-----
+
+TDC Internet Root CA
+====================
+-----BEGIN CERTIFICATE-----
+MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMGA1UE
+ChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUx
+NjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJu
+ZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20j
+xsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvL
+znWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc
+5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6
+otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZI
+AYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMM
+VERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JM
+MTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMC
+AQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqe
+UAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0G
+CSqGSIb3DQEBBQUAA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m
+gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+
+2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzb
+O0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU
+Cbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l
+-----END CERTIFICATE-----
+
+TDC OCES Root CA
+================
+-----BEGIN CERTIFICATE-----
+MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJESzEMMAoGA1UE
+ChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEwODM5MzBaFw0zNzAyMTEwOTA5
+MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNUREMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuH
+nEz9pPPEXyG9VhDr2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0
+zY0s2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItUGBxIYXvV
+iGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKjdGqPqcNiKXEx5TukYBde
+dObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+rTpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO
+3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB
+5DCB4TCB3gYIKoFQgSkBAQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5k
+ay9yZXBvc2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRlciBm
+cmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4xLiBDZXJ0aWZp
+Y2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4x
+LjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1UdHwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEM
+MAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYm
+aHR0cDovL2NybC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy
+MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZJ2cdUBVLc647
++RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6
+NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACromJkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4
+A9G28kNBKWKnctj7fAXmMXAnVBhOinxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYsc
+A+UYyAFMP8uXBV2YcaaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9
+AOoBmbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQYqbsFbS1
+AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9BKNDLdr8C2LqL19iUw==
+-----END CERTIFICATE-----
+
+UTN DATACorp SGC Root CA
+========================
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE
+BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
+IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ
+BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa
+MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w
+HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy
+dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys
+raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo
+wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA
+9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv
+33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud
+DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9
+BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD
+LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3
+DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0
+I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx
+EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP
+DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI
+-----END CERTIFICATE-----
+
+UTN USERFirst Email Root CA
+===========================
+-----BEGIN CERTIFICATE-----
+MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UE
+BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
+IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0
+BgNVBAMTLVVUTi1VU0VSRmlyc3QtQ2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05
+OTA3MDkxNzI4NTBaFw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQx
+FzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsx
+ITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UEAxMtVVROLVVTRVJGaXJz
+dC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWlsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3BYHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIx
+B8dOtINknS4p1aJkxIW9hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8
+om+rWV6lL8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLmSGHG
+TPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM1tZUOt4KpLoDd7Nl
+yP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws6wIDAQABo4G5MIG2MAsGA1UdDwQE
+AwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNV
+HR8EUTBPME2gS6BJhkdodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGll
+bnRBdXRoZW50aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH
+AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u7mFVbwQ+zzne
+xRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0xtcgBEXkzYABurorbs6q15L+
+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQrfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarV
+NZ1yQAOJujEdxRBoUp7fooXFXAimeOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZ
+w7JHpsIyYdfHb0gkUSeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ=
+-----END CERTIFICATE-----
+
+UTN USERFirst Hardware Root CA
+==============================
+-----BEGIN CERTIFICATE-----
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE
+BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
+IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd
+BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx
+OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0
+eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz
+ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI
+wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd
+tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8
+i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf
+Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw
+gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF
+lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF
+UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF
+BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW
+XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2
+lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn
+iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67
+nfhmqA==
+-----END CERTIFICATE-----
+
+UTN USERFirst Object Root CA
+============================
+-----BEGIN CERTIFICATE-----
+MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UE
+BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
+IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAb
+BgNVBAMTFFVUTi1VU0VSRmlyc3QtT2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAz
+NlowgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkx
+HjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3dy51c2Vy
+dHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicPHxzfOpuCaDDASmEd8S8O+r5596Uj71VR
+loTN2+O5bj4x2AogZ8f02b+U60cEPgLOKqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQ
+w5ujm9M89RKZd7G3CeBo5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vu
+lBe3/IW+pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehbkkj7
+RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUCAwEAAaOBrzCBrDAL
+BgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU2u1kdBScFDyr3ZmpvVsoTYs8
+ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmly
+c3QtT2JqZWN0LmNybDApBgNVHSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQw
+DQYJKoZIhvcNAQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw
+NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXBmMiKVl0+7kNO
+PmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU4U3GDZlDAQ0Slox4nb9QorFE
+qmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK581OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCG
+hU3IfdeLA/5u1fedFqySLKAj5ZyRUh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g=
+-----END CERTIFICATE-----
+
+Camerfirma Chambers of Commerce Root
+====================================
+-----BEGIN CERTIFICATE-----
+MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe
+QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i
+ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx
+NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp
+cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn
+MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC
+AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU
+xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH
+NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW
+DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV
+d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud
+EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v
+cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P
+AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh
+bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD
+VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz
+aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi
+fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD
+L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN
+UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n
+ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1
+erfutGWaIZDgqtCYvDi1czyL+Nw=
+-----END CERTIFICATE-----
+
+Camerfirma Global Chambersign Root
+==================================
+-----BEGIN CERTIFICATE-----
+MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe
+QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i
+ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx
+NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt
+YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg
+MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw
+ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J
+1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O
+by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl
+6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c
+8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/
+BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j
+aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B
+Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj
+aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y
+ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh
+bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA
+PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y
+gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ
+PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4
+IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes
+t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==
+-----END CERTIFICATE-----
+
+NetLock Qualified (Class QA) Root
+=================================
+-----BEGIN CERTIFICATE-----
+MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUxETAPBgNVBAcT
+CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV
+BAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQDEzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVn
+eXpvaSAoQ2xhc3MgUUEpIFRhbnVzaXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0
+bG9jay5odTAeFw0wMzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTER
+MA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNhZ2kgS2Z0
+LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5ldExvY2sgTWlub3NpdGV0
+dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZhbnlraWFkbzEeMBwGCSqGSIb3DQEJARYP
+aW5mb0BuZXRsb2NrLmh1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRV
+CacbvWy5FPSKAtt2/GoqeKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e
+8ia6AFQer7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO53Lhb
+m+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWdvLrqOU+L73Sa58XQ
+0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0lmT+1fMptsK6ZmfoIYOcZwvK9UdPM
+0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4ICwDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV
+HQ8BAf8EBAMCAQYwggJ1BglghkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2
+YW55IGEgTmV0TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh
+biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQgZWxla3Ryb25p
+a3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywgdmFsYW1pbnQgZWxmb2dhZGFz
+YW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwg
+YXogQWx0YWxhbm9zIFN6ZXJ6b2Rlc2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kg
+ZWxqYXJhcyBtZWd0ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczov
+L3d3dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0BuZXRsb2Nr
+Lm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0
+aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMg
+YXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0
+IGluZm9AbmV0bG9jay5uZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3
+DQEBBQUAA4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQMznN
+wNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+NFAwLvt/MpqNPfMg
+W/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCRVCHnpgu0mfVRQdzNo0ci2ccBgcTc
+R08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR
+5qq5aKrN9p2QdRLqOBrKROi3macqaJVmlaut74nLYKkGEsaUR+ko
+-----END CERTIFICATE-----
+
+NetLock Notary (Class A) Root
+=============================
+-----BEGIN CERTIFICATE-----
+MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI
+EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6
+dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j
+ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX
+DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH
+EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD
+VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz
+cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM
+D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ
+z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC
+/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7
+tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6
+4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG
+A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC
+Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv
+bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu
+IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn
+LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0
+ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz
+IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh
+IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu
+b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh
+bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg
+Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp
+bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5
+ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP
+ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB
+CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr
+KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM
+8CgHrTwXZoi1/baI
+-----END CERTIFICATE-----
+
+NetLock Business (Class B) Root
+===============================
+-----BEGIN CERTIFICATE-----
+MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcT
+CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV
+BAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikg
+VGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYD
+VQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRv
+bnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sg
+VXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
+iQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2S
+o/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr
+1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV
+HQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZ
+RUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRh
+dGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0
+ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRv
+c2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg
+YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh
+c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBz
+Oi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA
+bmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl
+IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2
+YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBj
+cHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM
+43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKR
+stE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI
+-----END CERTIFICATE-----
+
+NetLock Express (Class C) Root
+==============================
+-----BEGIN CERTIFICATE-----
+MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcT
+CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV
+BAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBD
+KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJ
+BgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6
+dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9j
+ayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOB
+jQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3Z
+W3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63
+euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQw
+DgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJN
+RklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xn
+YWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBB
+IGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1i
+aXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0
+ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs
+ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBo
+dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y
+emVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5k
+IHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQ
+UyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwg
+YXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2
+xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOW
+gyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A==
+-----END CERTIFICATE-----
+
+XRamp Global CA Root
+====================
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE
+BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj
+dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx
+HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg
+U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu
+IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx
+foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE
+zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs
+AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry
+xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap
+oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC
+AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc
+/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
+qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n
+nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz
+8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=
+-----END CERTIFICATE-----
+
+Go Daddy Class 2 CA
+===================
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY
+VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG
+A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
+RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD
+ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
+2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32
+qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j
+YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY
+vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O
+BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o
+atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu
+MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim
+PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt
+I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI
+Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b
+vZ8=
+-----END CERTIFICATE-----
+
+Starfield Class 2 CA
+====================
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc
+U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo
+MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG
+A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG
+SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY
+bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ
+JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm
+epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN
+F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF
+MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f
+hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo
+bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g
+QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs
+afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM
+PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD
+KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3
+QBFGmh95DmK/D5fs4C8fF5Q=
+-----END CERTIFICATE-----
+
+StartCom Certification Authority
+================================
+-----BEGIN CERTIFICATE-----
+MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
+U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu
+ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0
+NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk
+LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg
+U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
+ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y
+o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/
+Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d
+eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt
+2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z
+6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ
+osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/
+untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc
+UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT
+37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
+FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0
+Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj
+YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH
+AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw
+Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg
+U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5
+LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh
+cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT
+dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC
+AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh
+3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm
+vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk
+fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3
+fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ
+EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
+yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl
+1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/
+lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro
+g14=
+-----END CERTIFICATE-----
+
+Taiwan GRCA
+===========
+-----BEGIN CERTIFICATE-----
+MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG
+EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X
+DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv
+dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN
+w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5
+BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O
+1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO
+htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov
+J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7
+Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t
+B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB
+O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8
+lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV
+HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2
+09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ
+TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj
+Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2
+Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU
+D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz
+DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk
+Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk
+7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ
+CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy
++fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS
+-----END CERTIFICATE-----
+
+Firmaprofesional Root CA
+========================
+-----BEGIN CERTIFICATE-----
+MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMxIjAgBgNVBAcT
+GUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1dG9yaWRhZCBkZSBDZXJ0aWZp
+Y2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FA
+ZmlybWFwcm9mZXNpb25hbC5jb20wHhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTEL
+MAkGA1UEBhMCRVMxIjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMT
+OUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2
+ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20wggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5uCp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5V
+j1H5WuretXDE7aTt/6MNbg9kUDGvASdYrv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJH
+lShbz++AbOCQl4oBPB3zhxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf
+3H5idPayBQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcLiam8
+NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcbAgMBAAGjgZ8wgZww
+KgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lvbmFsLmNvbTASBgNVHRMBAf8ECDAG
+AQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1Ud
+DwEB/wQEAwIBBjAdBgNVHQ4EFgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQAD
+ggEBAEdz/o0nVPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq
+u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36mhoEyIwOdyPdf
+wUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzflZKG+TQyTmAyX9odtsz/ny4Cm
+7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBpQWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YG
+VM+h4k0460tQtcsm9MracEpqoeJ5quGnM/b9Sh/22WA=
+-----END CERTIFICATE-----
+
+Wells Fargo Root CA
+===================
+-----BEGIN CERTIFICATE-----
+MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMCVVMxFDASBgNV
+BAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhv
+cml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN
+MDAxMDExMTY0MTI4WhcNMjEwMTE0MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dl
+bGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEv
+MC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n135zHCLielTWi5MbqNQ1mX
+x3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHESxP9cMIlrCL1dQu3U+SlK93OvRw6esP3
+E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4OJgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5
+OEL8pahbSCOz6+MlsoCultQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4j
+sNtlAHCEAQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMBAAGj
+YTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcBCzAyMDAGCCsGAQUF
+BwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRwb2xpY3kwDQYJKoZIhvcNAQEFBQAD
+ggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrv
+m+0fazbuSCUlFLZWohDo7qd/0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0R
+OhPs7fpvcmR7nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx
+x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ33ZwmVxwQ023
+tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s=
+-----END CERTIFICATE-----
+
+Swisscom Root CA 1
+==================
+-----BEGIN CERTIFICATE-----
+MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG
+EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy
+dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4
+MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln
+aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC
+IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM
+MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF
+NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe
+AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC
+b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn
+7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN
+cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp
+WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5
+haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY
+MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw
+HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j
+BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9
+MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn
+jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ
+MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H
+VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl
+vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl
+OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3
+1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq
+nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy
+x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW
+NY6E0F/6MBr1mmz0DlP5OlvRHA==
+-----END CERTIFICATE-----
+
+DigiCert Assured ID Root CA
+===========================
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
+IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx
+MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
+ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO
+9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy
+UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW
+/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy
+oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf
+GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF
+66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq
+hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc
+EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn
+SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i
+8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
+-----END CERTIFICATE-----
+
+DigiCert Global Root CA
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
+HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw
+MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
+dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn
+TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5
+BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H
+4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y
+7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB
+o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm
+8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF
+BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr
+EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt
+tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886
+UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----
+
+DigiCert High Assurance EV Root CA
+==================================
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw
+KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw
+MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
+MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu
+Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t
+Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS
+OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3
+MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ
+NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe
+h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB
+Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY
+JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ
+V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp
+myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK
+mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
+-----END CERTIFICATE-----
+
+Certplus Class 2 Primary CA
+===========================
+-----BEGIN CERTIFICATE-----
+MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE
+BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN
+OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy
+dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR
+5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ
+Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO
+YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e
+e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME
+CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ
+YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t
+L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD
+P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R
+TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+
+7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW
+//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
+l7+ijrRU
+-----END CERTIFICATE-----
+
+DST Root CA X3
+==============
+-----BEGIN CERTIFICATE-----
+MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK
+ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X
+DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1
+cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT
+rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9
+UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy
+xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d
+utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T
+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ
+MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug
+dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE
+GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw
+RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS
+fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
+-----END CERTIFICATE-----
+
+DST ACES CA X6
+==============
+-----BEGIN CERTIFICATE-----
+MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG
+EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT
+MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha
+MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE
+CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI
+DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa
+pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow
+GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy
+MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu
+Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy
+dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU
+CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2
+5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t
+Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq
+nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs
+vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3
+oKfN5XozNmr6mis=
+-----END CERTIFICATE-----
+
+TURKTRUST Certificate Services Provider Root 1
+==============================================
+-----BEGIN CERTIFICATE-----
+MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP
+MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0
+acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx
+MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg
+U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB
+TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC
+aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX
+yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i
+Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ
+8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4
+W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME
+BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46
+sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE
+q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy
+B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY
+nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H
+-----END CERTIFICATE-----
+
+TURKTRUST Certificate Services Provider Root 2
+==============================================
+-----BEGIN CERTIFICATE-----
+MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP
+MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg
+QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN
+MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr
+dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G
+A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls
+acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe
+LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI
+x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g
+QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr
+5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB
+AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G
+A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt
+Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4
+Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+
+hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P
+9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5
+UrbnBEI=
+-----END CERTIFICATE-----
+
+SwissSign Platinum CA - G2
+==========================
+-----BEGIN CERTIFICATE-----
+MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UEBhMCQ0gxFTAT
+BgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWduIFBsYXRpbnVtIENBIC0gRzIw
+HhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAwWjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMM
+U3dpc3NTaWduIEFHMSMwIQYDVQQDExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJ
+KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu
+669yIIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2HtnIuJpX+UF
+eNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+6ixuEFGSzH7VozPY1kne
+WCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5objM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIo
+j5+saCB9bzuohTEJfwvH6GXp43gOCWcwizSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/6
+8++QHkwFix7qepF6w9fl+zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34T
+aNhxKFrYzt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaPpZjy
+domyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtFKwH3HBqi7Ri6Cr2D
++m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuWae5ogObnmLo2t/5u7Su9IPhlGdpV
+CX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMBAAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCv
+zAeHFUdvOMW0ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW
+IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUAA4ICAQAIhab1
+Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0uMoI3LQwnkAHFmtllXcBrqS3
+NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4
+U99REJNi54Av4tHgvI42Rncz7Lj7jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8
+KV2LwUvJ4ooTHbG/u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl
+9x8DYSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1puEa+S1B
+aYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXaicYwu+uPyyIIoK6q8QNs
+OktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbGDI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSY
+Mdp08YSTcU1f+2BY0fvEwW2JorsgH51xkcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAci
+IfNAChs0B0QTwoRqjt8ZWr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g==
+-----END CERTIFICATE-----
+
+SwissSign Gold CA - G2
+======================
+-----BEGIN CERTIFICATE-----
+MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw
+EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN
+MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp
+c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq
+t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C
+jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg
+vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF
+ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR
+AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend
+jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO
+peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR
+7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi
+GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64
+OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov
+L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm
+5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr
+44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf
+Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m
+Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp
+mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk
+vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf
+KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br
+NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj
+viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
+-----END CERTIFICATE-----
+
+SwissSign Silver CA - G2
+========================
+-----BEGIN CERTIFICATE-----
+MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT
+BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X
+DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3
+aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG
+9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644
+N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm
++/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH
+6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu
+MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h
+qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5
+FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs
+ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc
+celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X
+CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB
+tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0
+cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P
+4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F
+kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L
+3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx
+/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa
+DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP
+e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu
+WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ
+DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub
+DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
+-----END CERTIFICATE-----
+
+GeoTrust Primary Certification Authority
+========================================
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx
+CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ
+cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN
+b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9
+nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge
+RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt
+tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI
+hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K
+Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN
+NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa
+Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG
+1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
+-----END CERTIFICATE-----
+
+thawte Primary Root CA
+======================
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE
+BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
+aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3
+MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg
+SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv
+KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT
+FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs
+oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ
+1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc
+q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K
+aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p
+afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
+VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF
+AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE
+uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
+xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89
+jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH
+z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA==
+-----END CERTIFICATE-----
+
+VeriSign Class 3 Public Primary Certification Authority - G5
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
+BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
+ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
+IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB
+yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln
+biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh
+dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz
+j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD
+Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/
+Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r
+fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/
+BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv
+Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
+aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
+SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+
+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE
+KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC
+Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE
+ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
+-----END CERTIFICATE-----
+
+SecureTrust CA
+==============
+-----BEGIN CERTIFICATE-----
+MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG
+EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy
+dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe
+BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX
+OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t
+DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH
+GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b
+01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH
+ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj
+aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
+KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu
+SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf
+mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ
+nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
+3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
+-----END CERTIFICATE-----
+
+Secure Global CA
+================
+-----BEGIN CERTIFICATE-----
+MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG
+EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH
+bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg
+MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg
+Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx
+YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ
+bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g
+8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV
+HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi
+0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn
+oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA
+MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+
+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn
+CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5
+3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
+f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
+-----END CERTIFICATE-----
+
+COMODO Certification Authority
+==============================
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE
+BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
+A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1
+dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb
+MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD
+T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH
++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww
+xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV
+4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA
+1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI
+rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k
+b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC
+AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP
+OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
+RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc
+IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN
++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==
+-----END CERTIFICATE-----
+
+Network Solutions Certificate Authority
+=======================================
+-----BEGIN CERTIFICATE-----
+MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG
+EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr
+IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx
+MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
+MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx
+jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT
+aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT
+crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc
+/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB
+AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv
+bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA
+A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q
+4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/
+GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
+wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD
+ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
+-----END CERTIFICATE-----
+
+WellsSecure Public Root Certificate Authority
+=============================================
+-----BEGIN CERTIFICATE-----
+MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM
+F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw
+NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN
+MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl
+bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD
+VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1
+iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13
+i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8
+bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB
+K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB
+AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu
+cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm
+lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB
+i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww
+GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg
+Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI
+K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0
+bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj
+qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es
+E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ
+tylv2G0xffX8oRAHh84vWdw+WNs=
+-----END CERTIFICATE-----
+
+COMODO ECC Certification Authority
+==================================
+-----BEGIN CERTIFICATE-----
+MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC
+R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
+ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix
+GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
+Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo
+b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X
+4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni
+wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG
+FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA
+U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
+-----END CERTIFICATE-----
+
+IGC/A
+=====
+-----BEGIN CERTIFICATE-----
+MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD
+VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE
+Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy
+MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI
+EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT
+STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2
+TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW
+So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy
+HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd
+frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ
+tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB
+egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC
+iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK
+q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q
+MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg
+Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI
+lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF
+0mBWWg==
+-----END CERTIFICATE-----
+
+Security Communication EV RootCA1
+=================================
+-----BEGIN CERTIFICATE-----
+MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
+U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh
+dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE
+BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl
+Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO
+/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX
+WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z
+ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4
+bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK
+9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
+SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm
+iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG
+Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW
+mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW
+T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490
+-----END CERTIFICATE-----
+
+OISTE WISeKey Global Root GA CA
+===============================
+-----BEGIN CERTIFICATE-----
+MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE
+BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG
+A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH
+bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD
+VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw
+IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5
+IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9
+Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg
+Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD
+d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ
+/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R
+LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
+KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm
+MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4
++vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa
+hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY
+okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0=
+-----END CERTIFICATE-----
+
+S-TRUST Authentication and Encryption Root CA 2005 PN
+=====================================================
+-----BEGIN CERTIFICATE-----
+MIIEezCCA2OgAwIBAgIQNxkY5lNUfBq1uMtZWts1tzANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UE
+BhMCREUxIDAeBgNVBAgTF0JhZGVuLVd1ZXJ0dGVtYmVyZyAoQlcpMRIwEAYDVQQHEwlTdHV0dGdh
+cnQxKTAnBgNVBAoTIERldXRzY2hlciBTcGFya2Fzc2VuIFZlcmxhZyBHbWJIMT4wPAYDVQQDEzVT
+LVRSVVNUIEF1dGhlbnRpY2F0aW9uIGFuZCBFbmNyeXB0aW9uIFJvb3QgQ0EgMjAwNTpQTjAeFw0w
+NTA2MjIwMDAwMDBaFw0zMDA2MjEyMzU5NTlaMIGuMQswCQYDVQQGEwJERTEgMB4GA1UECBMXQmFk
+ZW4tV3VlcnR0ZW1iZXJnIChCVykxEjAQBgNVBAcTCVN0dXR0Z2FydDEpMCcGA1UEChMgRGV1dHNj
+aGVyIFNwYXJrYXNzZW4gVmVybGFnIEdtYkgxPjA8BgNVBAMTNVMtVFJVU1QgQXV0aGVudGljYXRp
+b24gYW5kIEVuY3J5cHRpb24gUm9vdCBDQSAyMDA1OlBOMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEA2bVKwdMz6tNGs9HiTNL1toPQb9UY6ZOvJ44TzbUlNlA0EmQpoVXhOmCTnijJ4/Ob
+4QSwI7+Vio5bG0F/WsPoTUzVJBY+h0jUJ67m91MduwwA7z5hca2/OnpYH5Q9XIHV1W/fuJvS9eXL
+g3KSwlOyggLrra1fFi2SU3bxibYs9cEv4KdKb6AwajLrmnQDaHgTncovmwsdvs91DSaXm8f1Xgqf
+eN+zvOyauu9VjxuapgdjKRdZYgkqeQd3peDRF2npW932kKvimAoA0SVtnteFhy+S8dF2g08LOlk3
+KC8zpxdQ1iALCvQm+Z845y2kuJuJja2tyWp9iRe79n+Ag3rm7QIDAQABo4GSMIGPMBIGA1UdEwEB
+/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFTVFJv
+bmxpbmUxLTIwNDgtNTAdBgNVHQ4EFgQUD8oeXHngovMpttKFswtKtWXsa1IwHwYDVR0jBBgwFoAU
+D8oeXHngovMpttKFswtKtWXsa1IwDQYJKoZIhvcNAQEFBQADggEBAK8B8O0ZPCjoTVy7pWMciDMD
+pwCHpB8gq9Yc4wYfl35UvbfRssnV2oDsF9eK9XvCAPbpEW+EoFolMeKJ+aQAPzFoLtU96G7m1R08
+P7K9n3frndOMusDXtk3sU5wPBG7qNWdX4wple5A64U8+wwCSersFiXOMy6ZNwPv2AtawB6MDwidA
+nwzkhYItr5pCHdDHjfhA7p0GVxzZotiAFP7hYy0yh9WUUpY6RsZxlj33mA6ykaqP2vROJAA5Veit
+F7nTNCtKqUDMFypVZUF0Qn71wK/Ik63yGFs9iQzbRzkk+OBM8h+wPQrKBU6JIRrjKpms/H+h8Q8b
+Hz2eBIPdltkdOpQ=
+-----END CERTIFICATE-----
+
+Microsec e-Szigno Root CA
+=========================
+-----BEGIN CERTIFICATE-----
+MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE
+BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL
+EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0
+MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz
+dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT
+GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG
+d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N
+oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc
+QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ
+PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb
+MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG
+IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD
+VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3
+LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A
+dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn
+AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA
+4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg
+AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA
+egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6
+Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO
+PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv
+c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h
+cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw
+IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT
+WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV
+MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER
+MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp
+Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal
+HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT
+nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE
+aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a
+86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK
+yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB
+S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU=
+-----END CERTIFICATE-----
+
+Certigna
+========
+-----BEGIN CERTIFICATE-----
+MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw
+EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3
+MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI
+Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q
+XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH
+GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p
+ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg
+DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf
+Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ
+tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ
+BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J
+SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA
+hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+
+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu
+PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY
+1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
+WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
+-----END CERTIFICATE-----
+
+AC Ra\xC3\xADz Certic\xC3\xA1mara S.A.
+======================================
+-----BEGIN CERTIFICATE-----
+MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNVBAYT
+AkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERpZ2l0YWwg
+LSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4w
+HhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+
+U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJh
+IFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeGqentLhM0R7LQcNzJPNCN
+yu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU
+2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU3
+4ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP
+2yYe68yQ54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm
+8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhf
+HjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCa
+Mh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK
+5lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1b
+czwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0g
+ADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEF
+BQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2Ug
+cHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEf
+AygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuX
+EpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v
+/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3
+MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR4
+3NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wk
+eZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f
+/RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5h
+RqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecU
+Iw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ==
+-----END CERTIFICATE-----
+
+TC TrustCenter Class 2 CA II
+============================
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC
+REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy
+IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw
+MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1
+c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE
+AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw
+IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2
+xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ
+Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u
+SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB
+7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90
+Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU
+cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i
+SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
+TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G
+dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ
+KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj
+TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP
+JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk
+vQ==
+-----END CERTIFICATE-----
+
+TC TrustCenter Class 3 CA II
+============================
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC
+REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy
+IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw
+MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1
+c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE
+AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W
+yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo
+6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ
+uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk
+2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB
+7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90
+Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU
+cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i
+SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
+TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE
+O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8
+yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9
+IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal
+092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc
+5A==
+-----END CERTIFICATE-----
+
+TC TrustCenter Universal CA I
+=============================
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC
+REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy
+IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN
+MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg
+VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw
+JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC
+qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv
+xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw
+ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O
+gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j
+BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG
+1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy
+vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3
+ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT
+ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a
+7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY
+-----END CERTIFICATE-----
+
+Deutsche Telekom Root CA 2
+==========================
+-----BEGIN CERTIFICATE-----
+MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT
+RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG
+A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5
+MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G
+A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS
+b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5
+bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI
+KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY
+AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK
+Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV
+jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV
+HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr
+E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy
+zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8
+rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G
+dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
+Cm26OWMohpLzGITY+9HPBVZkVw==
+-----END CERTIFICATE-----
+
+ComSign CA
+==========
+-----BEGIN CERTIFICATE-----
+MIIDkzCCAnugAwIBAgIQFBOWgxRVjOp7Y+X8NId3RDANBgkqhkiG9w0BAQUFADA0MRMwEQYDVQQD
+EwpDb21TaWduIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTMy
+MThaFw0yOTAzMTkxNTAyMThaMDQxEzARBgNVBAMTCkNvbVNpZ24gQ0ExEDAOBgNVBAoTB0NvbVNp
+Z24xCzAJBgNVBAYTAklMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ORUaSvTx49q
+ROR+WCf4C9DklBKK8Rs4OC8fMZwG1Cyn3gsqrhqg455qv588x26i+YtkbDqthVVRVKU4VbirgwTy
+P2Q298CNQ0NqZtH3FyrV7zb6MBBC11PN+fozc0yz6YQgitZBJzXkOPqUm7h65HkfM/sb2CEJKHxN
+GGleZIp6GZPKfuzzcuc3B1hZKKxC+cX/zT/npfo4sdAMx9lSGlPWgcxCejVb7Us6eva1jsz/D3zk
+YDaHL63woSV9/9JLEYhwVKZBqGdTUkJe5DSe5L6j7KpiXd3DTKaCQeQzC6zJMw9kglcq/QytNuEM
+rkvF7zuZ2SOzW120V+x0cAwqTwIDAQABo4GgMIGdMAwGA1UdEwQFMAMBAf8wPQYDVR0fBDYwNDAy
+oDCgLoYsaHR0cDovL2ZlZGlyLmNvbXNpZ24uY28uaWwvY3JsL0NvbVNpZ25DQS5jcmwwDgYDVR0P
+AQH/BAQDAgGGMB8GA1UdIwQYMBaAFEsBmz5WGmU2dst7l6qSBe4y5ygxMB0GA1UdDgQWBBRLAZs+
+VhplNnbLe5eqkgXuMucoMTANBgkqhkiG9w0BAQUFAAOCAQEA0Nmlfv4pYEWdfoPPbrxHbvUanlR2
+QnG0PFg/LUAlQvaBnPGJEMgOqnhPOAlXsDzACPw1jvFIUY0McXS6hMTXcpuEfDhOZAYnKuGntewI
+mbQKDdSFc8gS4TXt8QUxHXOZDOuWyt3T5oWq8Ir7dcHyCTxlZWTzTNity4hp8+SDtwy9F1qWF8pb
+/627HOkthIDYIb6FUtnUdLlphbpN7Sgy6/lhSuTENh4Z3G+EER+V9YMoGKgzkkMn3V0TBEVPh9VG
+zT2ouvDzuFYkRes3x+F2T3I5GN9+dHLHcy056mDmrRGiVod7w2ia/viMcKjfZTL0pECMocJEAw6U
+AGegcQCCSA==
+-----END CERTIFICATE-----
+
+ComSign Secured CA
+==================
+-----BEGIN CERTIFICATE-----
+MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE
+AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w
+NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD
+QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs
+49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH
+7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB
+kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1
+9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw
+AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t
+U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA
+j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC
+AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a
+BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp
+FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP
+51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz
+OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw==
+-----END CERTIFICATE-----
+
+Cybertrust Global Root
+======================
+-----BEGIN CERTIFICATE-----
+MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li
+ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4
+MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD
+ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW
+0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL
+AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin
+89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT
+8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2
+MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G
+A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO
+lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi
+5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2
+hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T
+X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW
+WL1WMRJOEcgh4LMRkWXbtKaIOM5V
+-----END CERTIFICATE-----
+
+ePKI Root Certification Authority
+=================================
+-----BEGIN CERTIFICATE-----
+MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG
+EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg
+Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx
+MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq
+MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs
+IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi
+lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv
+qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX
+12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O
+WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+
+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao
+lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/
+vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi
+Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi
+MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
+ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0
+1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq
+KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV
+xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP
+NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r
+GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE
+xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx
+gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy
+sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD
+BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw=
+-----END CERTIFICATE-----
+
+T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3
+=============================================================================================================================
+-----BEGIN CERTIFICATE-----
+MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH
+DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q
+aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry
+b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV
+BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg
+S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4
+MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl
+IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF
+n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl
+IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft
+dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl
+cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO
+Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1
+xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR
+6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL
+hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd
+BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4
+N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT
+y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh
+LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M
+dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI=
+-----END CERTIFICATE-----
+
+Buypass Class 2 CA 1
+====================
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2
+MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh
+c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M
+cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83
+0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4
+0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R
+uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P
+AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV
+1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt
+7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2
+fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w
+wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho
+-----END CERTIFICATE-----
+
+Buypass Class 3 CA 1
+====================
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1
+MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh
+c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx
+ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0
+n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia
+AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c
+1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P
+AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7
+pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA
+EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5
+htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj
+el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915
+-----END CERTIFICATE-----
+
+EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1
+==========================================================================
+-----BEGIN CERTIFICATE-----
+MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg
+QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe
+Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p
+ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt
+IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by
+X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b
+gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr
+eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ
+TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy
+Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn
+uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI
+qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm
+ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0
+Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
+/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW
+Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t
+FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm
+zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k
+XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT
+bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU
+RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK
+1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt
+2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ
+Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9
+AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT
+-----END CERTIFICATE-----
+
+certSIGN ROOT CA
+================
+-----BEGIN CERTIFICATE-----
+MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD
+VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa
+Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE
+CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I
+JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH
+rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2
+ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD
+0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943
+AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
+Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB
+AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8
+SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0
+x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt
+vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz
+TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD
+-----END CERTIFICATE-----
+
+CNNIC ROOT
+==========
+-----BEGIN CERTIFICATE-----
+MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE
+ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw
+OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD
+o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz
+VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT
+VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or
+czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK
+y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC
+wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S
+lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5
+Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM
+O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8
+BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2
+G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m
+mxE=
+-----END CERTIFICATE-----
+
+ApplicationCA - Japanese Government
+===================================
+-----BEGIN CERTIFICATE-----
+MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT
+SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw
+MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl
+cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4
+fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN
+wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE
+jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu
+nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU
+WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV
+BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD
+vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs
+o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g
+/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD
+io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW
+dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL
+rosot4LKGAfmt1t06SAZf7IbiVQ=
+-----END CERTIFICATE-----
+
+GeoTrust Primary Certification Authority - G3
+=============================================
+-----BEGIN CERTIFICATE-----
+MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE
+BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0
+IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy
+eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz
+NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo
+YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT
+LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j
+K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE
+c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C
+IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu
+dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr
+2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9
+cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE
+Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
+AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s
+t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt
+-----END CERTIFICATE-----
+
+thawte Primary Root CA - G2
+===========================
+-----BEGIN CERTIFICATE-----
+MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC
+VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu
+IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg
+Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV
+MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG
+b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt
+IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS
+LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5
+8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU
+mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN
+G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K
+rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
+-----END CERTIFICATE-----
+
+thawte Primary Root CA - G3
+===========================
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE
+BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
+aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w
+ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
+d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD
+VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG
+A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At
+P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC
++BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY
+7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW
+vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ
+KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK
+A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
+t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC
+8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm
+er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A=
+-----END CERTIFICATE-----
+
+GeoTrust Primary Certification Authority - G2
+=============================================
+-----BEGIN CERTIFICATE-----
+MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC
+VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu
+Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1
+OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
+MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl
+b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG
+BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc
+KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD
+VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+
+EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m
+ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2
+npaqBA+K
+-----END CERTIFICATE-----
+
+VeriSign Universal Root Certification Authority
+===============================================
+-----BEGIN CERTIFICATE-----
+MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE
+BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
+ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
+IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u
+IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
+cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj
+1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP
+MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72
+9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I
+AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR
+tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G
+CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O
+a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
+DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3
+Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx
+Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx
+P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P
+wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4
+mJO37M2CYfE45k+XmCpajQ==
+-----END CERTIFICATE-----
+
+VeriSign Class 3 Public Primary Certification Authority - G4
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC
+VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3
+b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz
+ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU
+cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo
+b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5
+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8
+Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz
+rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB
+/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw
+HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u
+Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD
+A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx
+AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
+-----END CERTIFICATE-----
+
+NetLock Arany (Class Gold) Főtanúsítvány
+============================================
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G
+A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610
+dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB
+cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx
+MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO
+ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6
+c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu
+0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw
+/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk
+H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw
+fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1
+neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB
+BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW
+qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta
+YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC
+bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna
+NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu
+dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
+-----END CERTIFICATE-----
+
+Staat der Nederlanden Root CA - G2
+==================================
+-----BEGIN CERTIFICATE-----
+MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE
+CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
+Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC
+TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l
+ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ
+5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn
+vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj
+CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil
+e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR
+OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI
+CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65
+48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi
+trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737
+qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB
+AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC
+ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV
+HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA
+A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz
++51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj
+f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN
+kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk
+CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF
+URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb
+CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h
+oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV
+IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm
+66+KAQ==
+-----END CERTIFICATE-----
+
+CA Disig
+========
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK
+QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw
+MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz
+bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm
+GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD
+Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo
+hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt
+ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w
+gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P
+AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz
+aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff
+ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa
+BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t
+WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3
+mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/
+CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K
+ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA
+4Z7CRneC9VkGjCFMhwnN5ag=
+-----END CERTIFICATE-----
+
+Juur-SK
+=======
+-----BEGIN CERTIFICATE-----
+MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA
+c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw
+DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG
+SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy
+aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf
+TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC
++Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw
+UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa
+Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF
+MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD
+HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh
+AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA
+cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr
+AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw
+cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE
+FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G
+A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo
+ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL
+abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678
+IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh
+Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2
+yyqcjg==
+-----END CERTIFICATE-----
+
+Hongkong Post Root CA 1
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT
+DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx
+NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n
+IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1
+ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr
+auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh
+qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY
+V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV
+HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i
+h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio
+l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei
+IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps
+T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT
+c4afU9hDDl3WY4JxHYB0yvbiAmvZWg==
+-----END CERTIFICATE-----
+
+SecureSign RootCA11
+===================
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi
+SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS
+b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw
+KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1
+cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL
+TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO
+wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq
+g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP
+O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA
+bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX
+t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh
+OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r
+bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ
+Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01
+y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061
+lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I=
+-----END CERTIFICATE-----
+
+ACEDICOM Root
+=============
+-----BEGIN CERTIFICATE-----
+MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD
+T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4
+MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG
+A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk
+WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD
+YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew
+MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb
+m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk
+HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT
+xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2
+3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9
+2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq
+TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz
+4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU
+9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv
+bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg
+aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP
+eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk
+zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1
+ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI
+KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq
+nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE
+I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp
+MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o
+tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA==
+-----END CERTIFICATE-----
+
+Verisign Class 1 Public Primary Certification Authority
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCED9pHoGc8JpK83P/uUii5N0wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx
+FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQcmltYXJ5
+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow
+XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAx
+IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDlGb9to1ZhLZlIcfZn3rmN67eehoAKkQ76OCWvRoiC5XOooJskXQ0fzGVuDLDQ
+VoQYh5oGmxChc9+0WDlrbsH2FdWoqD+qEgaNMax/sDTXjzRniAnNFBHiTkVWaR94AoDa3EeRKbs2
+yWNcxeDXLYd7obcysHswuiovMaruo2fa2wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFgVKTk8d6Pa
+XCUDfGD67gmZPCcQcMgMCeazh88K4hiWNWLMv5sneYlfycQJ9M61Hd8qveXbhpxoJeUwfLaJFf5n
+0a3hUKw8fGJLj7qE1xIVGx/KXQ/BUpQqEZnae88MNhPVNdwQGVnqlMEAv3WP2fr9dgTbYruQagPZ
+RjXZ+Hxb
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx
+FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5
+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow
+XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz
+IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94
+f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol
+hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABByUqkFFBky
+CEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWX
+bj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/
+D/xwzoiQ
+-----END CERTIFICATE-----
+
+Microsec e-Szigno Root CA 2009
+==============================
+-----BEGIN CERTIFICATE-----
+MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER
+MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv
+c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o
+dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE
+BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt
+U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA
+fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG
+0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA
+pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm
+1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC
+AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf
+QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE
+FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o
+lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX
+I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775
+tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02
+yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi
+LXpUq3DDfSJlgnCW
+-----END CERTIFICATE-----
+
+E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi
+===================================================
+-----BEGIN CERTIFICATE-----
+MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG
+EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz
+ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3
+MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0
+cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u
+aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY
+8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y
+jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI
+JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk
+9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD
+AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG
+SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d
+F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq
+D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4
+Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq
+fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX
+-----END CERTIFICATE-----
+
+GlobalSign Root CA - R3
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv
+YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
+bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
+aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
+bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt
+iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ
+0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3
+rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl
+OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2
+xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7
+lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8
+EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E
+bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18
+YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r
+kpeDMdmztcpHWD9f
+-----END CERTIFICATE-----
+
+TC TrustCenter Universal CA III
+===============================
+-----BEGIN CERTIFICATE-----
+MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezELMAkGA1UEBhMC
+REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy
+IFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAe
+Fw0wOTA5MDkwODE1MjdaFw0yOTEyMzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNU
+QyBUcnVzdENlbnRlciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0Ex
+KDAmBgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF5+cvAqBNLaT6hdqbJYUt
+QCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYvDIRlzg9uwliT6CwLOunBjvvya8o84pxO
+juT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8vzArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+Eut
+CHnNaYlAJ/Uqwa1D7KRTyGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1
+M4BDj5yjdipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBhMB8G
+A1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
+BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI4jANBgkqhkiG9w0BAQUFAAOCAQEA
+g8ev6n9NCjw5sWi+e22JLumzCecYV42FmhfzdkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+
+KGwWaODIl0YgoGhnYIg5IFHYaAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhK
+BgePxLcHsU0GDeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV
+CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPHLQNjO9Po5KIq
+woIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg==
+-----END CERTIFICATE-----
+
+Autoridad de Certificacion Firmaprofesional CIF A62634068
+=========================================================
+-----BEGIN CERTIFICATE-----
+MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA
+BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
+MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw
+QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB
+NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD
+Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P
+B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY
+7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH
+ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI
+plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX
+MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX
+LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK
+bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU
+vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud
+EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH
+DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp
+cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA
+bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx
+ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx
+51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk
+R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP
+T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f
+Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl
+osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR
+crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR
+saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD
+KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi
+6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
+-----END CERTIFICATE-----
+
+Izenpe.com
+==========
+-----BEGIN CERTIFICATE-----
+MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG
+EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz
+MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu
+QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ
+03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK
+ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU
++zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC
+PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT
+OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK
+F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK
+0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+
+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB
+leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID
+AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+
+SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG
+NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
+MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
+BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l
+Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga
+kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q
+hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs
+g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5
+aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5
+nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC
+ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo
+Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z
+WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
+-----END CERTIFICATE-----
+
+Chambers of Commerce Root - 2008
+================================
+-----BEGIN CERTIFICATE-----
+MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD
+MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
+bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
+QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy
+Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl
+ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF
+EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl
+cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA
+XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj
+h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/
+ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk
+NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g
+D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331
+lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ
+0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj
+ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2
+EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI
+G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ
+BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh
+bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh
+bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC
+CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH
+AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1
+wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH
+3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU
+RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6
+M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1
+YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF
+9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK
+zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG
+nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg
+OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ
+-----END CERTIFICATE-----
+
+Global Chambersign Root - 2008
+==============================
+-----BEGIN CERTIFICATE-----
+MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD
+MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
+bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
+QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx
+NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg
+Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ
+QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD
+aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf
+VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf
+XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0
+ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB
+/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA
+TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M
+H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe
+Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF
+HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh
+wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB
+AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT
+BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE
+BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm
+aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm
+aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp
+1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0
+dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG
+/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6
+ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s
+dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg
+9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH
+foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du
+qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr
+P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq
+c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z
+09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B
+-----END CERTIFICATE-----
+
+Go Daddy Root Certificate Authority - G2
+========================================
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu
+MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
+MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
+b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G
+A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq
+9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD
++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd
+fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl
+NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9
+BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac
+vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r
+5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV
+N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
+LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1
+-----END CERTIFICATE-----
+
+Starfield Root Certificate Authority - G2
+=========================================
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
+b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0
+eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw
+DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg
+VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB
+dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv
+W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs
+bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk
+N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf
+ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU
+JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol
+TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx
+4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw
+F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
+pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ
+c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
+-----END CERTIFICATE-----
+
+Starfield Services Root Certificate Authority - G2
+==================================================
+-----BEGIN CERTIFICATE-----
+MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
+b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl
+IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV
+BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT
+dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg
+Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2
+h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa
+hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP
+LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB
+rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
+AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG
+SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP
+E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy
+xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
+iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza
+YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6
+-----END CERTIFICATE-----
+
+AffirmTrust Commercial
+======================
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS
+BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw
+MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
+bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb
+DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV
+C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6
+BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww
+MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV
+HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG
+hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi
+qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv
+0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh
+sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
+-----END CERTIFICATE-----
+
+AffirmTrust Networking
+======================
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS
+BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw
+MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
+bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE
+Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI
+dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24
+/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb
+h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV
+HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu
+UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6
+12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23
+WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9
+/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
+-----END CERTIFICATE-----
+
+AffirmTrust Premium
+===================
+-----BEGIN CERTIFICATE-----
+MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS
+BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy
+OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy
+dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn
+BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV
+5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs
++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd
+GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R
+p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI
+S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04
+6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5
+/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo
++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv
+MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
+Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC
+6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S
+L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK
++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV
+BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg
+IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60
+g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb
+zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw==
+-----END CERTIFICATE-----
+
+AffirmTrust Premium ECC
+=======================
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV
+BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx
+MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U
+cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ
+N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW
+BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK
+BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X
+57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM
+eQ==
+-----END CERTIFICATE-----
+
+Certum Trusted Network CA
+=========================
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK
+ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy
+MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU
+ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC
+l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J
+J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4
+fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0
+cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB
+Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw
+DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj
+jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1
+mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj
+Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
+03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
+-----END CERTIFICATE-----
+
+Certinomis - Autorité Racine
+=============================
+-----BEGIN CERTIFICATE-----
+MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK
+Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg
+LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG
+A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw
+JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa
+wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly
+Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw
+2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N
+jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q
+c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC
+lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb
+xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g
+530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna
+4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
+A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ
+KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x
+WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva
+R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40
+nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B
+CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv
+JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE
+qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b
+WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE
+wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/
+vgt2Fl43N+bYdJeimUV5
+-----END CERTIFICATE-----
+
+Root CA Generalitat Valenciana
+==============================
+-----BEGIN CERTIFICATE-----
+MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE
+ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290
+IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3
+WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE
+CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2
+F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B
+ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ
+D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte
+JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB
+AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n
+dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB
+ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl
+AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA
+YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy
+AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA
+aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt
+AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA
+YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu
+AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA
+OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0
+dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV
+BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G
+A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S
+b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh
+TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz
+Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63
+NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH
+iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt
++GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM=
+-----END CERTIFICATE-----
+
+A-Trust-nQual-03
+================
+-----BEGIN CERTIFICATE-----
+MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE
+Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy
+a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R
+dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw
+RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0
+ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1
+c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA
+zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n
+yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE
+SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4
+iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V
+cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV
+eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40
+ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr
+sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd
+JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS
+mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6
+ahq97BvIxYSazQ==
+-----END CERTIFICATE-----
+
+TWCA Root Certification Authority
+=================================
+-----BEGIN CERTIFICATE-----
+MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ
+VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG
+EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB
+IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx
+QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC
+oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP
+4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r
+y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB
+BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG
+9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC
+mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW
+QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY
+T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny
+Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
+-----END CERTIFICATE-----
+
+Security Communication RootCA2
+==============================
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
+U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh
+dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC
+SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy
+aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++
++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R
+3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV
+spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K
+EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8
+QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB
+CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj
+u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk
+3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q
+tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29
+mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
+-----END CERTIFICATE-----
+
+EC-ACC
+======
+-----BEGIN CERTIFICATE-----
+MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE
+BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w
+ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD
+VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE
+CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT
+BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7
+MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt
+SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl
+Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh
+cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK
+w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT
+ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4
+HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a
+E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw
+0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD
+VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0
+Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l
+dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ
+lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa
+Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe
+l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2
+E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D
+5EI=
+-----END CERTIFICATE-----
+
+Hellenic Academic and Research Institutions RootCA 2011
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT
+O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y
+aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
+IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT
+AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
+IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo
+IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI
+1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa
+71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u
+8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH
+3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/
+MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8
+MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu
+b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt
+XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8
+TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD
+/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N
+7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4
+-----END CERTIFICATE-----
+
+Actalis Authentication Root CA
+==============================
+-----BEGIN CERTIFICATE-----
+MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM
+BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE
+AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky
+MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz
+IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
+IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ
+wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa
+by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6
+zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f
+YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2
+oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l
+EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7
+hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8
+EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5
+jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY
+iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
+ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI
+WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0
+JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx
+K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+
+Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC
+4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo
+2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz
+lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem
+OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9
+vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
+-----END CERTIFICATE-----
+
+Trustis FPS Root CA
+===================
+-----BEGIN CERTIFICATE-----
+MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG
+EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290
+IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV
+BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ
+RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk
+H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa
+cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt
+o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA
+AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd
+BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c
+GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC
+yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P
+8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV
+l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl
+iB6XzCGcKQENZetX2fNXlrtIzYE=
+-----END CERTIFICATE-----
+
+StartCom Certification Authority
+================================
+-----BEGIN CERTIFICATE-----
+MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
+U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu
+ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0
+NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk
+LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg
+U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
+ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y
+o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/
+Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d
+eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt
+2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z
+6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ
+osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/
+untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc
+UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT
+37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ
+Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0
+dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu
+c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv
+bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0
+aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0
+aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t
+L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG
+cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5
+fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm
+N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN
+Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T
+tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX
+e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA
+2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs
+HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE
+JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib
+D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8=
+-----END CERTIFICATE-----
+
+StartCom Certification Authority G2
+===================================
+-----BEGIN CERTIFICATE-----
+MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
+U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE
+ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O
+o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG
+4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi
+Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul
+Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs
+O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H
+vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L
+nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS
+FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa
+z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ
+KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K
+2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk
+J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+
+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG
+/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc
+nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld
+blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc
+l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm
+7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm
+obp573PYtlNXLfbQ4ddI
+-----END CERTIFICATE-----
+
+Buypass Class 2 Root CA
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X
+DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
+eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1
+g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn
+9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b
+/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU
+CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff
+awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI
+zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn
+Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX
+Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs
+M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
+AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s
+A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI
+osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S
+aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd
+DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD
+LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0
+oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC
+wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS
+CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN
+rJgWVqA=
+-----END CERTIFICATE-----
+
+Buypass Class 3 Root CA
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X
+DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
+eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH
+sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR
+5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh
+7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ
+ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH
+2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV
+/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ
+RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA
+Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq
+j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
+AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV
+cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G
+uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG
+Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8
+ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2
+KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz
+6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug
+UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe
+eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi
+Cp/HuZc=
+-----END CERTIFICATE-----
+
+TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı
+======================================================
+-----BEGIN CERTIFICATE-----
+MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP
+MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg
+QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X
+DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl
+a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN
+BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp
+bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N
+YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv
+KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya
+KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT
+rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC
+AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s
+Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I
+aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO
+Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb
+BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK
+poRq0Tl9
+-----END CERTIFICATE-----
+
+T-TeleSec GlobalRoot Class 3
+============================
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
+IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
+cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx
+MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
+dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
+ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK
+9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU
+NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF
+iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W
+0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr
+AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb
+fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT
+ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h
+P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
+e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==
+-----END CERTIFICATE-----
+
+EE Certification Centre Root CA
+===============================
+-----BEGIN CERTIFICATE-----
+MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG
+EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy
+dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw
+MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB
+UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy
+ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM
+TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2
+rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw
+93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN
+P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T
+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ
+MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF
+BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj
+xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM
+lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u
+uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU
+3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM
+dcGWxZ0=
+-----END CERTIFICATE-----
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/AdapterInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/AdapterInterface.php
new file mode 100644
index 0000000..f3c035e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/AdapterInterface.php
@@ -0,0 +1,23 @@
+multi = $multiHandle;
+ $this->handles = new \SplObjectStorage();
+ $this->throwsExceptions = $throwsExceptions;
+ $this->pending = $pending;
+ }
+
+ /**
+ * Find a transaction for a given curl handle
+ *
+ * @param resource $handle Curl handle
+ *
+ * @return TransactionInterface
+ * @throws AdapterException if a transaction is not found
+ */
+ public function findTransaction($handle)
+ {
+ foreach ($this->handles as $transaction) {
+ if ($this->handles[$transaction] === $handle) {
+ return $transaction;
+ }
+ }
+
+ throw new AdapterException('No curl handle was found');
+ }
+
+ /**
+ * Returns true if there are any remaining pending transactions
+ *
+ * @return bool
+ */
+ public function hasPending()
+ {
+ return $this->pending && $this->pending->valid();
+ }
+
+ /**
+ * Pop the next transaction from the transaction queue
+ *
+ * @return TransactionInterface|null
+ */
+ public function nextPending()
+ {
+ if (!$this->hasPending()) {
+ return null;
+ }
+
+ $current = $this->pending->current();
+ $this->pending->next();
+
+ return $current;
+ }
+
+ /**
+ * Checks if the batch is to throw exceptions on error
+ *
+ * @return bool
+ */
+ public function throwsExceptions()
+ {
+ return $this->throwsExceptions;
+ }
+
+ /**
+ * Get the curl_multi handle
+ *
+ * @return resource
+ */
+ public function getMultiHandle()
+ {
+ return $this->multi;
+ }
+
+ /**
+ * Add a transaction to the multi handle
+ *
+ * @param TransactionInterface $transaction Transaction to add
+ * @param resource $handle Resource to use with the handle
+ *
+ * @throws AdapterException If the handle is already registered
+ */
+ public function addTransaction(TransactionInterface $transaction, $handle)
+ {
+ if (isset($this->handles[$transaction])) {
+ throw new AdapterException('Transaction already registered');
+ }
+
+ $code = curl_multi_add_handle($this->multi, $handle);
+ if ($code != CURLM_OK) {
+ MultiAdapter::throwMultiError($code);
+ }
+
+ $this->handles[$transaction] = $handle;
+ }
+
+ /**
+ * Remove a transaction and associated handle from the context
+ *
+ * @param TransactionInterface $transaction Transaction to remove
+ *
+ * @return array Returns the curl_getinfo array
+ * @throws AdapterException if the transaction is not found
+ */
+ public function removeTransaction(TransactionInterface $transaction)
+ {
+ if (!isset($this->handles[$transaction])) {
+ throw new AdapterException('Transaction not registered');
+ }
+
+ $handle = $this->handles[$transaction];
+
+ $code = curl_multi_remove_handle($this->multi, $handle);
+ if ($code != CURLM_OK) {
+ MultiAdapter::throwMultiError($code);
+ }
+
+ $info = curl_getinfo($handle);
+ curl_close($handle);
+ unset($this->handles[$transaction]);
+
+ return $info;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/Curl/CurlAdapter.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/Curl/CurlAdapter.php
new file mode 100644
index 0000000..0f12035
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/Curl/CurlAdapter.php
@@ -0,0 +1,142 @@
+handles = $this->ownedHandles = [];
+ $this->messageFactory = $messageFactory;
+ $this->curlFactory = isset($options['handle_factory'])
+ ? $options['handle_factory']
+ : new CurlFactory();
+ $this->maxHandles = isset($options['max_handles'])
+ ? $options['max_handles']
+ : 5;
+ }
+
+ public function __destruct()
+ {
+ foreach ($this->handles as $handle) {
+ if (is_resource($handle)) {
+ curl_close($handle);
+ }
+ }
+ }
+
+ public function send(TransactionInterface $transaction)
+ {
+ RequestEvents::emitBefore($transaction);
+ if ($response = $transaction->getResponse()) {
+ return $response;
+ }
+
+ $factory = $this->curlFactory;
+ $handle = $factory(
+ $transaction,
+ $this->messageFactory,
+ $this->checkoutEasyHandle()
+ );
+
+ curl_exec($handle);
+ $info = curl_getinfo($handle);
+ $info['curl_result'] = curl_errno($handle);
+
+ if ($info['curl_result']) {
+ $this->handleError($transaction, $info, $handle);
+ } else {
+ $this->releaseEasyHandle($handle);
+ RequestEvents::emitComplete($transaction, $info);
+ }
+
+ return $transaction->getResponse();
+ }
+
+ private function handleError(
+ TransactionInterface $transaction,
+ $info,
+ $handle
+ ) {
+ $error = curl_error($handle);
+ $this->releaseEasyHandle($handle);
+ RequestEvents::emitError(
+ $transaction,
+ new AdapterException("cURL error {$info['curl_result']}: {$error}"),
+ $info
+ );
+ }
+
+ private function checkoutEasyHandle()
+ {
+ // Find an unused handle in the cache
+ if (false !== ($key = array_search(false, $this->ownedHandles, true))) {
+ $this->ownedHandles[$key] = true;
+ return $this->handles[$key];
+ }
+
+ // Add a new handle
+ $handle = curl_init();
+ $id = (int) $handle;
+ $this->handles[$id] = $handle;
+ $this->ownedHandles[$id] = true;
+
+ return $handle;
+ }
+
+ private function releaseEasyHandle($handle)
+ {
+ $id = (int) $handle;
+ if (count($this->ownedHandles) > $this->maxHandles) {
+ curl_close($this->handles[$id]);
+ unset($this->handles[$id], $this->ownedHandles[$id]);
+ } else {
+ curl_reset($handle);
+ $this->ownedHandles[$id] = false;
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/Curl/CurlFactory.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/Curl/CurlFactory.php
new file mode 100644
index 0000000..f1cb393
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/Curl/CurlFactory.php
@@ -0,0 +1,331 @@
+getRequest();
+ $mediator = new RequestMediator($transaction, $messageFactory);
+ $options = $this->getDefaultOptions($request, $mediator);
+ $this->applyMethod($request, $options);
+ $this->applyTransferOptions($request, $mediator, $options);
+ $this->applyHeaders($request, $options);
+ unset($options['_headers']);
+
+ // Add adapter options from the request's configuration options
+ if ($config = $request->getConfig()['curl']) {
+ $options = $this->applyCustomCurlOptions($config, $options);
+ }
+
+ if (!$handle) {
+ $handle = curl_init();
+ }
+
+ curl_setopt_array($handle, $options);
+
+ return $handle;
+ }
+
+ protected function getDefaultOptions(
+ RequestInterface $request,
+ RequestMediator $mediator
+ ) {
+ $url = $request->getUrl();
+
+ // Strip fragment from URL. See:
+ // https://github.com/guzzle/guzzle/issues/453
+ if (($pos = strpos($url, '#')) !== false) {
+ $url = substr($url, 0, $pos);
+ }
+
+ $config = $request->getConfig();
+ $options = array(
+ CURLOPT_URL => $url,
+ CURLOPT_CONNECTTIMEOUT => $config['connect_timeout'] ?: 150,
+ CURLOPT_RETURNTRANSFER => false,
+ CURLOPT_HEADER => false,
+ CURLOPT_WRITEFUNCTION => array($mediator, 'writeResponseBody'),
+ CURLOPT_HEADERFUNCTION => array($mediator, 'receiveResponseHeader'),
+ CURLOPT_READFUNCTION => array($mediator, 'readRequestBody'),
+ CURLOPT_HTTP_VERSION => $request->getProtocolVersion() === '1.0'
+ ? CURL_HTTP_VERSION_1_0 : CURL_HTTP_VERSION_1_1,
+ CURLOPT_SSL_VERIFYPEER => 1,
+ CURLOPT_SSL_VERIFYHOST => 2,
+ '_headers' => $request->getHeaders()
+ );
+
+ if (defined('CURLOPT_PROTOCOLS')) {
+ // Allow only HTTP and HTTPS protocols
+ $options[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
+ }
+
+ // Add CURLOPT_ENCODING if Accept-Encoding header is provided
+ if ($request->hasHeader('Accept-Encoding')) {
+ $options[CURLOPT_ENCODING] = $request->getHeader('Accept-Encoding');
+ // Let cURL set the Accept-Encoding header. Without this change
+ // curl could add a duplicate value.
+ $this->removeHeader('Accept-Encoding', $options);
+ }
+
+ return $options;
+ }
+
+ private function applyMethod(RequestInterface $request, array &$options)
+ {
+ $method = $request->getMethod();
+ if ($method == 'HEAD') {
+ $options[CURLOPT_NOBODY] = true;
+ unset($options[CURLOPT_WRITEFUNCTION], $options[CURLOPT_READFUNCTION]);
+ } else {
+ $options[CURLOPT_CUSTOMREQUEST] = $method;
+ if (!$request->getBody()) {
+ unset($options[CURLOPT_READFUNCTION]);
+ } else {
+ $this->applyBody($request, $options);
+ }
+ }
+ }
+
+ private function applyBody(RequestInterface $request, array &$options)
+ {
+ if ($request->hasHeader('Content-Length')) {
+ $size = (int) $request->getHeader('Content-Length');
+ } else {
+ $size = null;
+ }
+
+ $request->getBody()->seek(0);
+
+ // You can send the body as a string using curl's CURLOPT_POSTFIELDS
+ if (($size !== null && $size < 32768) ||
+ isset($request->getConfig()['curl']['body_as_string'])
+ ) {
+ $options[CURLOPT_POSTFIELDS] = $request->getBody()->getContents();
+ // Don't duplicate the Content-Length header
+ $this->removeHeader('Content-Length', $options);
+ $this->removeHeader('Transfer-Encoding', $options);
+ } else {
+ $options[CURLOPT_UPLOAD] = true;
+ // Let cURL handle setting the Content-Length header
+ if ($size !== null) {
+ $options[CURLOPT_INFILESIZE] = $size;
+ $this->removeHeader('Content-Length', $options);
+ }
+ }
+
+ // If the Expect header is not present, prevent curl from adding it
+ if (!$request->hasHeader('Expect')) {
+ $options[CURLOPT_HTTPHEADER][] = 'Expect:';
+ }
+ }
+
+ private function applyHeaders(RequestInterface $request, array &$options)
+ {
+ foreach ($options['_headers'] as $name => $values) {
+ $options[CURLOPT_HTTPHEADER][] = $name . ': ' . implode(', ', $values);
+ }
+
+ // Remove the Expect header if one was not set
+ if (!$request->hasHeader('Accept')) {
+ $options[CURLOPT_HTTPHEADER][] = 'Accept:';
+ }
+ }
+
+ private function applyTransferOptions(
+ RequestInterface $request,
+ RequestMediator $mediator,
+ array &$options
+ ) {
+ static $methods;
+ if (!$methods) {
+ $methods = array_flip(get_class_methods(__CLASS__));
+ }
+
+ foreach ($request->getConfig()->toArray() as $key => $value) {
+ $method = "add_{$key}";
+ if (isset($methods[$method])) {
+ $this->{$method}($request, $mediator, $options, $value);
+ }
+ }
+ }
+
+ private function add_debug(
+ RequestInterface $request,
+ RequestMediator $mediator,
+ &$options,
+ $value
+ ) {
+ if ($value) {
+ $options[CURLOPT_STDERR] = is_resource($value) ? $value : STDOUT;
+ $options[CURLOPT_VERBOSE] = true;
+ }
+ }
+
+ private function add_proxy(
+ RequestInterface $request,
+ RequestMediator $mediator,
+ &$options,
+ $value
+ ) {
+ if (!is_array($value)) {
+ $options[CURLOPT_PROXY] = $value;
+ } else {
+ $scheme = $request->getScheme();
+ if (isset($value[$scheme])) {
+ $options[CURLOPT_PROXY] = $value[$scheme];
+ }
+ }
+ }
+
+ private function add_timeout(
+ RequestInterface $request,
+ RequestMediator $mediator,
+ &$options,
+ $value
+ ) {
+ $options[CURLOPT_TIMEOUT_MS] = $value * 1000;
+ }
+
+ private function add_connect_timeout(
+ RequestInterface $request,
+ RequestMediator $mediator,
+ &$options,
+ $value
+ ) {
+ $options[CURLOPT_CONNECTTIMEOUT_MS] = $value * 1000;
+ }
+
+ private function add_verify(
+ RequestInterface $request,
+ RequestMediator $mediator,
+ &$options,
+ $value
+ ) {
+ if ($value === false) {
+ unset($options[CURLOPT_CAINFO]);
+ $options[CURLOPT_SSL_VERIFYHOST] = 0;
+ $options[CURLOPT_SSL_VERIFYPEER] = false;
+ } elseif ($value === true || is_string($value)) {
+ $options[CURLOPT_SSL_VERIFYHOST] = 2;
+ $options[CURLOPT_SSL_VERIFYPEER] = true;
+ if ($value !== true) {
+ if (!file_exists($value)) {
+ throw new AdapterException('SSL certificate authority file'
+ . " not found: {$value}");
+ }
+ $options[CURLOPT_CAINFO] = $value;
+ }
+ }
+ }
+
+ private function add_cert(
+ RequestInterface $request,
+ RequestMediator $mediator,
+ &$options,
+ $value
+ ) {
+ if (!file_exists($value)) {
+ throw new AdapterException("SSL certificate not found: {$value}");
+ }
+
+ $options[CURLOPT_SSLCERT] = $value;
+ }
+
+ private function add_ssl_key(
+ RequestInterface $request,
+ RequestMediator $mediator,
+ &$options,
+ $value
+ ) {
+ if (is_array($value)) {
+ $options[CURLOPT_SSLKEYPASSWD] = $value[1];
+ $value = $value[0];
+ }
+
+ if (!file_exists($value)) {
+ throw new AdapterException("SSL private key not found: {$value}");
+ }
+
+ $options[CURLOPT_SSLKEY] = $value;
+ }
+
+ private function add_save_to(
+ RequestInterface $request,
+ RequestMediator $mediator,
+ &$options,
+ $value
+ ) {
+ $mediator->setResponseBody(is_string($value)
+ ? Stream\create(fopen($value, 'w'))
+ : Stream\create($value));
+ }
+
+ /**
+ * Takes an array of curl options specified in the 'curl' option of a
+ * request's configuration array and maps them to CURLOPT_* options.
+ *
+ * This method is only called when a request has a 'curl' config setting.
+ * Array key strings that start with CURL that have a matching constant
+ * value will be automatically converted to the matching constant.
+ *
+ * @param array $config Configuration array of custom curl option
+ * @param array $options Array of existing curl options
+ *
+ * @return array Returns a new array of curl options
+ */
+ private function applyCustomCurlOptions(array $config, array $options)
+ {
+ unset($config['body_as_string']);
+ $curlOptions = [];
+
+ // Map curl constant strings to defined values
+ foreach ($config as $key => $value) {
+ if (defined($key) && substr($key, 0, 4) === 'CURL') {
+ $key = constant($key);
+ }
+ $curlOptions[$key] = $value;
+ }
+
+ return $curlOptions + $options;
+ }
+
+ /**
+ * Remove a header from the options array
+ *
+ * @param string $name Case-insensitive header to remove
+ * @param array $options Array of options to modify
+ */
+ private function removeHeader($name, array &$options)
+ {
+ foreach (array_keys($options['_headers']) as $key) {
+ if (!strcasecmp($key, $name)) {
+ unset($options['_headers'][$key]);
+ return;
+ }
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/Curl/MultiAdapter.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/Curl/MultiAdapter.php
new file mode 100644
index 0000000..3064595
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/Curl/MultiAdapter.php
@@ -0,0 +1,284 @@
+messageFactory = $messageFactory;
+ $this->curlFactory = isset($options['handle_factory'])
+ ? $options['handle_factory']
+ : new CurlFactory();
+
+ if (isset($options['select_timeout'])) {
+ $this->selectTimeout = $options['select_timeout'];
+ } elseif (isset($_SERVER[self::ENV_SELECT_TIMEOUT])) {
+ $this->selectTimeout = $_SERVER[self::ENV_SELECT_TIMEOUT];
+ } else {
+ $this->selectTimeout = 1;
+ }
+ }
+
+ public function __destruct()
+ {
+ foreach ($this->multiHandles as $handle) {
+ if (is_resource($handle)) {
+ curl_multi_close($handle);
+ }
+ }
+ }
+
+ /**
+ * Throw an exception for a cURL multi response
+ *
+ * @param int $code Curl response code
+ * @throws AdapterException
+ */
+ public static function throwMultiError($code)
+ {
+ $buffer = function_exists('curl_multi_strerror')
+ ? curl_multi_strerror($code)
+ : self::ERROR_STR;
+
+ throw new AdapterException(sprintf('cURL error %s: %s', $code, $buffer));
+ }
+
+ public function send(TransactionInterface $transaction)
+ {
+ $context = new BatchContext($this->checkoutMultiHandle(), true);
+ $this->addHandle($transaction, $context);
+ $this->perform($context);
+
+ return $transaction->getResponse();
+ }
+
+ public function sendAll(\Iterator $transactions, $parallel)
+ {
+ $context = new BatchContext(
+ $this->checkoutMultiHandle(),
+ false,
+ $transactions
+ );
+
+ foreach (new \LimitIterator($transactions, 0, $parallel) as $trans) {
+ $this->addHandle($trans, $context);
+ }
+
+ $this->perform($context);
+ }
+
+ private function perform(BatchContext $context)
+ {
+ // The first curl_multi_select often times out no matter what, but is
+ // usually required for fast transfers.
+ $active = false;
+ $multi = $context->getMultiHandle();
+
+ do {
+ while (($mrc = curl_multi_exec($multi, $active)) == CURLM_CALL_MULTI_PERFORM);
+ if ($mrc != CURLM_OK && $mrc != CURLM_CALL_MULTI_PERFORM) {
+ self::throwMultiError($mrc);
+ }
+ // Need to check if there are pending transactions before processing
+ // them so that we don't bail from the loop too early.
+ $pending = $context->hasPending();
+ $this->processMessages($context);
+ if ($active && curl_multi_select($multi, $this->selectTimeout) === -1) {
+ // Perform a usleep if a select returns -1.
+ // See: https://bugs.php.net/bug.php?id=61141
+ usleep(250);
+ }
+ } while ($active || $pending);
+
+ $this->releaseMultiHandle($multi);
+ }
+
+ private function processMessages(BatchContext $context)
+ {
+ $multi = $context->getMultiHandle();
+
+ while ($done = curl_multi_info_read($multi)) {
+ $transaction = $context->findTransaction($done['handle']);
+ $this->processResponse($transaction, $done, $context);
+ // Add the next transaction if there are more in the queue
+ if ($next = $context->nextPending()) {
+ $this->addHandle($next, $context);
+ }
+ }
+ }
+
+ private function processResponse(
+ TransactionInterface $transaction,
+ array $curl,
+ BatchContext $context
+ ) {
+ $info = $context->removeTransaction($transaction);
+
+ try {
+ if (!$this->isCurlException($transaction, $curl, $context, $info)) {
+ RequestEvents::emitComplete($transaction, $info);
+ }
+ } catch (RequestException $e) {
+ $this->throwException($e, $context);
+ }
+ }
+
+ private function addHandle(
+ TransactionInterface $transaction,
+ BatchContext $context
+ ) {
+ try {
+ RequestEvents::emitBefore($transaction);
+ // Only transfer if the request was not intercepted
+ if (!$transaction->getResponse()) {
+ $factory = $this->curlFactory;
+ $context->addTransaction(
+ $transaction,
+ $factory($transaction, $this->messageFactory)
+ );
+ }
+ } catch (RequestException $e) {
+ $this->throwException($e, $context);
+ }
+ }
+
+ private function isCurlException(
+ TransactionInterface $transaction,
+ array $curl,
+ BatchContext $context,
+ array $info
+ ) {
+ if (CURLM_OK == $curl['result'] ||
+ CURLM_CALL_MULTI_PERFORM == $curl['result']
+ ) {
+ return false;
+ }
+
+ $request = $transaction->getRequest();
+ try {
+ // Send curl stats along if they are available
+ $stats = ['curl_result' => $curl['result']] + $info;
+ RequestEvents::emitError(
+ $transaction,
+ new RequestException(
+ sprintf(
+ '[curl] (#%s) %s [url] %s',
+ $curl['result'],
+ function_exists('curl_strerror')
+ ? curl_strerror($curl['result'])
+ : self::ERROR_STR,
+ $request->getUrl()
+ ),
+ $request
+ ),
+ $stats
+ );
+ } catch (RequestException $e) {
+ $this->throwException($e, $context);
+ }
+
+ return true;
+ }
+
+ private function throwException(RequestException $e, BatchContext $context)
+ {
+ if ($context->throwsExceptions()) {
+ $this->releaseMultiHandle($context->getMultiHandle());
+ throw $e;
+ }
+ }
+
+ /**
+ * Returns a curl_multi handle from the cache or creates a new one
+ *
+ * @return resource
+ */
+ private function checkoutMultiHandle()
+ {
+ // Find an unused handle in the cache
+ $key = array_search(false, $this->multiOwned, true);
+ if (false !== $key) {
+ $this->multiOwned[$key] = true;
+ return $this->multiHandles[$key];
+ }
+
+ // Add a new handle
+ $handle = curl_multi_init();
+ $id = (int) $handle;
+ $this->multiHandles[$id] = $handle;
+ $this->multiOwned[$id] = true;
+
+ return $handle;
+ }
+
+ /**
+ * Releases a curl_multi handle back into the cache and removes excess cache
+ *
+ * @param resource $handle Curl multi handle to remove
+ */
+ private function releaseMultiHandle($handle)
+ {
+ $id = (int) $handle;
+
+ if (count($this->multiHandles) <= 3) {
+ $this->multiOwned[$id] = false;
+ } else {
+ // Prune excessive handles
+ curl_multi_close($this->multiHandles[$id]);
+ unset($this->multiHandles[$id], $this->multiOwned[$id]);
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/Curl/RequestMediator.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/Curl/RequestMediator.php
new file mode 100644
index 0000000..19cbcfd
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/Curl/RequestMediator.php
@@ -0,0 +1,130 @@
+transaction = $transaction;
+ $this->messageFactory = $messageFactory;
+ }
+
+ /**
+ * Set the body that will hold the response body
+ *
+ * @param StreamInterface $body Response body
+ */
+ public function setResponseBody(StreamInterface $body = null)
+ {
+ $this->body = $body;
+ }
+
+ /**
+ * Receive a response header from curl
+ *
+ * @param resource $curl Curl handle
+ * @param string $header Received header
+ *
+ * @return int
+ */
+ public function receiveResponseHeader($curl, $header)
+ {
+ static $normalize = ["\r", "\n"];
+ $length = strlen($header);
+ $header = str_replace($normalize, '', $header);
+
+ if (strpos($header, 'HTTP/') === 0) {
+ $startLine = explode(' ', $header, 3);
+ // Only download the body to a target body when a successful
+ // response is received.
+ if ($startLine[1][0] != '2') {
+ $this->body = null;
+ }
+ $this->statusCode = $startLine[1];
+ $this->reasonPhrase = isset($startLine[2]) ? $startLine[2] : null;
+ $this->protocolVersion = substr($startLine[0], -3);
+ $this->headers = [];
+ } elseif ($pos = strpos($header, ':')) {
+ $this->headers[substr($header, 0, $pos)][] = substr($header, $pos + 1);
+ } elseif ($header == '' && $this->statusCode >= 200) {
+ $response = $this->messageFactory->createResponse(
+ $this->statusCode,
+ $this->headers,
+ $this->body,
+ [
+ 'protocol_version' => $this->protocolVersion,
+ 'reason_phrase' => $this->reasonPhrase
+ ]
+ );
+ $this->headers = $this->body = null;
+ $this->transaction->setResponse($response);
+ // Allows events to react before downloading any of the body
+ RequestEvents::emitHeaders($this->transaction);
+ }
+
+ return $length;
+ }
+
+ /**
+ * Write data to the response body of a request
+ *
+ * @param resource $curl
+ * @param string $write
+ *
+ * @return int
+ */
+ public function writeResponseBody($curl, $write)
+ {
+ if (!($response = $this->transaction->getResponse())) {
+ return 0;
+ }
+
+ // Add a default body on the response if one was not found
+ if (!($body = $response->getBody())) {
+ $body = new Stream(fopen('php://temp', 'r+'));
+ $response->setBody($body);
+ }
+
+ return $body->write($write);
+ }
+
+ /**
+ * Read data from the request body and send it to curl
+ *
+ * @param resource $ch Curl handle
+ * @param resource $fd File descriptor
+ * @param int $length Amount of data to read
+ *
+ * @return string
+ */
+ public function readRequestBody($ch, $fd, $length)
+ {
+ return (string) $this->transaction->getRequest()->getBody()->read($length);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/FakeParallelAdapter.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/FakeParallelAdapter.php
new file mode 100644
index 0000000..3026568
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/FakeParallelAdapter.php
@@ -0,0 +1,34 @@
+adapter = $adapter;
+ }
+
+ public function sendAll(\Iterator $transactions, $parallel)
+ {
+ foreach ($transactions as $transaction) {
+ try {
+ $this->adapter->send($transaction);
+ } catch (RequestException $e) {
+ // no op for batch transaction
+ }
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/MockAdapter.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/MockAdapter.php
new file mode 100644
index 0000000..3e8020e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/MockAdapter.php
@@ -0,0 +1,60 @@
+setResponse($response);
+ }
+
+ /**
+ * Set the response that will be served by the adapter
+ *
+ * @param ResponseInterface|callable $response Response to serve or
+ * function to invoke that handles a transaction
+ */
+ public function setResponse($response)
+ {
+ $this->response = $response;
+ }
+
+ public function send(TransactionInterface $transaction)
+ {
+ RequestEvents::emitBefore($transaction);
+ if (!$transaction->getResponse()) {
+
+ // Read the request body if it is present
+ if ($transaction->getRequest()->getBody()) {
+ $transaction->getRequest()->getBody()->__toString();
+ }
+
+ $response = is_callable($this->response)
+ ? call_user_func($this->response, $transaction)
+ : $this->response;
+ if (!$response instanceof ResponseInterface) {
+ throw new \RuntimeException('Invalid mocked response');
+ }
+
+ $transaction->setResponse($response);
+ RequestEvents::emitHeaders($transaction);
+ RequestEvents::emitComplete($transaction);
+ }
+
+ return $transaction->getResponse();
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/ParallelAdapterInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/ParallelAdapterInterface.php
new file mode 100644
index 0000000..79a25b7
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/ParallelAdapterInterface.php
@@ -0,0 +1,23 @@
+messageFactory = $messageFactory;
+ }
+
+ public function send(TransactionInterface $transaction)
+ {
+ // HTTP/1.1 streams using the PHP stream wrapper require a
+ // Connection: close header. Setting here so that it is added before
+ // emitting the request.before_send event.
+ $request = $transaction->getRequest();
+ if ($request->getProtocolVersion() == '1.1' &&
+ !$request->hasHeader('Connection')
+ ) {
+ $transaction->getRequest()->setHeader('Connection', 'close');
+ }
+
+ RequestEvents::emitBefore($transaction);
+ if (!$transaction->getResponse()) {
+ $this->createResponse($transaction);
+ RequestEvents::emitComplete($transaction);
+ }
+
+ return $transaction->getResponse();
+ }
+
+ private function createResponse(TransactionInterface $transaction)
+ {
+ $request = $transaction->getRequest();
+ $stream = $this->createStream($request, $http_response_header);
+
+ if (!$request->getConfig()['stream']) {
+ $stream = $this->getSaveToBody($request, $stream);
+ }
+
+ // Track the response headers of the request
+ $this->createResponseObject($http_response_header, $transaction, $stream);
+ }
+
+ /**
+ * Drain the steam into the destination stream
+ */
+ private function getSaveToBody(RequestInterface $request, $stream)
+ {
+ if ($saveTo = $request->getConfig()['save_to']) {
+ // Stream the response into the destination stream
+ $saveTo = is_string($saveTo)
+ ? Stream\create(fopen($saveTo, 'r+'))
+ : Stream\create($saveTo);
+ } else {
+ // Stream into the default temp stream
+ $saveTo = Stream\create();
+ }
+
+ while (!feof($stream)) {
+ $saveTo->write(fread($stream, 8096));
+ }
+
+ fclose($stream);
+ $saveTo->seek(0);
+
+ return $saveTo;
+ }
+
+ private function createResponseObject(
+ array $headers,
+ TransactionInterface $transaction,
+ $stream
+ ) {
+ $parts = explode(' ', array_shift($headers), 3);
+ $options = ['protocol_version' => substr($parts[0], -3)];
+ if (isset($parts[2])) {
+ $options['reason_phrase'] = $parts[2];
+ }
+
+ // Set the size on the stream if it was returned in the response
+ $responseHeaders = [];
+ foreach ($headers as $header) {
+ $headerParts = explode(':', $header, 2);
+ $responseHeaders[$headerParts[0]] = isset($headerParts[1])
+ ? $headerParts[1]
+ : '';
+ }
+
+ $response = $this->messageFactory->createResponse(
+ $parts[1],
+ $responseHeaders,
+ $stream,
+ $options
+ );
+
+ $transaction->setResponse($response);
+ RequestEvents::emitHeaders($transaction);
+
+ return $response;
+ }
+
+ /**
+ * Create a resource and check to ensure it was created successfully
+ *
+ * @param callable $callback Callable that returns stream resource
+ * @param RequestInterface $request Request used when throwing exceptions
+ * @param array $options Options used when throwing exceptions
+ *
+ * @return resource
+ * @throws RequestException on error
+ */
+ private function createResource(callable $callback, RequestInterface $request, $options)
+ {
+ // Turn off error reporting while we try to initiate the request
+ $level = error_reporting(0);
+ $resource = call_user_func($callback);
+ error_reporting($level);
+
+ // If the resource could not be created, then grab the last error and
+ // throw an exception.
+ if (!is_resource($resource)) {
+ $message = 'Error creating resource. [url] ' . $request->getUrl() . ' ';
+ if (isset($options['http']['proxy'])) {
+ $message .= "[proxy] {$options['http']['proxy']} ";
+ }
+ foreach (error_get_last() as $key => $value) {
+ $message .= "[{$key}] {$value} ";
+ }
+ throw new RequestException(trim($message), $request);
+ }
+
+ return $resource;
+ }
+
+ /**
+ * Create the stream for the request with the context options.
+ *
+ * @param RequestInterface $request Request being sent
+ * @param mixed $http_response_header Populated by stream wrapper
+ *
+ * @return resource
+ */
+ private function createStream(
+ RequestInterface $request,
+ &$http_response_header
+ ) {
+ static $methods;
+ if (!$methods) {
+ $methods = array_flip(get_class_methods(__CLASS__));
+ }
+
+ $params = [];
+ $options = $this->getDefaultOptions($request);
+ foreach ($request->getConfig()->toArray() as $key => $value) {
+ $method = "add_{$key}";
+ if (isset($methods[$method])) {
+ $this->{$method}($request, $options, $value, $params);
+ }
+ }
+
+ $this->applyCustomOptions($request, $options);
+ $context = $this->createStreamContext($request, $options, $params);
+
+ return $this->createStreamResource(
+ $request,
+ $options,
+ $context,
+ $http_response_header
+ );
+ }
+
+ private function getDefaultOptions(RequestInterface $request)
+ {
+ $headers = '';
+ foreach ($request->getHeaders() as $name => $values) {
+ $headers .= $name . ': ' . implode(', ', $values) . "\r\n";
+ }
+
+ return [
+ 'http' => [
+ 'method' => $request->getMethod(),
+ 'header' => trim($headers),
+ 'protocol_version' => $request->getProtocolVersion(),
+ 'ignore_errors' => true,
+ 'follow_location' => 0,
+ 'content' => (string) $request->getBody()
+ ]
+ ];
+ }
+
+ private function add_proxy(RequestInterface $request, &$options, $value, &$params)
+ {
+ if (!is_array($value)) {
+ $options['http']['proxy'] = $value;
+ $options['http']['request_fulluri'] = true;
+ } else {
+ $scheme = $request->getScheme();
+ if (isset($value[$scheme])) {
+ $options['http']['proxy'] = $value[$scheme];
+ $options['http']['request_fulluri'] = true;
+ }
+ }
+ }
+
+ private function add_timeout(RequestInterface $request, &$options, $value, &$params)
+ {
+ $options['http']['timeout'] = $value;
+ }
+
+ private function add_verify(RequestInterface $request, &$options, $value, &$params)
+ {
+ if ($value === true || is_string($value)) {
+ $options['http']['verify_peer'] = true;
+ if ($value !== true) {
+ if (!file_exists($value)) {
+ throw new \RuntimeException("SSL certificate authority file not found: {$value}");
+ }
+ $options['http']['allow_self_signed'] = true;
+ $options['http']['cafile'] = $value;
+ }
+ } elseif ($value === false) {
+ $options['http']['verify_peer'] = false;
+ }
+ }
+
+ private function add_cert(RequestInterface $request, &$options, $value, &$params)
+ {
+ if (is_array($value)) {
+ $options['http']['passphrase'] = $value[1];
+ $value = $value[0];
+ }
+
+ if (!file_exists($value)) {
+ throw new \RuntimeException("SSL certificate not found: {$value}");
+ }
+
+ $options['http']['local_cert'] = $value;
+ }
+
+ private function add_debug(RequestInterface $request, &$options, $value, &$params)
+ {
+ static $map = [
+ STREAM_NOTIFY_CONNECT => 'CONNECT',
+ STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
+ STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
+ STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
+ STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
+ STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
+ STREAM_NOTIFY_PROGRESS => 'PROGRESS',
+ STREAM_NOTIFY_FAILURE => 'FAILURE',
+ STREAM_NOTIFY_COMPLETED => 'COMPLETED',
+ STREAM_NOTIFY_RESOLVE => 'RESOLVE'
+ ];
+
+ static $args = ['severity', 'message', 'message_code',
+ 'bytes_transferred', 'bytes_max'];
+
+ if (!is_resource($value)) {
+ $value = fopen('php://output', 'w');
+ }
+
+ $params['notification'] = function () use ($request, $value, $map, $args) {
+ $passed = func_get_args();
+ $code = array_shift($passed);
+ fprintf($value, '<%s> [%s] ', $request->getUrl(), $map[$code]);
+ foreach (array_filter($passed) as $i => $v) {
+ fwrite($value, $args[$i] . ': "' . $v . '" ');
+ }
+ fwrite($value, "\n");
+ };
+ }
+
+ private function applyCustomOptions(
+ RequestInterface $request,
+ array &$options
+ ) {
+ // Overwrite any generated options with custom options
+ if ($custom = $request->getConfig()['stream_context']) {
+ if (!is_array($custom)) {
+ throw new AdapterException('stream_context must be an array');
+ }
+ $options = array_replace_recursive($options, $custom);
+ }
+ }
+
+ private function createStreamContext(
+ RequestInterface $request,
+ array $options,
+ array $params
+ ) {
+ return $this->createResource(function () use (
+ $request,
+ $options,
+ $params
+ ) {
+ return stream_context_create($options, $params);
+ }, $request, $options);
+ }
+
+ private function createStreamResource(
+ RequestInterface $request,
+ array $options,
+ $context,
+ &$http_response_header
+ ) {
+ $url = $request->getUrl();
+ // Add automatic gzip decompression
+ if (strpos($request->getHeader('Accept-Encoding'), 'gzip') !== false) {
+ $url = 'compress.zlib://' . $url;
+ }
+
+ return $this->createResource(function () use (
+ $url,
+ &$http_response_header,
+ $context
+ ) {
+ if (false === strpos($url, 'http')) {
+ trigger_error("URL is invalid: {$url}", E_USER_WARNING);
+ return null;
+ }
+ return fopen($url, 'r', null, $context);
+ }, $request, $options);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/StreamingProxyAdapter.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/StreamingProxyAdapter.php
new file mode 100644
index 0000000..128eb1d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/StreamingProxyAdapter.php
@@ -0,0 +1,36 @@
+defaultAdapter = $defaultAdapter;
+ $this->streamingAdapter = $streamingAdapter;
+ }
+
+ public function send(TransactionInterface $transaction)
+ {
+ return $transaction->getRequest()->getConfig()['stream']
+ ? $this->streamingAdapter->send($transaction)
+ : $this->defaultAdapter->send($transaction);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/Transaction.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/Transaction.php
new file mode 100644
index 0000000..74bb6b4
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/Transaction.php
@@ -0,0 +1,49 @@
+client = $client;
+ $this->request = $request;
+ }
+
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ public function setResponse(ResponseInterface $response)
+ {
+ $this->response = $response;
+ }
+
+ public function getClient()
+ {
+ return $this->client;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/TransactionInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/TransactionInterface.php
new file mode 100644
index 0000000..b9bf50c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Adapter/TransactionInterface.php
@@ -0,0 +1,35 @@
+client = $client;
+ $this->eventListeners = $this->prepareListeners(
+ $options,
+ ['before', 'complete', 'error']
+ );
+ if ($source instanceof \Iterator) {
+ $this->source = $source;
+ } elseif (is_array($source)) {
+ $this->source = new \ArrayIterator($source);
+ } else {
+ throw new \InvalidArgumentException('Expected an Iterator or array');
+ }
+ }
+
+ public function current()
+ {
+ $request = $this->source->current();
+ if (!$request instanceof RequestInterface) {
+ throw new \RuntimeException('All must implement RequestInterface');
+ }
+
+ $this->attachListeners($request, $this->eventListeners);
+
+ return new Transaction($this->client, $request);
+ }
+
+ public function next()
+ {
+ $this->source->next();
+ }
+
+ public function key()
+ {
+ return $this->source->key();
+ }
+
+ public function valid()
+ {
+ return $this->source->valid();
+ }
+
+ public function rewind() {}
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Client.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Client.php
new file mode 100644
index 0000000..898157e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Client.php
@@ -0,0 +1,364 @@
+ [
+ * 'http://www.foo.com/{version}/',
+ * ['version' => '123']
+ * ],
+ * 'defaults' => [
+ * 'timeout' => 10,
+ * 'allow_redirects' => false,
+ * 'proxy' => '192.168.16.1:10'
+ * ]
+ * ]);
+ *
+ * @param array $config Client configuration settings
+ * - base_url: Base URL of the client that is merged into relative URLs.
+ * Can be a string or an array that contains a URI template followed
+ * by an associative array of expansion variables to inject into the
+ * URI template.
+ * - adapter: Adapter used to transfer requests
+ * - parallel_adapter: Adapter used to transfer requests in parallel
+ * - message_factory: Factory used to create request and response object
+ * - defaults: Default request options to apply to each request
+ * - emitter: Event emitter used for request events
+ */
+ public function __construct(array $config = [])
+ {
+ $this->configureBaseUrl($config);
+ $this->configureDefaults($config);
+ $this->configureAdapter($config);
+ if (isset($config['emitter'])) {
+ $this->emitter = $config['emitter'];
+ }
+ }
+
+ /**
+ * Get the default User-Agent string to use with Guzzle
+ *
+ * @return string
+ */
+ public static function getDefaultUserAgent()
+ {
+ static $defaultAgent = '';
+ if (!$defaultAgent) {
+ $defaultAgent = 'Guzzle/' . self::VERSION;
+ if (extension_loaded('curl')) {
+ $defaultAgent .= ' curl/' . curl_version()['version'];
+ }
+ $defaultAgent .= ' PHP/' . PHP_VERSION;
+ }
+
+ return $defaultAgent;
+ }
+
+ public function __call($name, $arguments)
+ {
+ return \GuzzleHttp\deprecation_proxy(
+ $this,
+ $name,
+ $arguments,
+ ['getEventDispatcher' => 'getEmitter']
+ );
+ }
+
+ public function getDefaultOption($keyOrPath = null)
+ {
+ return $keyOrPath === null
+ ? $this->defaults
+ : \GuzzleHttp\get_path($this->defaults, $keyOrPath);
+ }
+
+ public function setDefaultOption($keyOrPath, $value)
+ {
+ \GuzzleHttp\set_path($this->defaults, $keyOrPath, $value);
+ }
+
+ public function getBaseUrl()
+ {
+ return (string) $this->baseUrl;
+ }
+
+ public function createRequest($method, $url = null, array $options = [])
+ {
+ // Merge in default options
+ $options = array_replace_recursive($this->defaults, $options);
+
+ // Use a clone of the client's emitter
+ $options['config']['emitter'] = clone $this->getEmitter();
+
+ $request = $this->messageFactory->createRequest(
+ $method,
+ $url ? (string) $this->buildUrl($url) : (string) $this->baseUrl,
+ $options
+ );
+
+ return $request;
+ }
+
+ public function get($url = null, $options = [])
+ {
+ return $this->send($this->createRequest('GET', $url, $options));
+ }
+
+ public function head($url = null, array $options = [])
+ {
+ return $this->send($this->createRequest('HEAD', $url, $options));
+ }
+
+ public function delete($url = null, array $options = [])
+ {
+ return $this->send($this->createRequest('DELETE', $url, $options));
+ }
+
+ public function put($url = null, array $options = [])
+ {
+ return $this->send($this->createRequest('PUT', $url, $options));
+ }
+
+ public function patch($url = null, array $options = [])
+ {
+ return $this->send($this->createRequest('PATCH', $url, $options));
+ }
+
+ public function post($url = null, array $options = [])
+ {
+ return $this->send($this->createRequest('POST', $url, $options));
+ }
+
+ public function options($url = null, array $options = [])
+ {
+ return $this->send($this->createRequest('OPTIONS', $url, $options));
+ }
+
+ public function send(RequestInterface $request)
+ {
+ $transaction = new Transaction($this, $request);
+ try {
+ if ($response = $this->adapter->send($transaction)) {
+ return $response;
+ }
+ throw new \LogicException('No response was associated with the transaction');
+ } catch (RequestException $e) {
+ throw $e;
+ } catch (\Exception $e) {
+ // Wrap exceptions in a RequestException to adhere to the interface
+ throw new RequestException($e->getMessage(), $request, null, $e);
+ }
+ }
+
+ public function sendAll($requests, array $options = [])
+ {
+ if (!($requests instanceof TransactionIterator)) {
+ $requests = new TransactionIterator($requests, $this, $options);
+ }
+
+ $this->parallelAdapter->sendAll(
+ $requests,
+ isset($options['parallel'])
+ ? $options['parallel']
+ : self::DEFAULT_CONCURRENCY
+ );
+ }
+
+ /**
+ * Get an array of default options to apply to the client
+ *
+ * @return array
+ */
+ protected function getDefaultOptions()
+ {
+ $settings = [
+ 'allow_redirects' => true,
+ 'exceptions' => true,
+ 'verify' => __DIR__ . '/cacert.pem'
+ ];
+
+ // Use the bundled cacert if it is a regular file, or set to true if
+ // using a phar file (because curL and the stream wrapper can't read
+ // cacerts from the phar stream wrapper). Favor the ini setting over
+ // the system's cacert.
+ if (substr(__FILE__, 0, 7) == 'phar://') {
+ $settings['verify'] = ini_get('openssl.cafile') ?: true;
+ }
+
+ // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set
+ if (isset($_SERVER['HTTP_PROXY'])) {
+ $settings['proxy']['http'] = $_SERVER['HTTP_PROXY'];
+ }
+
+ if (isset($_SERVER['HTTPS_PROXY'])) {
+ $settings['proxy']['https'] = $_SERVER['HTTPS_PROXY'];
+ }
+
+ return $settings;
+ }
+
+ /**
+ * Expand a URI template and inherit from the base URL if it's relative
+ *
+ * @param string|array $url URL or URI template to expand
+ *
+ * @return string
+ */
+ private function buildUrl($url)
+ {
+ if (!is_array($url)) {
+ if (strpos($url, '://')) {
+ return (string) $url;
+ }
+ return (string) $this->baseUrl->combine($url);
+ } elseif (strpos($url[0], '://')) {
+ return \GuzzleHttp\uri_template($url[0], $url[1]);
+ }
+
+ return (string) $this->baseUrl->combine(
+ \GuzzleHttp\uri_template($url[0], $url[1])
+ );
+ }
+
+ /**
+ * Get a default parallel adapter to use based on the environment
+ *
+ * @return ParallelAdapterInterface
+ */
+ private function getDefaultParallelAdapter()
+ {
+ return extension_loaded('curl')
+ ? new MultiAdapter($this->messageFactory)
+ : new FakeParallelAdapter($this->adapter);
+ }
+
+ /**
+ * Create a default adapter to use based on the environment
+ * @throws \RuntimeException
+ */
+ private function getDefaultAdapter()
+ {
+ if (extension_loaded('curl')) {
+ $this->parallelAdapter = new MultiAdapter($this->messageFactory);
+ $this->adapter = function_exists('curl_reset')
+ ? new CurlAdapter($this->messageFactory)
+ : $this->parallelAdapter;
+ if (ini_get('allow_url_fopen')) {
+ $this->adapter = new StreamingProxyAdapter(
+ $this->adapter,
+ new StreamAdapter($this->messageFactory)
+ );
+ }
+ } elseif (ini_get('allow_url_fopen')) {
+ $this->adapter = new StreamAdapter($this->messageFactory);
+ } else {
+ throw new \RuntimeException('Guzzle requires cURL, the '
+ . 'allow_url_fopen ini setting, or a custom HTTP adapter.');
+ }
+ }
+
+ private function configureBaseUrl(&$config)
+ {
+ if (!isset($config['base_url'])) {
+ $this->baseUrl = new Url('', '');
+ } elseif (is_array($config['base_url'])) {
+ $this->baseUrl = Url::fromString(
+ \GuzzleHttp\uri_template(
+ $config['base_url'][0],
+ $config['base_url'][1]
+ )
+ );
+ $config['base_url'] = (string) $this->baseUrl;
+ } else {
+ $this->baseUrl = Url::fromString($config['base_url']);
+ }
+ }
+
+ private function configureDefaults($config)
+ {
+ if (!isset($config['defaults'])) {
+ $this->defaults = $this->getDefaultOptions();
+ } else {
+ $this->defaults = array_replace(
+ $this->getDefaultOptions(),
+ $config['defaults']
+ );
+ }
+
+ // Add the default user-agent header
+ if (!isset($this->defaults['headers'])) {
+ $this->defaults['headers'] = [
+ 'User-Agent' => static::getDefaultUserAgent()
+ ];
+ } elseif (!isset(array_change_key_case($this->defaults['headers'])['user-agent'])) {
+ // Add the User-Agent header if one was not already set
+ $this->defaults['headers']['User-Agent'] = static::getDefaultUserAgent();
+ }
+ }
+
+ private function configureAdapter(&$config)
+ {
+ if (isset($config['message_factory'])) {
+ $this->messageFactory = $config['message_factory'];
+ } else {
+ $this->messageFactory = new MessageFactory();
+ }
+ if (isset($config['adapter'])) {
+ $this->adapter = $config['adapter'];
+ } else {
+ $this->getDefaultAdapter();
+ }
+ // If no parallel adapter was explicitly provided and one was not
+ // defaulted when creating the default adapter, then create one now.
+ if (isset($config['parallel_adapter'])) {
+ $this->parallelAdapter = $config['parallel_adapter'];
+ } elseif (!$this->parallelAdapter) {
+ $this->parallelAdapter = $this->getDefaultParallelAdapter();
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/ClientInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/ClientInterface.php
new file mode 100644
index 0000000..b0e4cba
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/ClientInterface.php
@@ -0,0 +1,179 @@
+data = $data;
+ }
+
+ /**
+ * Create a new collection from an array, validate the keys, and add default
+ * values where missing
+ *
+ * @param array $config Configuration values to apply.
+ * @param array $defaults Default parameters
+ * @param array $required Required parameter names
+ *
+ * @return self
+ * @throws \InvalidArgumentException if a parameter is missing
+ */
+ public static function fromConfig(
+ array $config = [],
+ array $defaults = [],
+ array $required = []
+ ) {
+ $data = $config + $defaults;
+
+ if ($missing = array_diff($required, array_keys($data))) {
+ throw new \InvalidArgumentException(
+ 'Config is missing the following keys: ' .
+ implode(', ', $missing));
+ }
+
+ return new self($data);
+ }
+
+ /**
+ * Removes all key value pairs
+ *
+ * @return Collection
+ */
+ public function clear()
+ {
+ $this->data = [];
+
+ return $this;
+ }
+
+ /**
+ * Get a specific key value.
+ *
+ * @param string $key Key to retrieve.
+ *
+ * @return mixed|null Value of the key or NULL
+ */
+ public function get($key)
+ {
+ return isset($this->data[$key]) ? $this->data[$key] : null;
+ }
+
+ /**
+ * Set a key value pair
+ *
+ * @param string $key Key to set
+ * @param mixed $value Value to set
+ *
+ * @return Collection Returns a reference to the object
+ */
+ public function set($key, $value)
+ {
+ $this->data[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Add a value to a key. If a key of the same name has already been added,
+ * the key value will be converted into an array and the new value will be
+ * pushed to the end of the array.
+ *
+ * @param string $key Key to add
+ * @param mixed $value Value to add to the key
+ *
+ * @return Collection Returns a reference to the object.
+ */
+ public function add($key, $value)
+ {
+ if (!array_key_exists($key, $this->data)) {
+ $this->data[$key] = $value;
+ } elseif (is_array($this->data[$key])) {
+ $this->data[$key][] = $value;
+ } else {
+ $this->data[$key] = array($this->data[$key], $value);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Remove a specific key value pair
+ *
+ * @param string $key A key to remove
+ *
+ * @return Collection
+ */
+ public function remove($key)
+ {
+ unset($this->data[$key]);
+
+ return $this;
+ }
+
+ /**
+ * Get all keys in the collection
+ *
+ * @return array
+ */
+ public function getKeys()
+ {
+ return array_keys($this->data);
+ }
+
+ /**
+ * Returns whether or not the specified key is present.
+ *
+ * @param string $key The key for which to check the existence.
+ *
+ * @return bool
+ */
+ public function hasKey($key)
+ {
+ return array_key_exists($key, $this->data);
+ }
+
+ /**
+ * Checks if any keys contains a certain value
+ *
+ * @param string $value Value to search for
+ *
+ * @return mixed Returns the key if the value was found FALSE if the value
+ * was not found.
+ */
+ public function hasValue($value)
+ {
+ return array_search($value, $this->data, true);
+ }
+
+ /**
+ * Replace the data of the object with the value of an array
+ *
+ * @param array $data Associative array of data
+ *
+ * @return Collection Returns a reference to the object
+ */
+ public function replace(array $data)
+ {
+ $this->data = $data;
+
+ return $this;
+ }
+
+ /**
+ * Add and merge in a Collection or array of key value pair data.
+ *
+ * @param Collection|array $data Associative array of key value pair data
+ *
+ * @return Collection Returns a reference to the object.
+ */
+ public function merge($data)
+ {
+ foreach ($data as $key => $value) {
+ $this->add($key, $value);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Over write key value pairs in this collection with all of the data from
+ * an array or collection.
+ *
+ * @param array|\Traversable $data Values to override over this config
+ *
+ * @return self
+ */
+ public function overwriteWith($data)
+ {
+ if (is_array($data)) {
+ $this->data = $data + $this->data;
+ } elseif ($data instanceof Collection) {
+ $this->data = $data->toArray() + $this->data;
+ } else {
+ foreach ($data as $key => $value) {
+ $this->data[$key] = $value;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Returns a Collection containing all the elements of the collection after
+ * applying the callback function to each one.
+ *
+ * The callable should accept three arguments:
+ * - (string) $key
+ * - (string) $value
+ * - (array) $context
+ *
+ * The callable must return a the altered or unaltered value.
+ *
+ * @param callable $closure Map function to apply
+ * @param array $context Context to pass to the callable
+ *
+ * @return Collection
+ */
+ public function map(callable $closure, array $context = [])
+ {
+ $collection = new static();
+ foreach ($this as $key => $value) {
+ $collection[$key] = $closure($key, $value, $context);
+ }
+
+ return $collection;
+ }
+
+ /**
+ * Iterates over each key value pair in the collection passing them to the
+ * callable. If the callable returns true, the current value from input is
+ * returned into the result Collection.
+ *
+ * The callable must accept two arguments:
+ * - (string) $key
+ * - (string) $value
+ *
+ * @param callable $closure Evaluation function
+ *
+ * @return Collection
+ */
+ public function filter(callable $closure)
+ {
+ $collection = new static();
+ foreach ($this->data as $key => $value) {
+ if ($closure($key, $value)) {
+ $collection[$key] = $value;
+ }
+ }
+
+ return $collection;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Cookie/CookieJar.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Cookie/CookieJar.php
new file mode 100644
index 0000000..4134857
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Cookie/CookieJar.php
@@ -0,0 +1,249 @@
+strictMode = $strictMode;
+
+ foreach ($cookieArray as $cookie) {
+ if (!($cookieArray instanceof SetCookie)) {
+ $cookie = new SetCookie($cookie);
+ }
+ $this->setCookie($cookie);
+ }
+ }
+
+ /**
+ * Create a new Cookie jar from an associative array and domain.
+ *
+ * @param array $cookies Cookies to create the jar from
+ * @param string $domain Domain to set the cookies to
+ *
+ * @return self
+ */
+ public static function fromArray(array $cookies, $domain)
+ {
+ $cookieJar = new self();
+ foreach ($cookies as $name => $value) {
+ $cookieJar->setCookie(new SetCookie([
+ 'Domain' => $domain,
+ 'Name' => $name,
+ 'Value' => $value,
+ 'Discard' => true
+ ]));
+ }
+
+ return $cookieJar;
+ }
+
+ /**
+ * Quote the cookie value if it is not already quoted and it contains
+ * problematic characters.
+ *
+ * @param string $value Value that may or may not need to be quoted
+ *
+ * @return string
+ */
+ public static function getCookieValue($value)
+ {
+ if (substr($value, 0, 1) !== '"' &&
+ substr($value, -1, 1) !== '"' &&
+ strpbrk($value, ';,')
+ ) {
+ $value = '"' . $value . '"';
+ }
+
+ return $value;
+ }
+
+ public function toArray()
+ {
+ return array_map(function (SetCookie $cookie) {
+ return $cookie->toArray();
+ }, $this->getIterator()->getArrayCopy());
+ }
+
+ public function clear($domain = null, $path = null, $name = null)
+ {
+ if (!$domain) {
+ $this->cookies = [];
+ return;
+ } elseif (!$path) {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) use ($path, $domain) {
+ return !$cookie->matchesDomain($domain);
+ }
+ );
+ } elseif (!$name) {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) use ($path, $domain) {
+ return !($cookie->matchesPath($path) &&
+ $cookie->matchesDomain($domain));
+ }
+ );
+ } else {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) use ($path, $domain, $name) {
+ return !($cookie->getName() == $name &&
+ $cookie->matchesPath($path) &&
+ $cookie->matchesDomain($domain));
+ }
+ );
+ }
+ }
+
+ public function clearSessionCookies()
+ {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) {
+ return !$cookie->getDiscard() && $cookie->getExpires();
+ }
+ );
+ }
+
+ public function setCookie(SetCookie $cookie)
+ {
+ // Only allow cookies with set and valid domain, name, value
+ $result = $cookie->validate();
+ if ($result !== true) {
+ if ($this->strictMode) {
+ throw new \RuntimeException('Invalid cookie: ' . $result);
+ } else {
+ $this->removeCookieIfEmpty($cookie);
+ return false;
+ }
+ }
+
+ // Resolve conflicts with previously set cookies
+ foreach ($this->cookies as $i => $c) {
+
+ // Two cookies are identical, when their path, and domain are
+ // identical.
+ if ($c->getPath() != $cookie->getPath() ||
+ $c->getDomain() != $cookie->getDomain() ||
+ $c->getName() != $cookie->getName()
+ ) {
+ continue;
+ }
+
+ // The previously set cookie is a discard cookie and this one is
+ // not so allow the new cookie to be set
+ if (!$cookie->getDiscard() && $c->getDiscard()) {
+ unset($this->cookies[$i]);
+ continue;
+ }
+
+ // If the new cookie's expiration is further into the future, then
+ // replace the old cookie
+ if ($cookie->getExpires() > $c->getExpires()) {
+ unset($this->cookies[$i]);
+ continue;
+ }
+
+ // If the value has changed, we better change it
+ if ($cookie->getValue() !== $c->getValue()) {
+ unset($this->cookies[$i]);
+ continue;
+ }
+
+ // The cookie exists, so no need to continue
+ return false;
+ }
+
+ $this->cookies[] = $cookie;
+
+ return true;
+ }
+
+ public function count()
+ {
+ return count($this->cookies);
+ }
+
+ public function getIterator()
+ {
+ return new \ArrayIterator(array_values($this->cookies));
+ }
+
+ public function extractCookies(
+ RequestInterface $request,
+ ResponseInterface $response
+ ) {
+ if ($cookieHeader = $response->getHeader('Set-Cookie', true)) {
+ foreach ($cookieHeader as $cookie) {
+ $sc = SetCookie::fromString($cookie);
+ if (!$sc->getDomain()) {
+ $sc->setDomain($request->getHost());
+ }
+ $this->setCookie($sc);
+ }
+ }
+ }
+
+ public function addCookieHeader(RequestInterface $request)
+ {
+ $values = [];
+ $scheme = $request->getScheme();
+ $host = $request->getHost();
+ $path = $request->getPath();
+
+ foreach ($this->cookies as $cookie) {
+ if ($cookie->matchesPath($path) &&
+ $cookie->matchesDomain($host) &&
+ !$cookie->isExpired() &&
+ (!$cookie->getSecure() || $scheme == 'https')
+ ) {
+ $values[] = $cookie->getName() . '='
+ . self::getCookieValue($cookie->getValue());
+ }
+ }
+
+ if ($values) {
+ $request->setHeader('Cookie', implode(';', $values));
+ }
+ }
+
+ /**
+ * If a cookie already exists and the server asks to set it again with a
+ * null value, the cookie must be deleted.
+ *
+ * @param SetCookie $cookie
+ */
+ private function removeCookieIfEmpty(SetCookie $cookie)
+ {
+ $cookieValue = $cookie->getValue();
+ if ($cookieValue === null || $cookieValue === '') {
+ $this->clear(
+ $cookie->getDomain(),
+ $cookie->getPath(),
+ $cookie->getName()
+ );
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Cookie/CookieJarInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Cookie/CookieJarInterface.php
new file mode 100644
index 0000000..6cafce8
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Cookie/CookieJarInterface.php
@@ -0,0 +1,76 @@
+filename = $cookieFile;
+
+ if (file_exists($cookieFile)) {
+ $this->load($cookieFile);
+ }
+ }
+
+ /**
+ * Saves the file when shutting down
+ */
+ public function __destruct()
+ {
+ $this->save($this->filename);
+ }
+
+ /**
+ * Saves the cookies to a file.
+ *
+ * @param string $filename File to save
+ * @throws \RuntimeException if the file cannot be found or created
+ */
+ public function save($filename)
+ {
+ $json = [];
+ foreach ($this as $cookie) {
+ if ($cookie->getExpires() && !$cookie->getDiscard()) {
+ $json[] = $cookie->toArray();
+ }
+ }
+
+ if (false === file_put_contents($filename, json_encode($json))) {
+ // @codeCoverageIgnoreStart
+ throw new \RuntimeException("Unable to save file {$filename}");
+ // @codeCoverageIgnoreEnd
+ }
+ }
+
+ /**
+ * Load cookies from a JSON formatted file.
+ *
+ * Old cookies are kept unless overwritten by newly loaded ones.
+ *
+ * @param string $filename Cookie file to load.
+ * @throws \RuntimeException if the file cannot be loaded.
+ */
+ public function load($filename)
+ {
+ $json = file_get_contents($filename);
+ if (false === $json) {
+ // @codeCoverageIgnoreStart
+ throw new \RuntimeException("Unable to load file {$filename}");
+ // @codeCoverageIgnoreEnd
+ }
+
+ $data = \GuzzleHttp\json_decode($json, true);
+ if (is_array($data)) {
+ foreach (\GuzzleHttp\json_decode($json, true) as $cookie) {
+ $this->setCookie(new SetCookie($cookie));
+ }
+ } elseif (strlen($data)) {
+ throw new \RuntimeException("Invalid cookie file: {$filename}");
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Cookie/SessionCookieJar.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Cookie/SessionCookieJar.php
new file mode 100644
index 0000000..2f708d7
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Cookie/SessionCookieJar.php
@@ -0,0 +1,65 @@
+sessionKey = $sessionKey;
+ $this->load();
+ }
+
+ /**
+ * Saves cookies to session when shutting down
+ */
+ public function __destruct()
+ {
+ $this->save();
+ }
+
+ /**
+ * Save cookies to the client session
+ */
+ public function save()
+ {
+ $json = [];
+ foreach ($this as $cookie) {
+ if ($cookie->getExpires() && !$cookie->getDiscard()) {
+ $json[] = $cookie->toArray();
+ }
+ }
+
+ $_SESSION[$this->sessionKey] = json_encode($json);
+ }
+
+ /**
+ * Load the contents of the client session into the data array
+ */
+ protected function load()
+ {
+ $cookieJar = isset($_SESSION[$this->sessionKey])
+ ? $_SESSION[$this->sessionKey]
+ : null;
+
+ $data = \GuzzleHttp\json_decode($cookieJar, true);
+ if (is_array($data)) {
+ foreach ($data as $cookie) {
+ $this->setCookie(new SetCookie($cookie));
+ }
+ } elseif (strlen($data)) {
+ throw new \RuntimeException("Invalid cookie data");
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Cookie/SetCookie.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Cookie/SetCookie.php
new file mode 100644
index 0000000..76f6f8d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Cookie/SetCookie.php
@@ -0,0 +1,410 @@
+ null,
+ 'Value' => null,
+ 'Domain' => null,
+ 'Path' => '/',
+ 'Max-Age' => null,
+ 'Expires' => null,
+ 'Secure' => false,
+ 'Discard' => false,
+ 'HttpOnly' => false
+ ];
+
+ /** @var array Cookie data */
+ private $data;
+
+ /**
+ * Create a new SetCookie object from a string
+ *
+ * @param string $cookie Set-Cookie header string
+ *
+ * @return self
+ */
+ public static function fromString($cookie)
+ {
+ // Create the default return array
+ $data = self::$defaults;
+ // Explode the cookie string using a series of semicolons
+ $pieces = array_filter(array_map('trim', explode(';', $cookie)));
+ // The name of the cookie (first kvp) must include an equal sign.
+ if (empty($pieces) || !strpos($pieces[0], '=')) {
+ return new self($data);
+ }
+
+ // Add the cookie pieces into the parsed data array
+ foreach ($pieces as $part) {
+
+ $cookieParts = explode('=', $part, 2);
+ $key = trim($cookieParts[0]);
+ $value = isset($cookieParts[1])
+ ? trim($cookieParts[1], " \n\r\t\0\x0B\"")
+ : true;
+
+ // Only check for non-cookies when cookies have been found
+ if (empty($data['Name'])) {
+ $data['Name'] = $key;
+ $data['Value'] = $value;
+ } else {
+ foreach (array_keys(self::$defaults) as $search) {
+ if (!strcasecmp($search, $key)) {
+ $data[$search] = $value;
+ continue 2;
+ }
+ }
+ $data[$key] = $value;
+ }
+ }
+
+ return new self($data);
+ }
+
+ /**
+ * @param array $data Array of cookie data provided by a Cookie parser
+ */
+ public function __construct(array $data = [])
+ {
+ $this->data = array_replace(self::$defaults, $data);
+ // Extract the Expires value and turn it into a UNIX timestamp if needed
+ if (!$this->getExpires() && $this->getMaxAge()) {
+ // Calculate the Expires date
+ $this->setExpires(time() + $this->getMaxAge());
+ } elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
+ $this->setExpires($this->getExpires());
+ }
+ }
+
+ public function __toString()
+ {
+ $str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
+ foreach ($this->data as $k => $v) {
+ if ($k != 'Name' && $k != 'Value'&& $v !== null && $v !== false) {
+ if ($k == 'Expires') {
+ $str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
+ } else {
+ $str .= ($v === true ? $k : "{$k}={$v}") . '; ';
+ }
+ }
+ }
+
+ return rtrim($str, '; ');
+ }
+
+ public function toArray()
+ {
+ return $this->data;
+ }
+
+ /**
+ * Get the cookie name
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->data['Name'];
+ }
+
+ /**
+ * Set the cookie name
+ *
+ * @param string $name Cookie name
+ *
+ * @return self
+ */
+ public function setName($name)
+ {
+ $this->data['Name'] = $name;
+
+ return $this;
+ }
+
+ /**
+ * Get the cookie value
+ *
+ * @return string
+ */
+ public function getValue()
+ {
+ return $this->data['Value'];
+ }
+
+ /**
+ * Set the cookie value
+ *
+ * @param string $value Cookie value
+ *
+ * @return self
+ */
+ public function setValue($value)
+ {
+ $this->data['Value'] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get the domain
+ *
+ * @return string|null
+ */
+ public function getDomain()
+ {
+ return $this->data['Domain'];
+ }
+
+ /**
+ * Set the domain of the cookie
+ *
+ * @param string $domain
+ *
+ * @return self
+ */
+ public function setDomain($domain)
+ {
+ $this->data['Domain'] = $domain;
+
+ return $this;
+ }
+
+ /**
+ * Get the path
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->data['Path'];
+ }
+
+ /**
+ * Set the path of the cookie
+ *
+ * @param string $path Path of the cookie
+ *
+ * @return self
+ */
+ public function setPath($path)
+ {
+ $this->data['Path'] = $path;
+
+ return $this;
+ }
+
+ /**
+ * Maximum lifetime of the cookie in seconds
+ *
+ * @return int|null
+ */
+ public function getMaxAge()
+ {
+ return $this->data['Max-Age'];
+ }
+
+ /**
+ * Set the max-age of the cookie
+ *
+ * @param int $maxAge Max age of the cookie in seconds
+ *
+ * @return self
+ */
+ public function setMaxAge($maxAge)
+ {
+ $this->data['Max-Age'] = $maxAge;
+
+ return $this;
+ }
+
+ /**
+ * The UNIX timestamp when the cookie Expires
+ *
+ * @return mixed
+ */
+ public function getExpires()
+ {
+ return $this->data['Expires'];
+ }
+
+ /**
+ * Set the unix timestamp for which the cookie will expire
+ *
+ * @param int $timestamp Unix timestamp
+ *
+ * @return self
+ */
+ public function setExpires($timestamp)
+ {
+ $this->data['Expires'] = is_numeric($timestamp)
+ ? (int) $timestamp
+ : strtotime($timestamp);
+
+ return $this;
+ }
+
+ /**
+ * Get whether or not this is a secure cookie
+ *
+ * @return null|bool
+ */
+ public function getSecure()
+ {
+ return $this->data['Secure'];
+ }
+
+ /**
+ * Set whether or not the cookie is secure
+ *
+ * @param bool $secure Set to true or false if secure
+ *
+ * @return self
+ */
+ public function setSecure($secure)
+ {
+ $this->data['Secure'] = $secure;
+
+ return $this;
+ }
+
+ /**
+ * Get whether or not this is a session cookie
+ *
+ * @return null|bool
+ */
+ public function getDiscard()
+ {
+ return $this->data['Discard'];
+ }
+
+ /**
+ * Set whether or not this is a session cookie
+ *
+ * @param bool $discard Set to true or false if this is a session cookie
+ *
+ * @return self
+ */
+ public function setDiscard($discard)
+ {
+ $this->data['Discard'] = $discard;
+
+ return $this;
+ }
+
+ /**
+ * Get whether or not this is an HTTP only cookie
+ *
+ * @return bool
+ */
+ public function getHttpOnly()
+ {
+ return $this->data['HttpOnly'];
+ }
+
+ /**
+ * Set whether or not this is an HTTP only cookie
+ *
+ * @param bool $httpOnly Set to true or false if this is HTTP only
+ *
+ * @return self
+ */
+ public function setHttpOnly($httpOnly)
+ {
+ $this->data['HttpOnly'] = $httpOnly;
+
+ return $this;
+ }
+
+ /**
+ * Check if the cookie matches a path value
+ *
+ * @param string $path Path to check against
+ *
+ * @return bool
+ */
+ public function matchesPath($path)
+ {
+ return !$this->getPath() || 0 === stripos($path, $this->getPath());
+ }
+
+ /**
+ * Check if the cookie matches a domain value
+ *
+ * @param string $domain Domain to check against
+ *
+ * @return bool
+ */
+ public function matchesDomain($domain)
+ {
+ // Remove the leading '.' as per spec in RFC 6265.
+ // http://tools.ietf.org/html/rfc6265#section-5.2.3
+ $cookieDomain = ltrim($this->getDomain(), '.');
+
+ // Domain not set or exact match.
+ if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
+ return true;
+ }
+
+ // Matching the subdomain according to RFC 6265.
+ // http://tools.ietf.org/html/rfc6265#section-5.1.3
+ if (filter_var($domain, FILTER_VALIDATE_IP)) {
+ return false;
+ }
+
+ return (bool) preg_match('/\.' . preg_quote($cookieDomain) . '$/i', $domain);
+ }
+
+ /**
+ * Check if the cookie is expired
+ *
+ * @return bool
+ */
+ public function isExpired()
+ {
+ return $this->getExpires() && time() > $this->getExpires();
+ }
+
+ /**
+ * Check if the cookie is valid according to RFC 6265
+ *
+ * @return bool|string Returns true if valid or an error message if invalid
+ */
+ public function validate()
+ {
+ // Names must not be empty, but can be 0
+ $name = $this->getName();
+ if (empty($name) && !is_numeric($name)) {
+ return 'The cookie name must not be empty';
+ }
+
+ // Check if any of the invalid characters are present in the cookie name
+ if (preg_match("/[=,; \t\r\n\013\014]/", $name)) {
+ return "Cookie name must not cannot invalid characters: =,; \\t\\r\\n\\013\\014";
+ }
+
+ // Value must not be empty, but can be 0
+ $value = $this->getValue();
+ if (empty($value) && !is_numeric($value)) {
+ return 'The cookie value must not be empty';
+ }
+
+ // Domains must not be empty, but can be 0
+ // A "0" is not a valid internet domain, but may be used as server name
+ // in a private network.
+ $domain = $this->getDomain();
+ if (empty($domain) && !is_numeric($domain)) {
+ return 'The cookie domain must not be empty';
+ }
+
+ return true;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/AbstractEvent.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/AbstractEvent.php
new file mode 100644
index 0000000..fa1453c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/AbstractEvent.php
@@ -0,0 +1,21 @@
+propagationStopped;
+ }
+
+ public function stopPropagation()
+ {
+ $this->propagationStopped = true;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/AbstractRequestEvent.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/AbstractRequestEvent.php
new file mode 100644
index 0000000..d188248
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/AbstractRequestEvent.php
@@ -0,0 +1,49 @@
+transaction = $transaction;
+ }
+
+ /**
+ * Get the client associated with the event
+ *
+ * @return ClientInterface
+ */
+ public function getClient()
+ {
+ return $this->transaction->getClient();
+ }
+
+ /**
+ * Get the request object
+ *
+ * @return RequestInterface
+ */
+ public function getRequest()
+ {
+ return $this->transaction->getRequest();
+ }
+
+ /**
+ * @return TransactionInterface
+ */
+ protected function getTransaction()
+ {
+ return $this->transaction;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/AbstractTransferEvent.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/AbstractTransferEvent.php
new file mode 100644
index 0000000..dba1f98
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/AbstractTransferEvent.php
@@ -0,0 +1,83 @@
+transferInfo = $transferInfo;
+ }
+
+ /**
+ * Get all transfer information as an associative array if no $name
+ * argument is supplied, or gets a specific transfer statistic if
+ * a $name attribute is supplied (e.g., 'total_time').
+ *
+ * @param string $name Name of the transfer stat to retrieve
+ *
+ * @return mixed|null|array
+ */
+ public function getTransferInfo($name = null)
+ {
+ if (!$name) {
+ return $this->transferInfo;
+ }
+
+ return isset($this->transferInfo[$name])
+ ? $this->transferInfo[$name]
+ : null;
+ }
+
+ /**
+ * Get the response
+ *
+ * @return ResponseInterface|null
+ */
+ abstract public function getResponse();
+
+ /**
+ * Intercept the request and associate a response
+ *
+ * @param ResponseInterface $response Response to set
+ */
+ abstract public function intercept(ResponseInterface $response);
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/BeforeEvent.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/BeforeEvent.php
new file mode 100644
index 0000000..34a7811
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/BeforeEvent.php
@@ -0,0 +1,26 @@
+getTransaction()->setResponse($response);
+ $this->stopPropagation();
+ RequestEvents::emitComplete($this->getTransaction());
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/CompleteEvent.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/CompleteEvent.php
new file mode 100644
index 0000000..3445760
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/CompleteEvent.php
@@ -0,0 +1,35 @@
+stopPropagation();
+ $this->getTransaction()->setResponse($response);
+ }
+
+ /**
+ * Get the response of the request
+ *
+ * @return ResponseInterface
+ */
+ public function getResponse()
+ {
+ return $this->getTransaction()->getResponse();
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/Emitter.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/Emitter.php
new file mode 100644
index 0000000..49172bc
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/Emitter.php
@@ -0,0 +1,147 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @link https://github.com/symfony/symfony/tree/master/src/Symfony/Component/EventDispatcher
+ */
+class Emitter implements EmitterInterface
+{
+ /** @var array */
+ private $listeners = [];
+
+ /** @var array */
+ private $sorted = [];
+
+ public function on($eventName, callable $listener, $priority = 0)
+ {
+ if ($priority === 'first') {
+ $priority = isset($this->listeners[$eventName])
+ ? max(array_keys($this->listeners[$eventName])) + 1
+ : 1;
+ } elseif ($priority === 'last') {
+ $priority = isset($this->listeners[$eventName])
+ ? min(array_keys($this->listeners[$eventName])) - 1
+ : -1;
+ }
+
+ $this->listeners[$eventName][$priority][] = $listener;
+ unset($this->sorted[$eventName]);
+ }
+
+ public function once($eventName, callable $listener, $priority = 0)
+ {
+ $onceListener = function (
+ EventInterface $event,
+ $eventName
+ ) use (&$onceListener, $eventName, $listener, $priority) {
+ $this->removeListener($eventName, $onceListener);
+ $listener($event, $eventName, $this);
+ };
+
+ $this->on($eventName, $onceListener, $priority);
+ }
+
+ public function removeListener($eventName, callable $listener)
+ {
+ if (!isset($this->listeners[$eventName])) {
+ return;
+ }
+
+ foreach ($this->listeners[$eventName] as $priority => $listeners) {
+ if (false !== ($key = array_search($listener, $listeners, true))) {
+ unset(
+ $this->listeners[$eventName][$priority][$key],
+ $this->sorted[$eventName]
+ );
+ }
+ }
+ }
+
+ public function listeners($eventName = null)
+ {
+ // Return all events in a sorted priority order
+ if ($eventName === null) {
+ foreach (array_keys($this->listeners) as $eventName) {
+ if (!isset($this->sorted[$eventName])) {
+ $this->listeners($eventName);
+ }
+ }
+ return $this->sorted;
+ }
+
+ // Return the listeners for a specific event, sorted in priority order
+ if (!isset($this->sorted[$eventName])) {
+ if (!isset($this->listeners[$eventName])) {
+ return [];
+ } else {
+ krsort($this->listeners[$eventName]);
+ $this->sorted[$eventName] = call_user_func_array(
+ 'array_merge',
+ $this->listeners[$eventName]
+ );
+ }
+ }
+
+ return $this->sorted[$eventName];
+ }
+
+ public function emit($eventName, EventInterface $event)
+ {
+ if (isset($this->listeners[$eventName])) {
+ foreach ($this->listeners($eventName) as $listener) {
+ $listener($event, $eventName);
+ if ($event->isPropagationStopped()) {
+ break;
+ }
+ }
+ }
+
+ return $event;
+ }
+
+ public function attach(SubscriberInterface $subscriber)
+ {
+ foreach ($subscriber->getEvents() as $eventName => $listener) {
+ $this->on(
+ $eventName,
+ array($subscriber, $listener[0]),
+ isset($listener[1]) ? $listener[1] : 0
+ );
+ }
+ }
+
+ public function detach(SubscriberInterface $subscriber)
+ {
+ foreach ($subscriber->getEvents() as $eventName => $listener) {
+ $this->removeListener($eventName, array($subscriber, $listener[0]));
+ }
+ }
+
+ public function __call($name, $arguments)
+ {
+ return \GuzzleHttp\deprecation_proxy(
+ $this,
+ $name,
+ $arguments,
+ [
+ 'addSubscriber' => 'attach',
+ 'removeSubscriber' => 'detach',
+ 'addListener' => 'on',
+ 'dispatch' => 'emit'
+ ]
+ );
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/EmitterInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/EmitterInterface.php
new file mode 100644
index 0000000..0181e7f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/EmitterInterface.php
@@ -0,0 +1,88 @@
+exception = $e;
+ }
+
+ /**
+ * Intercept the exception and inject a response
+ *
+ * @param ResponseInterface $response Response to set
+ */
+ public function intercept(ResponseInterface $response)
+ {
+ $this->stopPropagation();
+ $this->getTransaction()->setResponse($response);
+ RequestEvents::emitComplete($this->getTransaction());
+ }
+
+ /**
+ * Get the exception that was encountered
+ *
+ * @return RequestException
+ */
+ public function getException()
+ {
+ return $this->exception;
+ }
+
+ /**
+ * Get the response the was received (if any)
+ *
+ * @return ResponseInterface|null
+ */
+ public function getResponse()
+ {
+ return $this->getException()->getResponse();
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/EventInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/EventInterface.php
new file mode 100644
index 0000000..bf58f8b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/EventInterface.php
@@ -0,0 +1,24 @@
+emitter) {
+ $this->emitter = new Emitter();
+ }
+
+ return $this->emitter;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/HeadersEvent.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/HeadersEvent.php
new file mode 100644
index 0000000..81274ff
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/HeadersEvent.php
@@ -0,0 +1,39 @@
+getResponse()) {
+ throw new \RuntimeException('A response must be present');
+ }
+ }
+
+ /**
+ * Get the response the was received
+ *
+ * @return ResponseInterface
+ */
+ public function getResponse()
+ {
+ return $this->getTransaction()->getResponse();
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/ListenerAttacherTrait.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/ListenerAttacherTrait.php
new file mode 100644
index 0000000..637cdae
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/ListenerAttacherTrait.php
@@ -0,0 +1,89 @@
+getEmitter();
+ foreach ($listeners as $el) {
+ if ($el['once']) {
+ $emitter->once($el['name'], $el['fn'], $el['priority']);
+ } else {
+ $emitter->on($el['name'], $el['fn'], $el['priority']);
+ }
+ }
+ }
+
+ /**
+ * Extracts the allowed events from the provided array, and ignores anything
+ * else in the array. The event listener must be specified as a callable or
+ * as an array of event listener data ("name", "fn", "priority", "once").
+ *
+ * @param array $source Array containing callables or hashes of data to be
+ * prepared as event listeners.
+ * @param array $events Names of events to look for in the provided $source
+ * array. Other keys are ignored.
+ * @return array
+ */
+ private function prepareListeners(array $source, array $events)
+ {
+ $listeners = [];
+ foreach ($events as $name) {
+ if (isset($source[$name])) {
+ $this->buildListener($name, $source[$name], $listeners);
+ }
+ }
+
+ return $listeners;
+ }
+
+ /**
+ * Creates a complete event listener definition from the provided array of
+ * listener data. Also works recursively if more than one listeners are
+ * contained in the provided array.
+ *
+ * @param string $name Name of the event the listener is for.
+ * @param array|callable $data Event listener data to prepare.
+ * @param array $listeners Array of listeners, passed by reference.
+ *
+ * @throws \InvalidArgumentException if the event data is malformed.
+ */
+ private function buildListener($name, $data, &$listeners)
+ {
+ static $defaults = ['priority' => 0, 'once' => false];
+
+ // If a callable is provided, normalize it to the array format.
+ if (is_callable($data)) {
+ $data = ['fn' => $data];
+ }
+
+ // Prepare the listener and add it to the array, recursively.
+ if (isset($data['fn'])) {
+ $data['name'] = $name;
+ $listeners[] = $data + $defaults;
+ } elseif (is_array($data)) {
+ foreach ($data as $listenerData) {
+ $this->buildListener($name, $listenerData, $listeners);
+ }
+ } else {
+ throw new \InvalidArgumentException('Each event listener must be a '
+ . 'callable or an associative array containing a "fn" key.');
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/RequestEvents.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/RequestEvents.php
new file mode 100644
index 0000000..654e8ad
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/RequestEvents.php
@@ -0,0 +1,162 @@
+getRequest();
+ try {
+ $request->getEmitter()->emit(
+ 'before',
+ new BeforeEvent($transaction)
+ );
+ } catch (RequestException $e) {
+ // When a RequestException has been emitted through emitError, the
+ // exception is marked as "emitted". This means that the exception
+ // had a chance to be rescued but was not. In this case, this method
+ // must not emit the error again, but rather throw the exception.
+ // This prevents RequestExceptions encountered during the before
+ // event from being emitted to listeners twice.
+ if ($e->emittedError()) {
+ throw $e;
+ }
+ self::emitError($transaction, $e);
+ } catch (\Exception $e) {
+ self::emitError($transaction, $e);
+ }
+ }
+
+ /**
+ * Emits the complete event for a request and emits an error
+ * event if an error is encountered during the after send.
+ *
+ * @param TransactionInterface $transaction Transaction to emit for
+ * @param array $stats Transfer stats
+ *
+ * @throws RequestException
+ */
+ public static function emitComplete(
+ TransactionInterface $transaction,
+ array $stats = []
+ ) {
+ $request = $transaction->getRequest();
+ $transaction->getResponse()->setEffectiveUrl($request->getUrl());
+ try {
+ $request->getEmitter()->emit(
+ 'complete',
+ new CompleteEvent($transaction, $stats)
+ );
+ } catch (RequestException $e) {
+ self::emitError($transaction, $e, $stats);
+ }
+ }
+
+ /**
+ * Emits the headers event for a request.
+ *
+ * @param TransactionInterface $transaction Transaction to emit for
+ */
+ public static function emitHeaders(TransactionInterface $transaction)
+ {
+ $transaction->getRequest()->getEmitter()->emit(
+ 'headers',
+ new HeadersEvent($transaction)
+ );
+ }
+
+ /**
+ * Emits an error event for a request and accounts for the propagation
+ * of an error event being stopped to prevent the exception from being
+ * thrown.
+ *
+ * @param TransactionInterface $transaction
+ * @param \Exception $e
+ * @param array $stats
+ *
+ * @throws \GuzzleHttp\Exception\RequestException
+ */
+ public static function emitError(
+ TransactionInterface $transaction,
+ \Exception $e,
+ array $stats = []
+ ) {
+ $request = $transaction->getRequest();
+
+ // Convert non-request exception to a wrapped exception
+ if (!($e instanceof RequestException)) {
+ $e = new RequestException($e->getMessage(), $request, null, $e);
+ }
+
+ // Mark the exception as having been emitted for an error event. This
+ // works in tandem with the emitBefore method to prevent the error
+ // event from being triggered twice for the same exception.
+ $e->emittedError(true);
+
+ // Dispatch an event and allow interception
+ if (!$request->getEmitter()->emit(
+ 'error',
+ new ErrorEvent($transaction, $e, $stats)
+ )->isPropagationStopped()) {
+ throw $e;
+ }
+ }
+
+ /**
+ * Converts an array of event options into a formatted array of valid event
+ * configuration.
+ *
+ * @param array $options Event array to convert
+ * @param array $events Event names to convert in the options array.
+ * @param mixed $handler Event handler to utilize
+ *
+ * @return array
+ * @throws \InvalidArgumentException if the event config is invalid
+ * @internal
+ */
+ public static function convertEventArray(
+ array $options,
+ array $events,
+ $handler
+ ) {
+ foreach ($events as $name) {
+ if (!isset($options[$name])) {
+ $options[$name] = $handler;
+ } elseif (is_callable($options[$name])) {
+ $options[$name] = [['fn' => $options[$name]], $handler];
+ } elseif (is_array($options[$name])) {
+ $options[$name][] = $handler;
+ } else {
+ throw new \InvalidArgumentException('Invalid event format');
+ }
+ }
+
+ return $options;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/SubscriberInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/SubscriberInterface.php
new file mode 100644
index 0000000..22c7311
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Event/SubscriberInterface.php
@@ -0,0 +1,31 @@
+ ['methodName']]
+ * - ['eventName' => ['methodName', $priority]]
+ *
+ * @return array
+ */
+ public function getEvents();
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Exception/AdapterException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Exception/AdapterException.php
new file mode 100644
index 0000000..55334c4
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Exception/AdapterException.php
@@ -0,0 +1,5 @@
+response = $response;
+ }
+ /**
+ * Get the associated response
+ *
+ * @return ResponseInterface|null
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Exception/RequestException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Exception/RequestException.php
new file mode 100644
index 0000000..ee953a9
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Exception/RequestException.php
@@ -0,0 +1,124 @@
+getStatusCode() : 0;
+ parent::__construct($message, $code, $previous);
+ $this->request = $request;
+ $this->response = $response;
+ }
+
+ /**
+ * Factory method to create a new exception with a normalized error message
+ *
+ * @param RequestInterface $request Request
+ * @param ResponseInterface $response Response received
+ * @param \Exception $previous Previous exception
+ *
+ * @return self
+ */
+ public static function create(
+ RequestInterface $request,
+ ResponseInterface $response = null,
+ \Exception $previous = null
+ ) {
+ if (!$response) {
+ return new self('Error completing request', $request, null, $previous);
+ }
+
+ $level = $response->getStatusCode()[0];
+ if ($level == '4') {
+ $label = 'Client error response';
+ $className = __NAMESPACE__ . '\\ClientException';
+ } elseif ($level == '5') {
+ $label = 'Server error response';
+ $className = __NAMESPACE__ . '\\ServerException';
+ } else {
+ $label = 'Unsuccessful response';
+ $className = __CLASS__;
+ }
+
+ $message = $label . ' [url] ' . $request->getUrl()
+ . ' [status code] ' . $response->getStatusCode()
+ . ' [reason phrase] ' . $response->getReasonPhrase();
+
+ return new $className($message, $request, $response, $previous);
+ }
+
+ /**
+ * Get the request that caused the exception
+ *
+ * @return RequestInterface
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+ /**
+ * Get the associated response
+ *
+ * @return ResponseInterface|null
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ /**
+ * Check if a response was received
+ *
+ * @return bool
+ */
+ public function hasResponse()
+ {
+ return $this->response !== null;
+ }
+
+ /**
+ * Check or set if the exception was emitted in an error event.
+ *
+ * This value is used in the RequestEvents::emitBefore() method to check
+ * to see if an exception has already been emitted in an error event.
+ *
+ * @param bool|null Set to true to set the exception as having emitted an
+ * error. Leave null to retrieve the current setting.
+ *
+ * @return null|bool
+ * @throws \InvalidArgumentException if you attempt to set the value to false
+ */
+ public function emittedError($value = null)
+ {
+ if ($value === null) {
+ return $this->emittedErrorEvent;
+ } elseif ($value === true) {
+ return $this->emittedErrorEvent = true;
+ } else {
+ throw new \InvalidArgumentException('You cannot set the emitted '
+ . 'error value to false.');
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Exception/ServerException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Exception/ServerException.php
new file mode 100644
index 0000000..d67ed27
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Exception/ServerException.php
@@ -0,0 +1,8 @@
+data);
+ }
+
+ public function offsetGet($offset)
+ {
+ return isset($this->data[$offset]) ? $this->data[$offset] : null;
+ }
+
+ public function offsetSet($offset, $value)
+ {
+ $this->data[$offset] = $value;
+ }
+
+ public function offsetExists($offset)
+ {
+ return isset($this->data[$offset]);
+ }
+
+ public function offsetUnset($offset)
+ {
+ unset($this->data[$offset]);
+ }
+
+ public function toArray()
+ {
+ return $this->data;
+ }
+
+ public function count()
+ {
+ return count($this->data);
+ }
+
+ /**
+ * Get a value from the collection using a path syntax to retrieve nested
+ * data.
+ *
+ * @param string $path Path to traverse and retrieve a value from
+ *
+ * @return mixed|null
+ */
+ public function getPath($path)
+ {
+ return \GuzzleHttp\get_path($this->data, $path);
+ }
+
+ /**
+ * Set a value into a nested array key. Keys will be created as needed to
+ * set the value.
+ *
+ * @param string $path Path to set
+ * @param mixed $value Value to set at the key
+ *
+ * @throws \RuntimeException when trying to setPath using a nested path
+ * that travels through a scalar value
+ */
+ public function setPath($path, $value)
+ {
+ \GuzzleHttp\set_path($this->data, $path, $value);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/AbstractMessage.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/AbstractMessage.php
new file mode 100644
index 0000000..6037a70
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/AbstractMessage.php
@@ -0,0 +1,237 @@
+getStartLine();
+ foreach ($this->getHeaders() as $name => $values) {
+ $result .= "\r\n{$name}: " . implode(', ', $values);
+ }
+
+ return $result . "\r\n\r\n" . $this->body;
+ }
+
+ public function getProtocolVersion()
+ {
+ return $this->protocolVersion;
+ }
+
+ public function getBody()
+ {
+ return $this->body;
+ }
+
+ public function setBody(StreamInterface $body = null)
+ {
+ if ($body === null) {
+ // Setting a null body will remove the body of the request
+ $this->removeHeader('Content-Length')
+ ->removeHeader('Transfer-Encoding');
+ }
+
+ $this->body = $body;
+
+ return $this;
+ }
+
+ public function addHeader($header, $value)
+ {
+ static $valid = ['string' => true, 'integer' => true,
+ 'double' => true, 'array' => true];
+
+ $type = gettype($value);
+ if (!isset($valid[$type])) {
+ throw new \InvalidArgumentException('Invalid header value');
+ }
+
+ if ($type == 'array') {
+ $current = array_merge($this->getHeader($header, true), $value);
+ } else {
+ $current = $this->getHeader($header, true);
+ $current[] = $value;
+ }
+
+ return $this->setHeader($header, $current);
+ }
+
+ public function addHeaders(array $headers)
+ {
+ foreach ($headers as $name => $header) {
+ $this->addHeader($name, $header);
+ }
+ }
+
+ public function getHeader($header, $asArray = false)
+ {
+ $name = strtolower($header);
+
+ if (!isset($this->headers[$name])) {
+ return $asArray ? [] : '';
+ }
+
+ return $asArray
+ ? $this->headers[$name]
+ : implode(', ', $this->headers[$name]);
+ }
+
+ public function getHeaders()
+ {
+ $headers = [];
+ foreach ($this->headers as $name => $values) {
+ $headers[$this->headerNames[$name]] = $values;
+ }
+
+ return $headers;
+ }
+
+ public function setHeader($header, $value)
+ {
+ $header = trim($header);
+ $name = strtolower($header);
+ $this->headerNames[$name] = $header;
+
+ switch (gettype($value)) {
+ case 'string':
+ $this->headers[$name] = [trim($value)];
+ break;
+ case 'integer':
+ case 'double':
+ $this->headers[$name] = [(string) $value];
+ break;
+ case 'array':
+ foreach ($value as &$v) {
+ $v = trim($v);
+ }
+ $this->headers[$name] = $value;
+ break;
+ default:
+ throw new \InvalidArgumentException('Invalid header value '
+ . 'provided: ' . var_export($value, true));
+ }
+
+ return $this;
+ }
+
+ public function setHeaders(array $headers)
+ {
+ $this->headers = $this->headerNames = [];
+ foreach ($headers as $key => $value) {
+ $this->setHeader($key, $value);
+ }
+
+ return $this;
+ }
+
+ public function hasHeader($header)
+ {
+ return isset($this->headers[strtolower($header)]);
+ }
+
+ public function removeHeader($header)
+ {
+ $name = strtolower($header);
+ unset($this->headers[$name], $this->headerNames[$name]);
+
+ return $this;
+ }
+
+ /**
+ * Parse an array of header values containing ";" separated data into an
+ * array of associative arrays representing the header key value pair
+ * data of the header. When a parameter does not contain a value, but just
+ * contains a key, this function will inject a key with a '' string value.
+ *
+ * @param MessageInterface $message That contains the header
+ * @param string $header Header to retrieve from the message
+ *
+ * @return array Returns the parsed header values.
+ */
+ public static function parseHeader(MessageInterface $message, $header)
+ {
+ static $trimmed = "\"' \n\t\r";
+ $params = $matches = [];
+
+ foreach (self::normalizeHeader($message, $header) as $val) {
+ $part = [];
+ foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
+ if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
+ $m = $matches[0];
+ if (isset($m[1])) {
+ $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
+ } else {
+ $part[] = trim($m[0], $trimmed);
+ }
+ }
+ }
+ if ($part) {
+ $params[] = $part;
+ }
+ }
+
+ return $params;
+ }
+
+ /**
+ * Converts an array of header values that may contain comma separated
+ * headers into an array of headers with no comma separated values.
+ *
+ * @param MessageInterface $message That contains the header
+ * @param string $header Header to retrieve from the message
+ *
+ * @return array Returns the normalized header field values.
+ */
+ public static function normalizeHeader(MessageInterface $message, $header)
+ {
+ $h = $message->getHeader($header, true);
+ for ($i = 0, $total = count($h); $i < $total; $i++) {
+ if (strpos($h[$i], ',') === false) {
+ continue;
+ }
+ foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $h[$i]) as $v) {
+ $h[] = trim($v);
+ }
+ unset($h[$i]);
+ }
+
+ return $h;
+ }
+
+ /**
+ * Returns the start line of a message.
+ *
+ * @return string
+ */
+ abstract protected function getStartLine();
+
+ /**
+ * Accepts and modifies the options provided to the message in the
+ * constructor.
+ *
+ * Can be overridden in subclasses as necessary.
+ *
+ * @param array $options Options array passed by reference.
+ */
+ protected function handleOptions(array &$options)
+ {
+ if (isset($options['protocol_version'])) {
+ $this->protocolVersion = $options['protocol_version'];
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/MessageFactory.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/MessageFactory.php
new file mode 100644
index 0000000..da67c38
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/MessageFactory.php
@@ -0,0 +1,345 @@
+errorPlugin = new HttpError();
+ $this->redirectPlugin = new Redirect();
+ }
+
+ public function createResponse(
+ $statusCode,
+ array $headers = [],
+ $body = null,
+ array $options = []
+ ) {
+ if (null !== $body) {
+ $body = Stream\create($body);
+ }
+
+ return new Response($statusCode, $headers, $body, $options);
+ }
+
+ public function createRequest($method, $url, array $options = [])
+ {
+ // Handle the request protocol version option that needs to be
+ // specified in the request constructor.
+ if (isset($options['version'])) {
+ $options['config']['protocol_version'] = $options['version'];
+ unset($options['version']);
+ }
+
+ $request = new Request($method, $url, [], null,
+ isset($options['config']) ? $options['config'] : []);
+
+ unset($options['config']);
+
+ // Use a POST body by default
+ if ($method == 'POST' &&
+ !isset($options['body']) &&
+ !isset($options['json'])
+ ) {
+ $options['body'] = [];
+ }
+
+ if ($options) {
+ $this->applyOptions($request, $options);
+ }
+
+ return $request;
+ }
+
+ /**
+ * Create a request or response object from an HTTP message string
+ *
+ * @param string $message Message to parse
+ *
+ * @return RequestInterface|ResponseInterface
+ * @throws \InvalidArgumentException if unable to parse a message
+ */
+ public function fromMessage($message)
+ {
+ static $parser;
+ if (!$parser) {
+ $parser = new MessageParser();
+ }
+
+ // Parse a response
+ if (strtoupper(substr($message, 0, 4)) == 'HTTP') {
+ $data = $parser->parseResponse($message);
+ return $this->createResponse(
+ $data['code'],
+ $data['headers'],
+ $data['body'] === '' ? null : $data['body'],
+ $data
+ );
+ }
+
+ // Parse a request
+ if (!($data = ($parser->parseRequest($message)))) {
+ throw new \InvalidArgumentException('Unable to parse request');
+ }
+
+ return $this->createRequest(
+ $data['method'],
+ Url::buildUrl($data['request_url']),
+ [
+ 'headers' => $data['headers'],
+ 'body' => $data['body'] === '' ? null : $data['body'],
+ 'config' => [
+ 'protocol_version' => $data['protocol_version']
+ ]
+ ]
+ );
+ }
+
+ /**
+ * Apply POST fields and files to a request to attempt to give an accurate
+ * representation.
+ *
+ * @param RequestInterface $request Request to update
+ * @param array $body Body to apply
+ */
+ protected function addPostData(RequestInterface $request, array $body)
+ {
+ static $fields = ['string' => true, 'array' => true, 'NULL' => true,
+ 'boolean' => true, 'double' => true, 'integer' => true];
+
+ $post = new PostBody();
+ foreach ($body as $key => $value) {
+ if (isset($fields[gettype($value)])) {
+ $post->setField($key, $value);
+ } elseif ($value instanceof PostFileInterface) {
+ $post->addFile($value);
+ } else {
+ $post->addFile(new PostFile($key, $value));
+ }
+ }
+
+ $request->setBody($post);
+ $post->applyRequestHeaders($request);
+ }
+
+ protected function applyOptions(
+ RequestInterface $request,
+ array $options = []
+ ) {
+ // Values specified in the config map are passed to request options
+ static $configMap = ['connect_timeout' => 1, 'timeout' => 1,
+ 'verify' => 1, 'ssl_key' => 1, 'cert' => 1, 'proxy' => 1,
+ 'debug' => 1, 'save_to' => 1, 'stream' => 1, 'expect' => 1];
+
+ // Take the class of the instance, not the parent
+ $selfClass = get_class($this);
+
+ // Check if we already took it's class methods and had them saved
+ if (!isset(self::$classMethods[$selfClass])) {
+ self::$classMethods[$selfClass] = array_flip(get_class_methods($this));
+ }
+
+ // Take class methods of this particular instance
+ $methods = self::$classMethods[$selfClass];
+
+ // Iterate over each key value pair and attempt to apply a config using
+ // double dispatch.
+ $config = $request->getConfig();
+ foreach ($options as $key => $value) {
+ $method = "add_{$key}";
+ if (isset($methods[$method])) {
+ $this->{$method}($request, $value);
+ } elseif (isset($configMap[$key])) {
+ $config[$key] = $value;
+ } else {
+ throw new \InvalidArgumentException("No method is configured "
+ . "to handle the {$key} config key");
+ }
+ }
+ }
+
+ private function add_body(RequestInterface $request, $value)
+ {
+ if ($value !== null) {
+ if (is_array($value)) {
+ $this->addPostData($request, $value);
+ } else {
+ $request->setBody(Stream\create($value));
+ }
+ }
+ }
+
+ private function add_allow_redirects(RequestInterface $request, $value)
+ {
+ static $defaultRedirect = [
+ 'max' => 5,
+ 'strict' => false,
+ 'referer' => false
+ ];
+
+ if ($value === false) {
+ return;
+ }
+
+ if ($value === true) {
+ $value = $defaultRedirect;
+ } elseif (!isset($value['max'])) {
+ throw new \InvalidArgumentException('allow_redirects must be '
+ . 'true, false, or an array that contains the \'max\' key');
+ } else {
+ // Merge the default settings with the provided settings
+ $value += $defaultRedirect;
+ }
+
+ $request->getConfig()['redirect'] = $value;
+ $request->getEmitter()->attach($this->redirectPlugin);
+ }
+
+ private function add_exceptions(RequestInterface $request, $value)
+ {
+ if ($value === true) {
+ $request->getEmitter()->attach($this->errorPlugin);
+ }
+ }
+
+ private function add_auth(RequestInterface $request, $value)
+ {
+ if (!$value) {
+ return;
+ } elseif (is_array($value)) {
+ $authType = isset($value[2]) ? strtolower($value[2]) : 'basic';
+ } else {
+ $authType = strtolower($value);
+ }
+
+ $request->getConfig()->set('auth', $value);
+
+ if ($authType == 'basic') {
+ $request->setHeader(
+ 'Authorization',
+ 'Basic ' . base64_encode("$value[0]:$value[1]")
+ );
+ } elseif ($authType == 'digest') {
+ // Currently only implemented by the cURL adapter.
+ // @todo: Need an event listener solution that does not rely on cURL
+ $config = $request->getConfig();
+ $config->setPath('curl/' . CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
+ $config->setPath('curl/' . CURLOPT_USERPWD, "$value[0]:$value[1]");
+ }
+ }
+
+ private function add_query(RequestInterface $request, $value)
+ {
+ if ($value instanceof Query) {
+ $original = $request->getQuery();
+ // Do not overwrite existing query string variables by overwriting
+ // the object with the query string data passed in the URL
+ $request->setQuery($value->overwriteWith($original->toArray()));
+ } elseif (is_array($value)) {
+ // Do not overwrite existing query string variables
+ $query = $request->getQuery();
+ foreach ($value as $k => $v) {
+ if (!isset($query[$k])) {
+ $query[$k] = $v;
+ }
+ }
+ } else {
+ throw new \InvalidArgumentException('query value must be an array '
+ . 'or Query object');
+ }
+ }
+
+ private function add_headers(RequestInterface $request, $value)
+ {
+ if (!is_array($value)) {
+ throw new \InvalidArgumentException('header value must be an array');
+ }
+
+ // Do not overwrite existing headers
+ foreach ($value as $k => $v) {
+ if (!$request->hasHeader($k)) {
+ $request->setHeader($k, $v);
+ }
+ }
+ }
+
+ private function add_cookies(RequestInterface $request, $value)
+ {
+ if ($value === true) {
+ static $cookie = null;
+ if (!$cookie) {
+ $cookie = new Cookie();
+ }
+ $request->getEmitter()->attach($cookie);
+ } elseif (is_array($value)) {
+ $request->getEmitter()->attach(
+ new Cookie(CookieJar::fromArray($value, $request->getHost()))
+ );
+ } elseif ($value instanceof CookieJarInterface) {
+ $request->getEmitter()->attach(new Cookie($value));
+ } elseif ($value !== false) {
+ throw new \InvalidArgumentException('cookies must be an array, '
+ . 'true, or a CookieJarInterface object');
+ }
+ }
+
+ private function add_events(RequestInterface $request, $value)
+ {
+ if (!is_array($value)) {
+ throw new \InvalidArgumentException('events value must be an array');
+ }
+
+ $this->attachListeners($request, $this->prepareListeners($value,
+ ['before', 'complete', 'error', 'headers']
+ ));
+ }
+
+ private function add_subscribers(RequestInterface $request, $value)
+ {
+ if (!is_array($value)) {
+ throw new \InvalidArgumentException('subscribers must be an array');
+ }
+
+ $emitter = $request->getEmitter();
+ foreach ($value as $subscribers) {
+ $emitter->attach($subscribers);
+ }
+ }
+
+ private function add_json(RequestInterface $request, $value)
+ {
+ if (!$request->hasHeader('Content-Type')) {
+ $request->setHeader('Content-Type', 'application/json');
+ }
+
+ $request->setBody(Stream\create(json_encode($value)));
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/MessageFactoryInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/MessageFactoryInterface.php
new file mode 100644
index 0000000..daab042
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/MessageFactoryInterface.php
@@ -0,0 +1,71 @@
+getHeaders() as $name => $values) {
+ * echo $name . ": " . implode(", ", $values);
+ * }
+ *
+ * @return array Returns an associative array of the message's headers.
+ */
+ public function getHeaders();
+
+ /**
+ * Retrieve a header by the given case-insensitive name.
+ *
+ * By default, this method returns all of the header values of the given
+ * case-insensitive header name as a string concatenated together using
+ * a comma. Because some header should not be concatenated together using a
+ * comma, this method provides a Boolean argument that can be used to
+ * retrieve the associated header values as an array of strings.
+ *
+ * @param string $header Case-insensitive header name.
+ * @param bool $asArray Set to true to retrieve the header value as an
+ * array of strings.
+ *
+ * @return array|string
+ */
+ public function getHeader($header, $asArray = false);
+
+ /**
+ * Checks if a header exists by the given case-insensitive name.
+ *
+ * @param string $header Case-insensitive header name.
+ *
+ * @return bool Returns true if any header names match the given header
+ * name using a case-insensitive string comparison. Returns false if
+ * no matching header name is found in the message.
+ */
+ public function hasHeader($header);
+
+ /**
+ * Remove a specific header by case-insensitive name.
+ *
+ * @param string $header Case-insensitive header name.
+ *
+ * @return self
+ */
+ public function removeHeader($header);
+
+ /**
+ * Appends a header value to any existing values associated with the
+ * given header name.
+ *
+ * @param string $header Header name to add
+ * @param string $value Value of the header
+ *
+ * @return self
+ */
+ public function addHeader($header, $value);
+
+ /**
+ * Merges in an associative array of headers.
+ *
+ * Each array key MUST be a string representing the case-insensitive name
+ * of a header. Each value MUST be either a string or an array of strings.
+ * For each value, the value is appended to any existing header of the same
+ * name, or, if a header does not already exist by the given name, then the
+ * header is added.
+ *
+ * @param array $headers Associative array of headers to add to the message
+ *
+ * @return self
+ */
+ public function addHeaders(array $headers);
+
+ /**
+ * Sets a header, replacing any existing values of any headers with the
+ * same case-insensitive name.
+ *
+ * The header values MUST be a string or an array of strings.
+ *
+ * @param string $header Header name
+ * @param string|array $value Header value(s)
+ *
+ * @return self Returns the message.
+ */
+ public function setHeader($header, $value);
+
+ /**
+ * Sets headers, replacing any headers that have already been set on the
+ * message.
+ *
+ * The array keys MUST be a string. The array values must be either a
+ * string or an array of strings.
+ *
+ * @param array $headers Headers to set.
+ *
+ * @return self Returns the message.
+ */
+ public function setHeaders(array $headers);
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/MessageParser.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/MessageParser.php
new file mode 100644
index 0000000..777ce26
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/MessageParser.php
@@ -0,0 +1,172 @@
+parseMessage($message))) {
+ return false;
+ }
+
+ // Parse the protocol and protocol version
+ if (isset($parts['start_line'][2])) {
+ $startParts = explode('/', $parts['start_line'][2]);
+ $protocol = strtoupper($startParts[0]);
+ $version = isset($startParts[1]) ? $startParts[1] : '1.1';
+ } else {
+ $protocol = 'HTTP';
+ $version = '1.1';
+ }
+
+ $parsed = [
+ 'method' => strtoupper($parts['start_line'][0]),
+ 'protocol' => $protocol,
+ 'protocol_version' => $version,
+ 'headers' => $parts['headers'],
+ 'body' => $parts['body']
+ ];
+
+ $parsed['request_url'] = $this->getUrlPartsFromMessage(
+ (isset($parts['start_line'][1]) ? $parts['start_line'][1] : ''), $parsed);
+
+ return $parsed;
+ }
+
+ /**
+ * Parse an HTTP response message into an associative array of parts.
+ *
+ * @param string $message HTTP response to parse
+ *
+ * @return array|bool Returns false if the message is invalid
+ */
+ public function parseResponse($message)
+ {
+ if (!($parts = $this->parseMessage($message))) {
+ return false;
+ }
+
+ list($protocol, $version) = explode('/', trim($parts['start_line'][0]));
+
+ return [
+ 'protocol' => $protocol,
+ 'protocol_version' => $version,
+ 'code' => $parts['start_line'][1],
+ 'reason_phrase' => isset($parts['start_line'][2]) ? $parts['start_line'][2] : '',
+ 'headers' => $parts['headers'],
+ 'body' => $parts['body']
+ ];
+ }
+
+ /**
+ * Parse a message into parts
+ *
+ * @param string $message Message to parse
+ *
+ * @return array|bool
+ */
+ private function parseMessage($message)
+ {
+ if (!$message) {
+ return false;
+ }
+
+ $startLine = null;
+ $headers = [];
+ $body = '';
+
+ // Iterate over each line in the message, accounting for line endings
+ $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
+ for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) {
+
+ $line = $lines[$i];
+
+ // If two line breaks were encountered, then this is the end of body
+ if (empty($line)) {
+ if ($i < $totalLines - 1) {
+ $body = implode('', array_slice($lines, $i + 2));
+ }
+ break;
+ }
+
+ // Parse message headers
+ if (!$startLine) {
+ $startLine = explode(' ', $line, 3);
+ } elseif (strpos($line, ':')) {
+ $parts = explode(':', $line, 2);
+ $key = trim($parts[0]);
+ $value = isset($parts[1]) ? trim($parts[1]) : '';
+ if (!isset($headers[$key])) {
+ $headers[$key] = $value;
+ } elseif (!is_array($headers[$key])) {
+ $headers[$key] = [$headers[$key], $value];
+ } else {
+ $headers[$key][] = $value;
+ }
+ }
+ }
+
+ return [
+ 'start_line' => $startLine,
+ 'headers' => $headers,
+ 'body' => $body
+ ];
+ }
+
+ /**
+ * Create URL parts from HTTP message parts
+ *
+ * @param string $requestUrl Associated URL
+ * @param array $parts HTTP message parts
+ *
+ * @return array
+ */
+ private function getUrlPartsFromMessage($requestUrl, array $parts)
+ {
+ // Parse the URL information from the message
+ $urlParts = ['path' => $requestUrl, 'scheme' => 'http'];
+
+ // Check for the Host header
+ if (isset($parts['headers']['Host'])) {
+ $urlParts['host'] = $parts['headers']['Host'];
+ } elseif (isset($parts['headers']['host'])) {
+ $urlParts['host'] = $parts['headers']['host'];
+ } else {
+ $urlParts['host'] = null;
+ }
+
+ if (false === strpos($urlParts['host'], ':')) {
+ $urlParts['port'] = '';
+ } else {
+ $hostParts = explode(':', $urlParts['host']);
+ $urlParts['host'] = trim($hostParts[0]);
+ $urlParts['port'] = (int) trim($hostParts[1]);
+ if ($urlParts['port'] == 443) {
+ $urlParts['scheme'] = 'https';
+ }
+ }
+
+ // Check if a query is present
+ $path = $urlParts['path'];
+ $qpos = strpos($path, '?');
+ if ($qpos) {
+ $urlParts['query'] = substr($path, $qpos + 1);
+ $urlParts['path'] = substr($path, 0, $qpos);
+ } else {
+ $urlParts['query'] = '';
+ }
+
+ return $urlParts;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/Request.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/Request.php
new file mode 100644
index 0000000..5c0e0ae
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/Request.php
@@ -0,0 +1,216 @@
+setUrl($url);
+ $this->method = strtoupper($method);
+ $this->handleOptions($options);
+ $this->transferOptions = new Collection($options);
+ $this->addPrepareEvent();
+
+ if ($body !== null) {
+ $this->setBody($body);
+ }
+
+ if ($headers) {
+ foreach ($headers as $key => $value) {
+ $this->setHeader($key, $value);
+ }
+ }
+ }
+
+ public function __clone()
+ {
+ if ($this->emitter) {
+ $this->emitter = clone $this->emitter;
+ }
+ $this->transferOptions = clone $this->transferOptions;
+ $this->url = clone $this->url;
+ }
+
+ public function setUrl($url)
+ {
+ $this->url = $url instanceof Url ? $url : Url::fromString($url);
+ $this->updateHostHeaderFromUrl();
+
+ return $this;
+ }
+
+ public function getUrl()
+ {
+ return (string) $this->url;
+ }
+
+ public function setQuery($query)
+ {
+ $this->url->setQuery($query);
+
+ return $this;
+ }
+
+ public function getQuery()
+ {
+ return $this->url->getQuery();
+ }
+
+ public function setMethod($method)
+ {
+ $this->method = strtoupper($method);
+
+ return $this;
+ }
+
+ public function getMethod()
+ {
+ return $this->method;
+ }
+
+ public function getScheme()
+ {
+ return $this->url->getScheme();
+ }
+
+ public function setScheme($scheme)
+ {
+ $this->url->setScheme($scheme);
+
+ return $this;
+ }
+
+ public function getPort()
+ {
+ return $this->url->getPort();
+ }
+
+ public function setPort($port)
+ {
+ $this->url->setPort($port);
+ $this->updateHostHeaderFromUrl();
+
+ return $this;
+ }
+
+ public function getHost()
+ {
+ return $this->url->getHost();
+ }
+
+ public function setHost($host)
+ {
+ $this->url->setHost($host);
+ $this->updateHostHeaderFromUrl();
+
+ return $this;
+ }
+
+ public function getPath()
+ {
+ return '/' . ltrim($this->url->getPath(), '/');
+ }
+
+ public function setPath($path)
+ {
+ $this->url->setPath($path);
+
+ return $this;
+ }
+
+ public function getResource()
+ {
+ $resource = $this->getPath();
+ if ($query = (string) $this->url->getQuery()) {
+ $resource .= '?' . $query;
+ }
+
+ return $resource;
+ }
+
+ public function getConfig()
+ {
+ return $this->transferOptions;
+ }
+
+ protected function handleOptions(array &$options)
+ {
+ parent::handleOptions($options);
+ // Use a custom emitter if one is specified, and remove it from
+ // options that are exposed through getConfig()
+ if (isset($options['emitter'])) {
+ $this->emitter = $options['emitter'];
+ unset($options['emitter']);
+ }
+ }
+
+ protected function getStartLine()
+ {
+ return trim($this->method . ' ' . $this->getResource())
+ . ' HTTP/' . $this->getProtocolVersion();
+ }
+
+ /**
+ * Adds a subscriber that ensures a request's body is prepared before
+ * sending.
+ */
+ private function addPrepareEvent()
+ {
+ static $subscriber;
+ if (!$subscriber) {
+ $subscriber = new Prepare();
+ }
+
+ $this->getEmitter()->attach($subscriber);
+ }
+
+ private function updateHostHeaderFromUrl()
+ {
+ $port = $this->url->getPort();
+ $scheme = $this->url->getScheme();
+ if ($host = $this->url->getHost()) {
+ if (($port == 80 && $scheme == 'http') ||
+ ($port == 443 && $scheme == 'https')
+ ) {
+ $this->setHeader('Host', $host);
+ } else {
+ $this->setHeader('Host', "{$host}:{$port}");
+ }
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/RequestInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/RequestInterface.php
new file mode 100644
index 0000000..8cd5de7
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/RequestInterface.php
@@ -0,0 +1,150 @@
+ 'Continue',
+ 101 => 'Switching Protocols',
+ 102 => 'Processing',
+ 200 => 'OK',
+ 201 => 'Created',
+ 202 => 'Accepted',
+ 203 => 'Non-Authoritative Information',
+ 204 => 'No Content',
+ 205 => 'Reset Content',
+ 206 => 'Partial Content',
+ 207 => 'Multi-Status',
+ 208 => 'Already Reported',
+ 226 => 'IM Used',
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 307 => 'Temporary Redirect',
+ 308 => 'Permanent Redirect',
+ 400 => 'Bad Request',
+ 401 => 'Unauthorized',
+ 402 => 'Payment Required',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 405 => 'Method Not Allowed',
+ 406 => 'Not Acceptable',
+ 407 => 'Proxy Authentication Required',
+ 408 => 'Request Timeout',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition Failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Long',
+ 415 => 'Unsupported Media Type',
+ 416 => 'Requested Range Not Satisfiable',
+ 417 => 'Expectation Failed',
+ 422 => 'Unprocessable Entity',
+ 423 => 'Locked',
+ 424 => 'Failed Dependency',
+ 425 => 'Reserved for WebDAV advanced collections expired proposal',
+ 426 => 'Upgrade required',
+ 428 => 'Precondition Required',
+ 429 => 'Too Many Requests',
+ 431 => 'Request Header Fields Too Large',
+ 500 => 'Internal Server Error',
+ 501 => 'Not Implemented',
+ 502 => 'Bad Gateway',
+ 503 => 'Service Unavailable',
+ 504 => 'Gateway Timeout',
+ 505 => 'HTTP Version Not Supported',
+ 506 => 'Variant Also Negotiates (Experimental)',
+ 507 => 'Insufficient Storage',
+ 508 => 'Loop Detected',
+ 510 => 'Not Extended',
+ 511 => 'Network Authentication Required',
+ );
+
+ /** @var string The reason phrase of the response (human readable code) */
+ private $reasonPhrase;
+
+ /** @var string The status code of the response */
+ private $statusCode;
+
+ /** @var string The effective URL that returned this response */
+ private $effectiveUrl;
+
+ /**
+ * @param string $statusCode The response status code (e.g. 200)
+ * @param array $headers The response headers
+ * @param StreamInterface $body The body of the response
+ * @param array $options Response message options
+ * - reason_phrase: Set a custom reason phrase
+ * - protocol_version: Set a custom protocol version
+ */
+ public function __construct(
+ $statusCode,
+ array $headers = [],
+ StreamInterface $body = null,
+ array $options = []
+ ) {
+ $this->statusCode = (string) $statusCode;
+ $this->handleOptions($options);
+
+ // Assume a reason phrase if one was not applied as an option
+ if (!$this->reasonPhrase &&
+ isset(self::$statusTexts[$this->statusCode])
+ ) {
+ $this->reasonPhrase = self::$statusTexts[$this->statusCode];
+ }
+
+ if ($headers) {
+ $this->setHeaders($headers);
+ }
+
+ if ($body) {
+ $this->setBody($body);
+ }
+ }
+
+ public function getStatusCode()
+ {
+ return $this->statusCode;
+ }
+
+ public function getReasonPhrase()
+ {
+ return $this->reasonPhrase;
+ }
+
+ public function json(array $config = [])
+ {
+ try {
+ return \GuzzleHttp\json_decode(
+ (string) $this->getBody(),
+ isset($config['object']) ? !$config['object'] : true,
+ 512,
+ isset($config['big_int_strings']) ? JSON_BIGINT_AS_STRING : 0
+ );
+ } catch (\InvalidArgumentException $e) {
+ throw new ParseException(
+ $e->getMessage(),
+ $this
+ );
+ }
+ }
+
+ public function xml(array $config = [])
+ {
+ $disableEntities = libxml_disable_entity_loader(true);
+ $internalErrors = libxml_use_internal_errors(true);
+
+ try {
+ // Allow XML to be retrieved even if there is no response body
+ $xml = new \SimpleXMLElement(
+ (string) $this->getBody() ?: ' ',
+ LIBXML_NONET,
+ isset($config['ns']) ? $config['ns'] : '',
+ isset($config['ns_is_prefix']) ? $config['ns_is_prefix'] : false
+ );
+ libxml_disable_entity_loader($disableEntities);
+ libxml_use_internal_errors($internalErrors);
+ } catch (\Exception $e) {
+ libxml_disable_entity_loader($disableEntities);
+ libxml_use_internal_errors($internalErrors);
+ throw new ParseException(
+ 'Unable to parse response body into XML: ' . $e->getMessage(),
+ $this
+ );
+ }
+
+ return $xml;
+ }
+
+ public function getEffectiveUrl()
+ {
+ return $this->effectiveUrl;
+ }
+
+ public function setEffectiveUrl($url)
+ {
+ $this->effectiveUrl = $url;
+
+ return $this;
+ }
+
+ /**
+ * Accepts and modifies the options provided to the response in the
+ * constructor.
+ *
+ * @param array $options Options array passed by reference.
+ */
+ protected function handleOptions(array &$options = [])
+ {
+ parent::handleOptions($options);
+ if (isset($options['reason_phrase'])) {
+ $this->reasonPhrase = $options['reason_phrase'];
+ }
+ }
+
+ protected function getStartLine()
+ {
+ return 'HTTP/' . $this->getProtocolVersion()
+ . " {$this->statusCode} {$this->reasonPhrase}";
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/ResponseInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/ResponseInterface.php
new file mode 100644
index 0000000..db8252c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Message/ResponseInterface.php
@@ -0,0 +1,86 @@
+ 'text/vnd.in3d.3dml',
+ '3g2' => 'video/3gpp2',
+ '3gp' => 'video/3gpp',
+ '7z' => 'application/x-7z-compressed',
+ 'aab' => 'application/x-authorware-bin',
+ 'aac' => 'audio/x-aac',
+ 'aam' => 'application/x-authorware-map',
+ 'aas' => 'application/x-authorware-seg',
+ 'abw' => 'application/x-abiword',
+ 'ac' => 'application/pkix-attr-cert',
+ 'acc' => 'application/vnd.americandynamics.acc',
+ 'ace' => 'application/x-ace-compressed',
+ 'acu' => 'application/vnd.acucobol',
+ 'acutc' => 'application/vnd.acucorp',
+ 'adp' => 'audio/adpcm',
+ 'aep' => 'application/vnd.audiograph',
+ 'afm' => 'application/x-font-type1',
+ 'afp' => 'application/vnd.ibm.modcap',
+ 'ahead' => 'application/vnd.ahead.space',
+ 'ai' => 'application/postscript',
+ 'aif' => 'audio/x-aiff',
+ 'aifc' => 'audio/x-aiff',
+ 'aiff' => 'audio/x-aiff',
+ 'air' => 'application/vnd.adobe.air-application-installer-package+zip',
+ 'ait' => 'application/vnd.dvb.ait',
+ 'ami' => 'application/vnd.amiga.ami',
+ 'apk' => 'application/vnd.android.package-archive',
+ 'application' => 'application/x-ms-application',
+ 'apr' => 'application/vnd.lotus-approach',
+ 'asa' => 'text/plain',
+ 'asax' => 'application/octet-stream',
+ 'asc' => 'application/pgp-signature',
+ 'ascx' => 'text/plain',
+ 'asf' => 'video/x-ms-asf',
+ 'ashx' => 'text/plain',
+ 'asm' => 'text/x-asm',
+ 'asmx' => 'text/plain',
+ 'aso' => 'application/vnd.accpac.simply.aso',
+ 'asp' => 'text/plain',
+ 'aspx' => 'text/plain',
+ 'asx' => 'video/x-ms-asf',
+ 'atc' => 'application/vnd.acucorp',
+ 'atom' => 'application/atom+xml',
+ 'atomcat' => 'application/atomcat+xml',
+ 'atomsvc' => 'application/atomsvc+xml',
+ 'atx' => 'application/vnd.antix.game-component',
+ 'au' => 'audio/basic',
+ 'avi' => 'video/x-msvideo',
+ 'aw' => 'application/applixware',
+ 'axd' => 'text/plain',
+ 'azf' => 'application/vnd.airzip.filesecure.azf',
+ 'azs' => 'application/vnd.airzip.filesecure.azs',
+ 'azw' => 'application/vnd.amazon.ebook',
+ 'bat' => 'application/x-msdownload',
+ 'bcpio' => 'application/x-bcpio',
+ 'bdf' => 'application/x-font-bdf',
+ 'bdm' => 'application/vnd.syncml.dm+wbxml',
+ 'bed' => 'application/vnd.realvnc.bed',
+ 'bh2' => 'application/vnd.fujitsu.oasysprs',
+ 'bin' => 'application/octet-stream',
+ 'bmi' => 'application/vnd.bmi',
+ 'bmp' => 'image/bmp',
+ 'book' => 'application/vnd.framemaker',
+ 'box' => 'application/vnd.previewsystems.box',
+ 'boz' => 'application/x-bzip2',
+ 'bpk' => 'application/octet-stream',
+ 'btif' => 'image/prs.btif',
+ 'bz' => 'application/x-bzip',
+ 'bz2' => 'application/x-bzip2',
+ 'c' => 'text/x-c',
+ 'c11amc' => 'application/vnd.cluetrust.cartomobile-config',
+ 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg',
+ 'c4d' => 'application/vnd.clonk.c4group',
+ 'c4f' => 'application/vnd.clonk.c4group',
+ 'c4g' => 'application/vnd.clonk.c4group',
+ 'c4p' => 'application/vnd.clonk.c4group',
+ 'c4u' => 'application/vnd.clonk.c4group',
+ 'cab' => 'application/vnd.ms-cab-compressed',
+ 'car' => 'application/vnd.curl.car',
+ 'cat' => 'application/vnd.ms-pki.seccat',
+ 'cc' => 'text/x-c',
+ 'cct' => 'application/x-director',
+ 'ccxml' => 'application/ccxml+xml',
+ 'cdbcmsg' => 'application/vnd.contact.cmsg',
+ 'cdf' => 'application/x-netcdf',
+ 'cdkey' => 'application/vnd.mediastation.cdkey',
+ 'cdmia' => 'application/cdmi-capability',
+ 'cdmic' => 'application/cdmi-container',
+ 'cdmid' => 'application/cdmi-domain',
+ 'cdmio' => 'application/cdmi-object',
+ 'cdmiq' => 'application/cdmi-queue',
+ 'cdx' => 'chemical/x-cdx',
+ 'cdxml' => 'application/vnd.chemdraw+xml',
+ 'cdy' => 'application/vnd.cinderella',
+ 'cer' => 'application/pkix-cert',
+ 'cfc' => 'application/x-coldfusion',
+ 'cfm' => 'application/x-coldfusion',
+ 'cgm' => 'image/cgm',
+ 'chat' => 'application/x-chat',
+ 'chm' => 'application/vnd.ms-htmlhelp',
+ 'chrt' => 'application/vnd.kde.kchart',
+ 'cif' => 'chemical/x-cif',
+ 'cii' => 'application/vnd.anser-web-certificate-issue-initiation',
+ 'cil' => 'application/vnd.ms-artgalry',
+ 'cla' => 'application/vnd.claymore',
+ 'class' => 'application/java-vm',
+ 'clkk' => 'application/vnd.crick.clicker.keyboard',
+ 'clkp' => 'application/vnd.crick.clicker.palette',
+ 'clkt' => 'application/vnd.crick.clicker.template',
+ 'clkw' => 'application/vnd.crick.clicker.wordbank',
+ 'clkx' => 'application/vnd.crick.clicker',
+ 'clp' => 'application/x-msclip',
+ 'cmc' => 'application/vnd.cosmocaller',
+ 'cmdf' => 'chemical/x-cmdf',
+ 'cml' => 'chemical/x-cml',
+ 'cmp' => 'application/vnd.yellowriver-custom-menu',
+ 'cmx' => 'image/x-cmx',
+ 'cod' => 'application/vnd.rim.cod',
+ 'com' => 'application/x-msdownload',
+ 'conf' => 'text/plain',
+ 'cpio' => 'application/x-cpio',
+ 'cpp' => 'text/x-c',
+ 'cpt' => 'application/mac-compactpro',
+ 'crd' => 'application/x-mscardfile',
+ 'crl' => 'application/pkix-crl',
+ 'crt' => 'application/x-x509-ca-cert',
+ 'cryptonote' => 'application/vnd.rig.cryptonote',
+ 'cs' => 'text/plain',
+ 'csh' => 'application/x-csh',
+ 'csml' => 'chemical/x-csml',
+ 'csp' => 'application/vnd.commonspace',
+ 'css' => 'text/css',
+ 'cst' => 'application/x-director',
+ 'csv' => 'text/csv',
+ 'cu' => 'application/cu-seeme',
+ 'curl' => 'text/vnd.curl',
+ 'cww' => 'application/prs.cww',
+ 'cxt' => 'application/x-director',
+ 'cxx' => 'text/x-c',
+ 'dae' => 'model/vnd.collada+xml',
+ 'daf' => 'application/vnd.mobius.daf',
+ 'dataless' => 'application/vnd.fdsn.seed',
+ 'davmount' => 'application/davmount+xml',
+ 'dcr' => 'application/x-director',
+ 'dcurl' => 'text/vnd.curl.dcurl',
+ 'dd2' => 'application/vnd.oma.dd2+xml',
+ 'ddd' => 'application/vnd.fujixerox.ddd',
+ 'deb' => 'application/x-debian-package',
+ 'def' => 'text/plain',
+ 'deploy' => 'application/octet-stream',
+ 'der' => 'application/x-x509-ca-cert',
+ 'dfac' => 'application/vnd.dreamfactory',
+ 'dic' => 'text/x-c',
+ 'dir' => 'application/x-director',
+ 'dis' => 'application/vnd.mobius.dis',
+ 'dist' => 'application/octet-stream',
+ 'distz' => 'application/octet-stream',
+ 'djv' => 'image/vnd.djvu',
+ 'djvu' => 'image/vnd.djvu',
+ 'dll' => 'application/x-msdownload',
+ 'dmg' => 'application/octet-stream',
+ 'dms' => 'application/octet-stream',
+ 'dna' => 'application/vnd.dna',
+ 'doc' => 'application/msword',
+ 'docm' => 'application/vnd.ms-word.document.macroenabled.12',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'dot' => 'application/msword',
+ 'dotm' => 'application/vnd.ms-word.template.macroenabled.12',
+ 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+ 'dp' => 'application/vnd.osgi.dp',
+ 'dpg' => 'application/vnd.dpgraph',
+ 'dra' => 'audio/vnd.dra',
+ 'dsc' => 'text/prs.lines.tag',
+ 'dssc' => 'application/dssc+der',
+ 'dtb' => 'application/x-dtbook+xml',
+ 'dtd' => 'application/xml-dtd',
+ 'dts' => 'audio/vnd.dts',
+ 'dtshd' => 'audio/vnd.dts.hd',
+ 'dump' => 'application/octet-stream',
+ 'dvi' => 'application/x-dvi',
+ 'dwf' => 'model/vnd.dwf',
+ 'dwg' => 'image/vnd.dwg',
+ 'dxf' => 'image/vnd.dxf',
+ 'dxp' => 'application/vnd.spotfire.dxp',
+ 'dxr' => 'application/x-director',
+ 'ecelp4800' => 'audio/vnd.nuera.ecelp4800',
+ 'ecelp7470' => 'audio/vnd.nuera.ecelp7470',
+ 'ecelp9600' => 'audio/vnd.nuera.ecelp9600',
+ 'ecma' => 'application/ecmascript',
+ 'edm' => 'application/vnd.novadigm.edm',
+ 'edx' => 'application/vnd.novadigm.edx',
+ 'efif' => 'application/vnd.picsel',
+ 'ei6' => 'application/vnd.pg.osasli',
+ 'elc' => 'application/octet-stream',
+ 'eml' => 'message/rfc822',
+ 'emma' => 'application/emma+xml',
+ 'eol' => 'audio/vnd.digital-winds',
+ 'eot' => 'application/vnd.ms-fontobject',
+ 'eps' => 'application/postscript',
+ 'epub' => 'application/epub+zip',
+ 'es3' => 'application/vnd.eszigno3+xml',
+ 'esf' => 'application/vnd.epson.esf',
+ 'et3' => 'application/vnd.eszigno3+xml',
+ 'etx' => 'text/x-setext',
+ 'exe' => 'application/x-msdownload',
+ 'exi' => 'application/exi',
+ 'ext' => 'application/vnd.novadigm.ext',
+ 'ez' => 'application/andrew-inset',
+ 'ez2' => 'application/vnd.ezpix-album',
+ 'ez3' => 'application/vnd.ezpix-package',
+ 'f' => 'text/x-fortran',
+ 'f4v' => 'video/x-f4v',
+ 'f77' => 'text/x-fortran',
+ 'f90' => 'text/x-fortran',
+ 'fbs' => 'image/vnd.fastbidsheet',
+ 'fcs' => 'application/vnd.isac.fcs',
+ 'fdf' => 'application/vnd.fdf',
+ 'fe_launch' => 'application/vnd.denovo.fcselayout-link',
+ 'fg5' => 'application/vnd.fujitsu.oasysgp',
+ 'fgd' => 'application/x-director',
+ 'fh' => 'image/x-freehand',
+ 'fh4' => 'image/x-freehand',
+ 'fh5' => 'image/x-freehand',
+ 'fh7' => 'image/x-freehand',
+ 'fhc' => 'image/x-freehand',
+ 'fig' => 'application/x-xfig',
+ 'fli' => 'video/x-fli',
+ 'flo' => 'application/vnd.micrografx.flo',
+ 'flv' => 'video/x-flv',
+ 'flw' => 'application/vnd.kde.kivio',
+ 'flx' => 'text/vnd.fmi.flexstor',
+ 'fly' => 'text/vnd.fly',
+ 'fm' => 'application/vnd.framemaker',
+ 'fnc' => 'application/vnd.frogans.fnc',
+ 'for' => 'text/x-fortran',
+ 'fpx' => 'image/vnd.fpx',
+ 'frame' => 'application/vnd.framemaker',
+ 'fsc' => 'application/vnd.fsc.weblaunch',
+ 'fst' => 'image/vnd.fst',
+ 'ftc' => 'application/vnd.fluxtime.clip',
+ 'fti' => 'application/vnd.anser-web-funds-transfer-initiation',
+ 'fvt' => 'video/vnd.fvt',
+ 'fxp' => 'application/vnd.adobe.fxp',
+ 'fxpl' => 'application/vnd.adobe.fxp',
+ 'fzs' => 'application/vnd.fuzzysheet',
+ 'g2w' => 'application/vnd.geoplan',
+ 'g3' => 'image/g3fax',
+ 'g3w' => 'application/vnd.geospace',
+ 'gac' => 'application/vnd.groove-account',
+ 'gdl' => 'model/vnd.gdl',
+ 'geo' => 'application/vnd.dynageo',
+ 'gex' => 'application/vnd.geometry-explorer',
+ 'ggb' => 'application/vnd.geogebra.file',
+ 'ggt' => 'application/vnd.geogebra.tool',
+ 'ghf' => 'application/vnd.groove-help',
+ 'gif' => 'image/gif',
+ 'gim' => 'application/vnd.groove-identity-message',
+ 'gmx' => 'application/vnd.gmx',
+ 'gnumeric' => 'application/x-gnumeric',
+ 'gph' => 'application/vnd.flographit',
+ 'gqf' => 'application/vnd.grafeq',
+ 'gqs' => 'application/vnd.grafeq',
+ 'gram' => 'application/srgs',
+ 'gre' => 'application/vnd.geometry-explorer',
+ 'grv' => 'application/vnd.groove-injector',
+ 'grxml' => 'application/srgs+xml',
+ 'gsf' => 'application/x-font-ghostscript',
+ 'gtar' => 'application/x-gtar',
+ 'gtm' => 'application/vnd.groove-tool-message',
+ 'gtw' => 'model/vnd.gtw',
+ 'gv' => 'text/vnd.graphviz',
+ 'gxt' => 'application/vnd.geonext',
+ 'h' => 'text/x-c',
+ 'h261' => 'video/h261',
+ 'h263' => 'video/h263',
+ 'h264' => 'video/h264',
+ 'hal' => 'application/vnd.hal+xml',
+ 'hbci' => 'application/vnd.hbci',
+ 'hdf' => 'application/x-hdf',
+ 'hh' => 'text/x-c',
+ 'hlp' => 'application/winhlp',
+ 'hpgl' => 'application/vnd.hp-hpgl',
+ 'hpid' => 'application/vnd.hp-hpid',
+ 'hps' => 'application/vnd.hp-hps',
+ 'hqx' => 'application/mac-binhex40',
+ 'hta' => 'application/octet-stream',
+ 'htc' => 'text/html',
+ 'htke' => 'application/vnd.kenameaapp',
+ 'htm' => 'text/html',
+ 'html' => 'text/html',
+ 'hvd' => 'application/vnd.yamaha.hv-dic',
+ 'hvp' => 'application/vnd.yamaha.hv-voice',
+ 'hvs' => 'application/vnd.yamaha.hv-script',
+ 'i2g' => 'application/vnd.intergeo',
+ 'icc' => 'application/vnd.iccprofile',
+ 'ice' => 'x-conference/x-cooltalk',
+ 'icm' => 'application/vnd.iccprofile',
+ 'ico' => 'image/x-icon',
+ 'ics' => 'text/calendar',
+ 'ief' => 'image/ief',
+ 'ifb' => 'text/calendar',
+ 'ifm' => 'application/vnd.shana.informed.formdata',
+ 'iges' => 'model/iges',
+ 'igl' => 'application/vnd.igloader',
+ 'igm' => 'application/vnd.insors.igm',
+ 'igs' => 'model/iges',
+ 'igx' => 'application/vnd.micrografx.igx',
+ 'iif' => 'application/vnd.shana.informed.interchange',
+ 'imp' => 'application/vnd.accpac.simply.imp',
+ 'ims' => 'application/vnd.ms-ims',
+ 'in' => 'text/plain',
+ 'ini' => 'text/plain',
+ 'ipfix' => 'application/ipfix',
+ 'ipk' => 'application/vnd.shana.informed.package',
+ 'irm' => 'application/vnd.ibm.rights-management',
+ 'irp' => 'application/vnd.irepository.package+xml',
+ 'iso' => 'application/octet-stream',
+ 'itp' => 'application/vnd.shana.informed.formtemplate',
+ 'ivp' => 'application/vnd.immervision-ivp',
+ 'ivu' => 'application/vnd.immervision-ivu',
+ 'jad' => 'text/vnd.sun.j2me.app-descriptor',
+ 'jam' => 'application/vnd.jam',
+ 'jar' => 'application/java-archive',
+ 'java' => 'text/x-java-source',
+ 'jisp' => 'application/vnd.jisp',
+ 'jlt' => 'application/vnd.hp-jlyt',
+ 'jnlp' => 'application/x-java-jnlp-file',
+ 'joda' => 'application/vnd.joost.joda-archive',
+ 'jpe' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'jpgm' => 'video/jpm',
+ 'jpgv' => 'video/jpeg',
+ 'jpm' => 'video/jpm',
+ 'js' => 'text/javascript',
+ 'json' => 'application/json',
+ 'kar' => 'audio/midi',
+ 'karbon' => 'application/vnd.kde.karbon',
+ 'kfo' => 'application/vnd.kde.kformula',
+ 'kia' => 'application/vnd.kidspiration',
+ 'kml' => 'application/vnd.google-earth.kml+xml',
+ 'kmz' => 'application/vnd.google-earth.kmz',
+ 'kne' => 'application/vnd.kinar',
+ 'knp' => 'application/vnd.kinar',
+ 'kon' => 'application/vnd.kde.kontour',
+ 'kpr' => 'application/vnd.kde.kpresenter',
+ 'kpt' => 'application/vnd.kde.kpresenter',
+ 'ksp' => 'application/vnd.kde.kspread',
+ 'ktr' => 'application/vnd.kahootz',
+ 'ktx' => 'image/ktx',
+ 'ktz' => 'application/vnd.kahootz',
+ 'kwd' => 'application/vnd.kde.kword',
+ 'kwt' => 'application/vnd.kde.kword',
+ 'lasxml' => 'application/vnd.las.las+xml',
+ 'latex' => 'application/x-latex',
+ 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop',
+ 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml',
+ 'les' => 'application/vnd.hhe.lesson-player',
+ 'lha' => 'application/octet-stream',
+ 'link66' => 'application/vnd.route66.link66+xml',
+ 'list' => 'text/plain',
+ 'list3820' => 'application/vnd.ibm.modcap',
+ 'listafp' => 'application/vnd.ibm.modcap',
+ 'log' => 'text/plain',
+ 'lostxml' => 'application/lost+xml',
+ 'lrf' => 'application/octet-stream',
+ 'lrm' => 'application/vnd.ms-lrm',
+ 'ltf' => 'application/vnd.frogans.ltf',
+ 'lvp' => 'audio/vnd.lucent.voice',
+ 'lwp' => 'application/vnd.lotus-wordpro',
+ 'lzh' => 'application/octet-stream',
+ 'm13' => 'application/x-msmediaview',
+ 'm14' => 'application/x-msmediaview',
+ 'm1v' => 'video/mpeg',
+ 'm21' => 'application/mp21',
+ 'm2a' => 'audio/mpeg',
+ 'm2v' => 'video/mpeg',
+ 'm3a' => 'audio/mpeg',
+ 'm3u' => 'audio/x-mpegurl',
+ 'm3u8' => 'application/vnd.apple.mpegurl',
+ 'm4a' => 'audio/mp4',
+ 'm4u' => 'video/vnd.mpegurl',
+ 'm4v' => 'video/mp4',
+ 'ma' => 'application/mathematica',
+ 'mads' => 'application/mads+xml',
+ 'mag' => 'application/vnd.ecowin.chart',
+ 'maker' => 'application/vnd.framemaker',
+ 'man' => 'text/troff',
+ 'mathml' => 'application/mathml+xml',
+ 'mb' => 'application/mathematica',
+ 'mbk' => 'application/vnd.mobius.mbk',
+ 'mbox' => 'application/mbox',
+ 'mc1' => 'application/vnd.medcalcdata',
+ 'mcd' => 'application/vnd.mcd',
+ 'mcurl' => 'text/vnd.curl.mcurl',
+ 'mdb' => 'application/x-msaccess',
+ 'mdi' => 'image/vnd.ms-modi',
+ 'me' => 'text/troff',
+ 'mesh' => 'model/mesh',
+ 'meta4' => 'application/metalink4+xml',
+ 'mets' => 'application/mets+xml',
+ 'mfm' => 'application/vnd.mfmp',
+ 'mgp' => 'application/vnd.osgeo.mapguide.package',
+ 'mgz' => 'application/vnd.proteus.magazine',
+ 'mid' => 'audio/midi',
+ 'midi' => 'audio/midi',
+ 'mif' => 'application/vnd.mif',
+ 'mime' => 'message/rfc822',
+ 'mj2' => 'video/mj2',
+ 'mjp2' => 'video/mj2',
+ 'mlp' => 'application/vnd.dolby.mlp',
+ 'mmd' => 'application/vnd.chipnuts.karaoke-mmd',
+ 'mmf' => 'application/vnd.smaf',
+ 'mmr' => 'image/vnd.fujixerox.edmics-mmr',
+ 'mny' => 'application/x-msmoney',
+ 'mobi' => 'application/x-mobipocket-ebook',
+ 'mods' => 'application/mods+xml',
+ 'mov' => 'video/quicktime',
+ 'movie' => 'video/x-sgi-movie',
+ 'mp2' => 'audio/mpeg',
+ 'mp21' => 'application/mp21',
+ 'mp2a' => 'audio/mpeg',
+ 'mp3' => 'audio/mpeg',
+ 'mp4' => 'video/mp4',
+ 'mp4a' => 'audio/mp4',
+ 'mp4s' => 'application/mp4',
+ 'mp4v' => 'video/mp4',
+ 'mpc' => 'application/vnd.mophun.certificate',
+ 'mpe' => 'video/mpeg',
+ 'mpeg' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'mpg4' => 'video/mp4',
+ 'mpga' => 'audio/mpeg',
+ 'mpkg' => 'application/vnd.apple.installer+xml',
+ 'mpm' => 'application/vnd.blueice.multipass',
+ 'mpn' => 'application/vnd.mophun.application',
+ 'mpp' => 'application/vnd.ms-project',
+ 'mpt' => 'application/vnd.ms-project',
+ 'mpy' => 'application/vnd.ibm.minipay',
+ 'mqy' => 'application/vnd.mobius.mqy',
+ 'mrc' => 'application/marc',
+ 'mrcx' => 'application/marcxml+xml',
+ 'ms' => 'text/troff',
+ 'mscml' => 'application/mediaservercontrol+xml',
+ 'mseed' => 'application/vnd.fdsn.mseed',
+ 'mseq' => 'application/vnd.mseq',
+ 'msf' => 'application/vnd.epson.msf',
+ 'msh' => 'model/mesh',
+ 'msi' => 'application/x-msdownload',
+ 'msl' => 'application/vnd.mobius.msl',
+ 'msty' => 'application/vnd.muvee.style',
+ 'mts' => 'model/vnd.mts',
+ 'mus' => 'application/vnd.musician',
+ 'musicxml' => 'application/vnd.recordare.musicxml+xml',
+ 'mvb' => 'application/x-msmediaview',
+ 'mwf' => 'application/vnd.mfer',
+ 'mxf' => 'application/mxf',
+ 'mxl' => 'application/vnd.recordare.musicxml',
+ 'mxml' => 'application/xv+xml',
+ 'mxs' => 'application/vnd.triscape.mxs',
+ 'mxu' => 'video/vnd.mpegurl',
+ 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install',
+ 'n3' => 'text/n3',
+ 'nb' => 'application/mathematica',
+ 'nbp' => 'application/vnd.wolfram.player',
+ 'nc' => 'application/x-netcdf',
+ 'ncx' => 'application/x-dtbncx+xml',
+ 'ngdat' => 'application/vnd.nokia.n-gage.data',
+ 'nlu' => 'application/vnd.neurolanguage.nlu',
+ 'nml' => 'application/vnd.enliven',
+ 'nnd' => 'application/vnd.noblenet-directory',
+ 'nns' => 'application/vnd.noblenet-sealer',
+ 'nnw' => 'application/vnd.noblenet-web',
+ 'npx' => 'image/vnd.net-fpx',
+ 'nsf' => 'application/vnd.lotus-notes',
+ 'oa2' => 'application/vnd.fujitsu.oasys2',
+ 'oa3' => 'application/vnd.fujitsu.oasys3',
+ 'oas' => 'application/vnd.fujitsu.oasys',
+ 'obd' => 'application/x-msbinder',
+ 'oda' => 'application/oda',
+ 'odb' => 'application/vnd.oasis.opendocument.database',
+ 'odc' => 'application/vnd.oasis.opendocument.chart',
+ 'odf' => 'application/vnd.oasis.opendocument.formula',
+ 'odft' => 'application/vnd.oasis.opendocument.formula-template',
+ 'odg' => 'application/vnd.oasis.opendocument.graphics',
+ 'odi' => 'application/vnd.oasis.opendocument.image',
+ 'odm' => 'application/vnd.oasis.opendocument.text-master',
+ 'odp' => 'application/vnd.oasis.opendocument.presentation',
+ 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
+ 'odt' => 'application/vnd.oasis.opendocument.text',
+ 'oga' => 'audio/ogg',
+ 'ogg' => 'audio/ogg',
+ 'ogv' => 'video/ogg',
+ 'ogx' => 'application/ogg',
+ 'onepkg' => 'application/onenote',
+ 'onetmp' => 'application/onenote',
+ 'onetoc' => 'application/onenote',
+ 'onetoc2' => 'application/onenote',
+ 'opf' => 'application/oebps-package+xml',
+ 'oprc' => 'application/vnd.palm',
+ 'org' => 'application/vnd.lotus-organizer',
+ 'osf' => 'application/vnd.yamaha.openscoreformat',
+ 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml',
+ 'otc' => 'application/vnd.oasis.opendocument.chart-template',
+ 'otf' => 'application/x-font-otf',
+ 'otg' => 'application/vnd.oasis.opendocument.graphics-template',
+ 'oth' => 'application/vnd.oasis.opendocument.text-web',
+ 'oti' => 'application/vnd.oasis.opendocument.image-template',
+ 'otp' => 'application/vnd.oasis.opendocument.presentation-template',
+ 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
+ 'ott' => 'application/vnd.oasis.opendocument.text-template',
+ 'oxt' => 'application/vnd.openofficeorg.extension',
+ 'p' => 'text/x-pascal',
+ 'p10' => 'application/pkcs10',
+ 'p12' => 'application/x-pkcs12',
+ 'p7b' => 'application/x-pkcs7-certificates',
+ 'p7c' => 'application/pkcs7-mime',
+ 'p7m' => 'application/pkcs7-mime',
+ 'p7r' => 'application/x-pkcs7-certreqresp',
+ 'p7s' => 'application/pkcs7-signature',
+ 'p8' => 'application/pkcs8',
+ 'pas' => 'text/x-pascal',
+ 'paw' => 'application/vnd.pawaafile',
+ 'pbd' => 'application/vnd.powerbuilder6',
+ 'pbm' => 'image/x-portable-bitmap',
+ 'pcf' => 'application/x-font-pcf',
+ 'pcl' => 'application/vnd.hp-pcl',
+ 'pclxl' => 'application/vnd.hp-pclxl',
+ 'pct' => 'image/x-pict',
+ 'pcurl' => 'application/vnd.curl.pcurl',
+ 'pcx' => 'image/x-pcx',
+ 'pdb' => 'application/vnd.palm',
+ 'pdf' => 'application/pdf',
+ 'pfa' => 'application/x-font-type1',
+ 'pfb' => 'application/x-font-type1',
+ 'pfm' => 'application/x-font-type1',
+ 'pfr' => 'application/font-tdpfr',
+ 'pfx' => 'application/x-pkcs12',
+ 'pgm' => 'image/x-portable-graymap',
+ 'pgn' => 'application/x-chess-pgn',
+ 'pgp' => 'application/pgp-encrypted',
+ 'php' => 'text/x-php',
+ 'phps' => 'application/x-httpd-phps',
+ 'pic' => 'image/x-pict',
+ 'pkg' => 'application/octet-stream',
+ 'pki' => 'application/pkixcmp',
+ 'pkipath' => 'application/pkix-pkipath',
+ 'plb' => 'application/vnd.3gpp.pic-bw-large',
+ 'plc' => 'application/vnd.mobius.plc',
+ 'plf' => 'application/vnd.pocketlearn',
+ 'pls' => 'application/pls+xml',
+ 'pml' => 'application/vnd.ctc-posml',
+ 'png' => 'image/png',
+ 'pnm' => 'image/x-portable-anymap',
+ 'portpkg' => 'application/vnd.macports.portpkg',
+ 'pot' => 'application/vnd.ms-powerpoint',
+ 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12',
+ 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
+ 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12',
+ 'ppd' => 'application/vnd.cups-ppd',
+ 'ppm' => 'image/x-portable-pixmap',
+ 'pps' => 'application/vnd.ms-powerpoint',
+ 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12',
+ 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
+ 'ppt' => 'application/vnd.ms-powerpoint',
+ 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'pqa' => 'application/vnd.palm',
+ 'prc' => 'application/x-mobipocket-ebook',
+ 'pre' => 'application/vnd.lotus-freelance',
+ 'prf' => 'application/pics-rules',
+ 'ps' => 'application/postscript',
+ 'psb' => 'application/vnd.3gpp.pic-bw-small',
+ 'psd' => 'image/vnd.adobe.photoshop',
+ 'psf' => 'application/x-font-linux-psf',
+ 'pskcxml' => 'application/pskc+xml',
+ 'ptid' => 'application/vnd.pvi.ptid1',
+ 'pub' => 'application/x-mspublisher',
+ 'pvb' => 'application/vnd.3gpp.pic-bw-var',
+ 'pwn' => 'application/vnd.3m.post-it-notes',
+ 'pya' => 'audio/vnd.ms-playready.media.pya',
+ 'pyv' => 'video/vnd.ms-playready.media.pyv',
+ 'qam' => 'application/vnd.epson.quickanime',
+ 'qbo' => 'application/vnd.intu.qbo',
+ 'qfx' => 'application/vnd.intu.qfx',
+ 'qps' => 'application/vnd.publishare-delta-tree',
+ 'qt' => 'video/quicktime',
+ 'qwd' => 'application/vnd.quark.quarkxpress',
+ 'qwt' => 'application/vnd.quark.quarkxpress',
+ 'qxb' => 'application/vnd.quark.quarkxpress',
+ 'qxd' => 'application/vnd.quark.quarkxpress',
+ 'qxl' => 'application/vnd.quark.quarkxpress',
+ 'qxt' => 'application/vnd.quark.quarkxpress',
+ 'ra' => 'audio/x-pn-realaudio',
+ 'ram' => 'audio/x-pn-realaudio',
+ 'rar' => 'application/x-rar-compressed',
+ 'ras' => 'image/x-cmu-raster',
+ 'rb' => 'text/plain',
+ 'rcprofile' => 'application/vnd.ipunplugged.rcprofile',
+ 'rdf' => 'application/rdf+xml',
+ 'rdz' => 'application/vnd.data-vision.rdz',
+ 'rep' => 'application/vnd.businessobjects',
+ 'res' => 'application/x-dtbresource+xml',
+ 'resx' => 'text/xml',
+ 'rgb' => 'image/x-rgb',
+ 'rif' => 'application/reginfo+xml',
+ 'rip' => 'audio/vnd.rip',
+ 'rl' => 'application/resource-lists+xml',
+ 'rlc' => 'image/vnd.fujixerox.edmics-rlc',
+ 'rld' => 'application/resource-lists-diff+xml',
+ 'rm' => 'application/vnd.rn-realmedia',
+ 'rmi' => 'audio/midi',
+ 'rmp' => 'audio/x-pn-realaudio-plugin',
+ 'rms' => 'application/vnd.jcp.javame.midlet-rms',
+ 'rnc' => 'application/relax-ng-compact-syntax',
+ 'roff' => 'text/troff',
+ 'rp9' => 'application/vnd.cloanto.rp9',
+ 'rpss' => 'application/vnd.nokia.radio-presets',
+ 'rpst' => 'application/vnd.nokia.radio-preset',
+ 'rq' => 'application/sparql-query',
+ 'rs' => 'application/rls-services+xml',
+ 'rsd' => 'application/rsd+xml',
+ 'rss' => 'application/rss+xml',
+ 'rtf' => 'application/rtf',
+ 'rtx' => 'text/richtext',
+ 's' => 'text/x-asm',
+ 'saf' => 'application/vnd.yamaha.smaf-audio',
+ 'sbml' => 'application/sbml+xml',
+ 'sc' => 'application/vnd.ibm.secure-container',
+ 'scd' => 'application/x-msschedule',
+ 'scm' => 'application/vnd.lotus-screencam',
+ 'scq' => 'application/scvp-cv-request',
+ 'scs' => 'application/scvp-cv-response',
+ 'scurl' => 'text/vnd.curl.scurl',
+ 'sda' => 'application/vnd.stardivision.draw',
+ 'sdc' => 'application/vnd.stardivision.calc',
+ 'sdd' => 'application/vnd.stardivision.impress',
+ 'sdkd' => 'application/vnd.solent.sdkm+xml',
+ 'sdkm' => 'application/vnd.solent.sdkm+xml',
+ 'sdp' => 'application/sdp',
+ 'sdw' => 'application/vnd.stardivision.writer',
+ 'see' => 'application/vnd.seemail',
+ 'seed' => 'application/vnd.fdsn.seed',
+ 'sema' => 'application/vnd.sema',
+ 'semd' => 'application/vnd.semd',
+ 'semf' => 'application/vnd.semf',
+ 'ser' => 'application/java-serialized-object',
+ 'setpay' => 'application/set-payment-initiation',
+ 'setreg' => 'application/set-registration-initiation',
+ 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data',
+ 'sfs' => 'application/vnd.spotfire.sfs',
+ 'sgl' => 'application/vnd.stardivision.writer-global',
+ 'sgm' => 'text/sgml',
+ 'sgml' => 'text/sgml',
+ 'sh' => 'application/x-sh',
+ 'shar' => 'application/x-shar',
+ 'shf' => 'application/shf+xml',
+ 'sig' => 'application/pgp-signature',
+ 'silo' => 'model/mesh',
+ 'sis' => 'application/vnd.symbian.install',
+ 'sisx' => 'application/vnd.symbian.install',
+ 'sit' => 'application/x-stuffit',
+ 'sitx' => 'application/x-stuffitx',
+ 'skd' => 'application/vnd.koan',
+ 'skm' => 'application/vnd.koan',
+ 'skp' => 'application/vnd.koan',
+ 'skt' => 'application/vnd.koan',
+ 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12',
+ 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
+ 'slt' => 'application/vnd.epson.salt',
+ 'sm' => 'application/vnd.stepmania.stepchart',
+ 'smf' => 'application/vnd.stardivision.math',
+ 'smi' => 'application/smil+xml',
+ 'smil' => 'application/smil+xml',
+ 'snd' => 'audio/basic',
+ 'snf' => 'application/x-font-snf',
+ 'so' => 'application/octet-stream',
+ 'spc' => 'application/x-pkcs7-certificates',
+ 'spf' => 'application/vnd.yamaha.smaf-phrase',
+ 'spl' => 'application/x-futuresplash',
+ 'spot' => 'text/vnd.in3d.spot',
+ 'spp' => 'application/scvp-vp-response',
+ 'spq' => 'application/scvp-vp-request',
+ 'spx' => 'audio/ogg',
+ 'src' => 'application/x-wais-source',
+ 'sru' => 'application/sru+xml',
+ 'srx' => 'application/sparql-results+xml',
+ 'sse' => 'application/vnd.kodak-descriptor',
+ 'ssf' => 'application/vnd.epson.ssf',
+ 'ssml' => 'application/ssml+xml',
+ 'st' => 'application/vnd.sailingtracker.track',
+ 'stc' => 'application/vnd.sun.xml.calc.template',
+ 'std' => 'application/vnd.sun.xml.draw.template',
+ 'stf' => 'application/vnd.wt.stf',
+ 'sti' => 'application/vnd.sun.xml.impress.template',
+ 'stk' => 'application/hyperstudio',
+ 'stl' => 'application/vnd.ms-pki.stl',
+ 'str' => 'application/vnd.pg.format',
+ 'stw' => 'application/vnd.sun.xml.writer.template',
+ 'sub' => 'image/vnd.dvb.subtitle',
+ 'sus' => 'application/vnd.sus-calendar',
+ 'susp' => 'application/vnd.sus-calendar',
+ 'sv4cpio' => 'application/x-sv4cpio',
+ 'sv4crc' => 'application/x-sv4crc',
+ 'svc' => 'application/vnd.dvb.service',
+ 'svd' => 'application/vnd.svd',
+ 'svg' => 'image/svg+xml',
+ 'svgz' => 'image/svg+xml',
+ 'swa' => 'application/x-director',
+ 'swf' => 'application/x-shockwave-flash',
+ 'swi' => 'application/vnd.aristanetworks.swi',
+ 'sxc' => 'application/vnd.sun.xml.calc',
+ 'sxd' => 'application/vnd.sun.xml.draw',
+ 'sxg' => 'application/vnd.sun.xml.writer.global',
+ 'sxi' => 'application/vnd.sun.xml.impress',
+ 'sxm' => 'application/vnd.sun.xml.math',
+ 'sxw' => 'application/vnd.sun.xml.writer',
+ 't' => 'text/troff',
+ 'tao' => 'application/vnd.tao.intent-module-archive',
+ 'tar' => 'application/x-tar',
+ 'tcap' => 'application/vnd.3gpp2.tcap',
+ 'tcl' => 'application/x-tcl',
+ 'teacher' => 'application/vnd.smart.teacher',
+ 'tei' => 'application/tei+xml',
+ 'teicorpus' => 'application/tei+xml',
+ 'tex' => 'application/x-tex',
+ 'texi' => 'application/x-texinfo',
+ 'texinfo' => 'application/x-texinfo',
+ 'text' => 'text/plain',
+ 'tfi' => 'application/thraud+xml',
+ 'tfm' => 'application/x-tex-tfm',
+ 'thmx' => 'application/vnd.ms-officetheme',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'tmo' => 'application/vnd.tmobile-livetv',
+ 'torrent' => 'application/x-bittorrent',
+ 'tpl' => 'application/vnd.groove-tool-template',
+ 'tpt' => 'application/vnd.trid.tpt',
+ 'tr' => 'text/troff',
+ 'tra' => 'application/vnd.trueapp',
+ 'trm' => 'application/x-msterminal',
+ 'tsd' => 'application/timestamped-data',
+ 'tsv' => 'text/tab-separated-values',
+ 'ttc' => 'application/x-font-ttf',
+ 'ttf' => 'application/x-font-ttf',
+ 'ttl' => 'text/turtle',
+ 'twd' => 'application/vnd.simtech-mindmapper',
+ 'twds' => 'application/vnd.simtech-mindmapper',
+ 'txd' => 'application/vnd.genomatix.tuxedo',
+ 'txf' => 'application/vnd.mobius.txf',
+ 'txt' => 'text/plain',
+ 'u32' => 'application/x-authorware-bin',
+ 'udeb' => 'application/x-debian-package',
+ 'ufd' => 'application/vnd.ufdl',
+ 'ufdl' => 'application/vnd.ufdl',
+ 'umj' => 'application/vnd.umajin',
+ 'unityweb' => 'application/vnd.unity',
+ 'uoml' => 'application/vnd.uoml+xml',
+ 'uri' => 'text/uri-list',
+ 'uris' => 'text/uri-list',
+ 'urls' => 'text/uri-list',
+ 'ustar' => 'application/x-ustar',
+ 'utz' => 'application/vnd.uiq.theme',
+ 'uu' => 'text/x-uuencode',
+ 'uva' => 'audio/vnd.dece.audio',
+ 'uvd' => 'application/vnd.dece.data',
+ 'uvf' => 'application/vnd.dece.data',
+ 'uvg' => 'image/vnd.dece.graphic',
+ 'uvh' => 'video/vnd.dece.hd',
+ 'uvi' => 'image/vnd.dece.graphic',
+ 'uvm' => 'video/vnd.dece.mobile',
+ 'uvp' => 'video/vnd.dece.pd',
+ 'uvs' => 'video/vnd.dece.sd',
+ 'uvt' => 'application/vnd.dece.ttml+xml',
+ 'uvu' => 'video/vnd.uvvu.mp4',
+ 'uvv' => 'video/vnd.dece.video',
+ 'uvva' => 'audio/vnd.dece.audio',
+ 'uvvd' => 'application/vnd.dece.data',
+ 'uvvf' => 'application/vnd.dece.data',
+ 'uvvg' => 'image/vnd.dece.graphic',
+ 'uvvh' => 'video/vnd.dece.hd',
+ 'uvvi' => 'image/vnd.dece.graphic',
+ 'uvvm' => 'video/vnd.dece.mobile',
+ 'uvvp' => 'video/vnd.dece.pd',
+ 'uvvs' => 'video/vnd.dece.sd',
+ 'uvvt' => 'application/vnd.dece.ttml+xml',
+ 'uvvu' => 'video/vnd.uvvu.mp4',
+ 'uvvv' => 'video/vnd.dece.video',
+ 'uvvx' => 'application/vnd.dece.unspecified',
+ 'uvx' => 'application/vnd.dece.unspecified',
+ 'vcd' => 'application/x-cdlink',
+ 'vcf' => 'text/x-vcard',
+ 'vcg' => 'application/vnd.groove-vcard',
+ 'vcs' => 'text/x-vcalendar',
+ 'vcx' => 'application/vnd.vcx',
+ 'vis' => 'application/vnd.visionary',
+ 'viv' => 'video/vnd.vivo',
+ 'vor' => 'application/vnd.stardivision.writer',
+ 'vox' => 'application/x-authorware-bin',
+ 'vrml' => 'model/vrml',
+ 'vsd' => 'application/vnd.visio',
+ 'vsf' => 'application/vnd.vsf',
+ 'vss' => 'application/vnd.visio',
+ 'vst' => 'application/vnd.visio',
+ 'vsw' => 'application/vnd.visio',
+ 'vtu' => 'model/vnd.vtu',
+ 'vxml' => 'application/voicexml+xml',
+ 'w3d' => 'application/x-director',
+ 'wad' => 'application/x-doom',
+ 'wav' => 'audio/x-wav',
+ 'wax' => 'audio/x-ms-wax',
+ 'wbmp' => 'image/vnd.wap.wbmp',
+ 'wbs' => 'application/vnd.criticaltools.wbs+xml',
+ 'wbxml' => 'application/vnd.wap.wbxml',
+ 'wcm' => 'application/vnd.ms-works',
+ 'wdb' => 'application/vnd.ms-works',
+ 'weba' => 'audio/webm',
+ 'webm' => 'video/webm',
+ 'webp' => 'image/webp',
+ 'wg' => 'application/vnd.pmi.widget',
+ 'wgt' => 'application/widget',
+ 'wks' => 'application/vnd.ms-works',
+ 'wm' => 'video/x-ms-wm',
+ 'wma' => 'audio/x-ms-wma',
+ 'wmd' => 'application/x-ms-wmd',
+ 'wmf' => 'application/x-msmetafile',
+ 'wml' => 'text/vnd.wap.wml',
+ 'wmlc' => 'application/vnd.wap.wmlc',
+ 'wmls' => 'text/vnd.wap.wmlscript',
+ 'wmlsc' => 'application/vnd.wap.wmlscriptc',
+ 'wmv' => 'video/x-ms-wmv',
+ 'wmx' => 'video/x-ms-wmx',
+ 'wmz' => 'application/x-ms-wmz',
+ 'woff' => 'application/x-font-woff',
+ 'wpd' => 'application/vnd.wordperfect',
+ 'wpl' => 'application/vnd.ms-wpl',
+ 'wps' => 'application/vnd.ms-works',
+ 'wqd' => 'application/vnd.wqd',
+ 'wri' => 'application/x-mswrite',
+ 'wrl' => 'model/vrml',
+ 'wsdl' => 'application/wsdl+xml',
+ 'wspolicy' => 'application/wspolicy+xml',
+ 'wtb' => 'application/vnd.webturbo',
+ 'wvx' => 'video/x-ms-wvx',
+ 'x32' => 'application/x-authorware-bin',
+ 'x3d' => 'application/vnd.hzn-3d-crossword',
+ 'xap' => 'application/x-silverlight-app',
+ 'xar' => 'application/vnd.xara',
+ 'xbap' => 'application/x-ms-xbap',
+ 'xbd' => 'application/vnd.fujixerox.docuworks.binder',
+ 'xbm' => 'image/x-xbitmap',
+ 'xdf' => 'application/xcap-diff+xml',
+ 'xdm' => 'application/vnd.syncml.dm+xml',
+ 'xdp' => 'application/vnd.adobe.xdp+xml',
+ 'xdssc' => 'application/dssc+xml',
+ 'xdw' => 'application/vnd.fujixerox.docuworks',
+ 'xenc' => 'application/xenc+xml',
+ 'xer' => 'application/patch-ops-error+xml',
+ 'xfdf' => 'application/vnd.adobe.xfdf',
+ 'xfdl' => 'application/vnd.xfdl',
+ 'xht' => 'application/xhtml+xml',
+ 'xhtml' => 'application/xhtml+xml',
+ 'xhvml' => 'application/xv+xml',
+ 'xif' => 'image/vnd.xiff',
+ 'xla' => 'application/vnd.ms-excel',
+ 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12',
+ 'xlc' => 'application/vnd.ms-excel',
+ 'xlm' => 'application/vnd.ms-excel',
+ 'xls' => 'application/vnd.ms-excel',
+ 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12',
+ 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xlt' => 'application/vnd.ms-excel',
+ 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12',
+ 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
+ 'xlw' => 'application/vnd.ms-excel',
+ 'xml' => 'application/xml',
+ 'xo' => 'application/vnd.olpc-sugar',
+ 'xop' => 'application/xop+xml',
+ 'xpi' => 'application/x-xpinstall',
+ 'xpm' => 'image/x-xpixmap',
+ 'xpr' => 'application/vnd.is-xpr',
+ 'xps' => 'application/vnd.ms-xpsdocument',
+ 'xpw' => 'application/vnd.intercon.formnet',
+ 'xpx' => 'application/vnd.intercon.formnet',
+ 'xsl' => 'application/xml',
+ 'xslt' => 'application/xslt+xml',
+ 'xsm' => 'application/vnd.syncml+xml',
+ 'xspf' => 'application/xspf+xml',
+ 'xul' => 'application/vnd.mozilla.xul+xml',
+ 'xvm' => 'application/xv+xml',
+ 'xvml' => 'application/xv+xml',
+ 'xwd' => 'image/x-xwindowdump',
+ 'xyz' => 'chemical/x-xyz',
+ 'yaml' => 'text/yaml',
+ 'yang' => 'application/yang',
+ 'yin' => 'application/yin+xml',
+ 'yml' => 'text/yaml',
+ 'zaz' => 'application/vnd.zzazz.deck+xml',
+ 'zip' => 'application/zip',
+ 'zir' => 'application/vnd.zul',
+ 'zirz' => 'application/vnd.zul',
+ 'zmm' => 'application/vnd.handheld-entertainment+xml'
+ );
+
+ /**
+ * Get a singleton instance of the class
+ *
+ * @return self
+ * @codeCoverageIgnore
+ */
+ public static function getInstance()
+ {
+ if (!self::$instance) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Get a mimetype value from a file extension
+ *
+ * @param string $extension File extension
+ *
+ * @return string|null
+ *
+ */
+ public function fromExtension($extension)
+ {
+ $extension = strtolower($extension);
+
+ return isset($this->mimetypes[$extension])
+ ? $this->mimetypes[$extension]
+ : null;
+ }
+
+ /**
+ * Get a mimetype from a filename
+ *
+ * @param string $filename Filename to generate a mimetype from
+ *
+ * @return string|null
+ */
+ public function fromFilename($filename)
+ {
+ return $this->fromExtension(pathinfo($filename, PATHINFO_EXTENSION));
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Post/MultipartBody.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Post/MultipartBody.php
new file mode 100644
index 0000000..72ce6e1
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Post/MultipartBody.php
@@ -0,0 +1,292 @@
+boundary = $boundary ?: uniqid();
+ $this->fields = $fields;
+ $this->files = $files;
+
+ // Ensure each file is a PostFileInterface
+ foreach ($this->files as $file) {
+ if (!$file instanceof PostFileInterface) {
+ throw new \InvalidArgumentException('All POST fields must '
+ . 'implement PostFieldInterface');
+ }
+ }
+ }
+
+ public function __toString()
+ {
+ $this->seek(0);
+
+ return $this->getContents();
+ }
+
+ public function getContents($maxLength = -1)
+ {
+ $buffer = '';
+
+ while (!$this->eof()) {
+ if ($maxLength === -1) {
+ $read = 1048576;
+ } else {
+ $len = strlen($buffer);
+ if ($len == $maxLength) {
+ break;
+ }
+ $read = min(1048576, $maxLength - $len);
+ }
+ $buffer .= $this->read($read);
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * Get the boundary
+ *
+ * @return string
+ */
+ public function getBoundary()
+ {
+ return $this->boundary;
+ }
+
+ public function close()
+ {
+ $this->detach();
+ }
+
+ public function detach()
+ {
+ $this->fields = $this->files = [];
+ }
+
+ /**
+ * The stream has reached an EOF when all of the fields and files have been
+ * read.
+ * {@inheritdoc}
+ */
+ public function eof()
+ {
+ return $this->currentField == count($this->fields) &&
+ $this->currentFile == count($this->files);
+ }
+
+ public function tell()
+ {
+ return $this->pos;
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ /**
+ * The steam is seekable by default, but all attached files must be
+ * seekable too.
+ * {@inheritdoc}
+ */
+ public function isSeekable()
+ {
+ foreach ($this->files as $file) {
+ if (!$file->getContent()->isSeekable()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public function getSize()
+ {
+ if ($this->size === null) {
+ foreach ($this->files as $file) {
+ // We must be able to ascertain the size of each attached file
+ if (null === ($size = $file->getContent()->getSize())) {
+ return null;
+ }
+ $this->size += strlen($this->getFileHeaders($file)) + $size;
+ }
+ foreach (array_keys($this->fields) as $key) {
+ $this->size += strlen($this->getFieldString($key));
+ }
+ $this->size += strlen("\r\n--{$this->boundary}--");
+ }
+
+ return $this->size;
+ }
+
+ public function read($length)
+ {
+ $content = '';
+ if ($this->buffer && !$this->buffer->eof()) {
+ $content .= $this->buffer->read($length);
+ }
+ if ($delta = $length - strlen($content)) {
+ $content .= $this->readData($delta);
+ }
+
+ if ($content === '' && !$this->sentLast) {
+ $this->sentLast = true;
+ $content = "\r\n--{$this->boundary}--";
+ }
+
+ return $content;
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if ($offset != 0 || $whence != SEEK_SET || !$this->isSeekable()) {
+ return false;
+ }
+
+ foreach ($this->files as $file) {
+ if (!$file->getContent()->seek(0)) {
+ throw new \RuntimeException('Rewind on multipart file failed '
+ . 'even though it shouldn\'t have');
+ }
+ }
+
+ $this->buffer = $this->sentLast = null;
+ $this->pos = $this->currentField = $this->currentFile = 0;
+ $this->bufferedHeaders = [];
+
+ return true;
+ }
+
+ public function write($string)
+ {
+ return false;
+ }
+
+ /**
+ * No data is in the read buffer, so more needs to be pulled in from fields
+ * and files.
+ *
+ * @param int $length Amount of data to read
+ *
+ * @return string
+ */
+ private function readData($length)
+ {
+ $result = '';
+
+ if ($this->currentField < count($this->fields)) {
+ $result = $this->readField($length);
+ }
+
+ if ($result === '' && $this->currentFile < count($this->files)) {
+ $result = $this->readFile($length);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Create a new stream buffer and inject form-data
+ *
+ * @param int $length Amount of data to read from the stream buffer
+ *
+ * @return string
+ */
+ private function readField($length)
+ {
+ $name = array_keys($this->fields)[++$this->currentField - 1];
+ $this->buffer = Stream\create($this->getFieldString($name));
+
+ return $this->buffer->read($length);
+ }
+
+ /**
+ * Read data from a POST file, fill the read buffer with any overflow
+ *
+ * @param int $length Amount of data to read from the file
+ *
+ * @return string
+ */
+ private function readFile($length)
+ {
+ $current = $this->files[$this->currentFile];
+
+ // Got to the next file and recursively return the read value, or bail
+ // if no more data can be read.
+ if ($current->getContent()->eof()) {
+ return ++$this->currentFile == count($this->files)
+ ? ''
+ : $this->readFile($length);
+ }
+
+ // If this is the start of a file, then send the headers to the read
+ // buffer.
+ if (!isset($this->bufferedHeaders[$this->currentFile])) {
+ $this->buffer = Stream\create($this->getFileHeaders($current));
+ $this->bufferedHeaders[$this->currentFile] = true;
+ }
+
+ // More data needs to be read to meet the limit, so pull from the file
+ $content = $this->buffer ? $this->buffer->read($length) : '';
+ if (($remaining = $length - strlen($content)) > 0) {
+ $content .= $current->getContent()->read($remaining);
+ }
+
+ return $content;
+ }
+
+ private function getFieldString($key)
+ {
+ return sprintf(
+ "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n",
+ $this->boundary,
+ $key,
+ $this->fields[$key]
+ );
+ }
+
+ private function getFileHeaders(PostFileInterface $file)
+ {
+ $headers = '';
+ foreach ($file->getHeaders() as $key => $value) {
+ $headers .= "{$key}: {$value}\r\n";
+ }
+
+ return "--{$this->boundary}\r\n" . trim($headers) . "\r\n\r\n";
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Post/PostBody.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Post/PostBody.php
new file mode 100644
index 0000000..6ba253b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Post/PostBody.php
@@ -0,0 +1,282 @@
+files || $this->forceMultipart) {
+ $request->setHeader(
+ 'Content-Type',
+ 'multipart/form-data; boundary=' . $this->getBody()->getBoundary()
+ );
+ } elseif ($this->fields) {
+ $request->setHeader('Content-Type', 'application/x-www-form-urlencoded');
+ }
+
+ if ($size = $this->getSize()) {
+ $request->setHeader('Content-Length', $size);
+ }
+ }
+
+ public function forceMultipartUpload($force)
+ {
+ $this->forceMultipart = $force;
+
+ return $this;
+ }
+
+ public function setAggregator(callable $aggregator)
+ {
+ $this->aggregator = $aggregator;
+ }
+
+ public function setField($name, $value)
+ {
+ $this->fields[$name] = $value;
+ $this->mutate();
+
+ return $this;
+ }
+
+ public function replaceFields(array $fields)
+ {
+ $this->fields = $fields;
+ $this->mutate();
+
+ return $this;
+ }
+
+ public function getField($name)
+ {
+ return isset($this->fields[$name]) ? $this->fields[$name] : null;
+ }
+
+ public function removeField($name)
+ {
+ unset($this->fields[$name]);
+ $this->mutate();
+
+ return $this;
+ }
+
+ public function getFields($asString = false)
+ {
+ if (!$asString) {
+ return $this->fields;
+ }
+
+ return (string) (new Query($this->fields))
+ ->setEncodingType(Query::RFC1738)
+ ->setAggregator($this->getAggregator());
+ }
+
+ public function hasField($name)
+ {
+ return isset($this->fields[$name]);
+ }
+
+ public function getFile($name)
+ {
+ foreach ($this->files as $file) {
+ if ($file->getName() == $name) {
+ return $file;
+ }
+ }
+
+ return null;
+ }
+
+ public function getFiles()
+ {
+ return $this->files;
+ }
+
+ public function addFile(PostFileInterface $file)
+ {
+ $this->files[] = $file;
+ $this->mutate();
+
+ return $this;
+ }
+
+ public function clearFiles()
+ {
+ $this->files = [];
+ $this->mutate();
+
+ return $this;
+ }
+
+ /**
+ * Returns the numbers of fields + files
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->files) + count($this->fields);
+ }
+
+ public function __toString()
+ {
+ return (string) $this->getBody();
+ }
+
+ public function getContents($maxLength = -1)
+ {
+ return $this->getBody()->getContents();
+ }
+
+ public function close()
+ {
+ return $this->body ? $this->body->close() : true;
+ }
+
+ public function detach()
+ {
+ $this->body = null;
+ $this->fields = $this->files = [];
+
+ return $this;
+ }
+
+ public function eof()
+ {
+ return $this->getBody()->eof();
+ }
+
+ public function tell()
+ {
+ return $this->body ? $this->body->tell() : 0;
+ }
+
+ public function isSeekable()
+ {
+ return true;
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ public function getSize()
+ {
+ return $this->getBody()->getSize();
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ return $this->getBody()->seek($offset, $whence);
+ }
+
+ public function read($length)
+ {
+ return $this->getBody()->read($length);
+ }
+
+ public function write($string)
+ {
+ return false;
+ }
+
+ /**
+ * Return a stream object that is built from the POST fields and files.
+ *
+ * If one has already been created, the previously created stream will be
+ * returned.
+ */
+ private function getBody()
+ {
+ if ($this->body) {
+ return $this->body;
+ } elseif ($this->files || $this->forceMultipart) {
+ return $this->body = $this->createMultipart();
+ } elseif ($this->fields) {
+ return $this->body = $this->createUrlEncoded();
+ } else {
+ return $this->body = Stream\create();
+ }
+ }
+
+ /**
+ * Get the aggregator used to join multi-valued field parameters
+ *
+ * @return callable
+ */
+ final protected function getAggregator()
+ {
+ if (!$this->aggregator) {
+ $this->aggregator = Query::phpAggregator();
+ }
+
+ return $this->aggregator;
+ }
+
+ /**
+ * Creates a multipart/form-data body stream
+ *
+ * @return MultipartBody
+ */
+ private function createMultipart()
+ {
+ // Flatten the nested query string values using the correct aggregator
+ $query = (string) (new Query($this->fields))
+ ->setEncodingType(false)
+ ->setAggregator($this->getAggregator());
+ // Convert the flattened query string back into an array
+ $fields = Query::fromString($query)->toArray();
+
+ return new MultipartBody($fields, $this->files);
+ }
+
+ /**
+ * Creates an application/x-www-form-urlencoded stream body
+ *
+ * @return Stream\StreamInterface
+ */
+ private function createUrlEncoded()
+ {
+ return Stream\create($this->getFields(true));
+ }
+
+ /**
+ * Get rid of any cached data
+ */
+ private function mutate()
+ {
+ $this->body = null;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Post/PostBodyInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Post/PostBodyInterface.php
new file mode 100644
index 0000000..4405ce2
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Post/PostBodyInterface.php
@@ -0,0 +1,129 @@
+headers = $headers;
+ $this->name = $name;
+ $this->prepareContent($content);
+ $this->prepareFilename($filename);
+ $this->prepareDefaultHeaders();
+ }
+
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ public function getFilename()
+ {
+ return $this->filename;
+ }
+
+ public function getContent()
+ {
+ return $this->content;
+ }
+
+ public function getHeaders()
+ {
+ return $this->headers;
+ }
+
+ /**
+ * Prepares the contents of a POST file.
+ *
+ * @param mixed $content Content of the POST file
+ */
+ private function prepareContent($content)
+ {
+ $this->content = $content;
+
+ if (!($this->content instanceof StreamInterface)) {
+ $this->content = \GuzzleHttp\Stream\create($this->content);
+ } elseif ($this->content instanceof MultipartBody) {
+ if (!$this->hasHeader('Content-Disposition')) {
+ $disposition = 'form-data; name="' . $this->name .'"';
+ $this->headers['Content-Disposition'] = $disposition;
+ }
+
+ if (!$this->hasHeader('Content-Type')) {
+ $this->headers['Content-Type'] = sprintf(
+ "multipart/form-data; boundary=%s",
+ $this->content->getBoundary()
+ );
+ }
+ }
+ }
+
+ /**
+ * Applies a file name to the POST file based on various checks.
+ *
+ * @param string|null $filename Filename to apply (or null to guess)
+ */
+ private function prepareFilename($filename)
+ {
+ $this->filename = $filename;
+
+ if (!$this->filename &&
+ $this->content instanceof MetadataStreamInterface
+ ) {
+ $this->filename = $this->content->getMetadata('uri');
+ }
+
+ if (!$this->filename || substr($this->filename, 0, 6) === 'php://') {
+ $this->filename = $this->name;
+ }
+ }
+
+ /**
+ * Applies default Content-Disposition and Content-Type headers if needed.
+ */
+ private function prepareDefaultHeaders()
+ {
+ // Set a default content-disposition header if one was no provided
+ if (!$this->hasHeader('Content-Disposition')) {
+ $this->headers['Content-Disposition'] = sprintf(
+ 'form-data; filename="%s"; name="%s"',
+ basename($this->filename),
+ $this->name
+ );
+ }
+
+ // Set a default Content-Type if one was not supplied
+ if (!$this->hasHeader('Content-Type')) {
+ $this->headers['Content-Type'] = Mimetypes::getInstance()
+ ->fromFilename($this->filename) ?: 'text/plain';
+ }
+ }
+
+ /**
+ * Check if a specific header exists on the POST file by name.
+ *
+ * @param string $name Case-insensitive header to check
+ *
+ * @return bool
+ */
+ private function hasHeader($name)
+ {
+ return isset(array_change_key_case($this->headers)[strtolower($name)]);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Post/PostFileInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Post/PostFileInterface.php
new file mode 100644
index 0000000..205dd96
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Post/PostFileInterface.php
@@ -0,0 +1,42 @@
+add($key, $value);
+ $foundDuplicates = true;
+ } elseif ($paramIsPhpStyleArray) {
+ $q[$key] = array($value);
+ } else {
+ $q[$key] = $value;
+ }
+ } else {
+ $q->add($key, null);
+ }
+ }
+
+ // Use the duplicate aggregator if duplicates were found and not using
+ // PHP style arrays.
+ if ($foundDuplicates && !$foundPhpStyle) {
+ $q->setAggregator(self::duplicateAggregator());
+ }
+
+ return $q;
+ }
+
+ /**
+ * Convert the query string parameters to a query string string
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ if (!$this->data) {
+ return '';
+ }
+
+ // The default aggregator is statically cached
+ static $defaultAggregator;
+
+ if (!$this->aggregator) {
+ if (!$defaultAggregator) {
+ $defaultAggregator = self::phpAggregator();
+ }
+ $this->aggregator = $defaultAggregator;
+ }
+
+ $result = '';
+ $aggregator = $this->aggregator;
+
+ foreach ($aggregator($this->data) as $key => $values) {
+ foreach ($values as $value) {
+ if ($result) {
+ $result .= '&';
+ }
+ if ($this->encoding == self::RFC1738) {
+ $result .= urlencode($key);
+ if ($value !== null) {
+ $result .= '=' . urlencode($value);
+ }
+ } elseif ($this->encoding == self::RFC3986) {
+ $result .= rawurlencode($key);
+ if ($value !== null) {
+ $result .= '=' . rawurlencode($value);
+ }
+ } else {
+ $result .= $key;
+ if ($value !== null) {
+ $result .= '=' . $value;
+ }
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Controls how multi-valued query string parameters are aggregated into a
+ * string.
+ *
+ * $query->setAggregator($query::duplicateAggregator());
+ *
+ * @param callable $aggregator Callable used to convert a deeply nested
+ * array of query string variables into a flattened array of key value
+ * pairs. The callable accepts an array of query data and returns a
+ * flattened array of key value pairs where each value is an array of
+ * strings.
+ *
+ * @return self
+ */
+ public function setAggregator(callable $aggregator)
+ {
+ $this->aggregator = $aggregator;
+
+ return $this;
+ }
+
+ /**
+ * Specify how values are URL encoded
+ *
+ * @param string|bool $type One of 'RFC1738', 'RFC3986', or false to disable encoding
+ *
+ * @return self
+ * @throws \InvalidArgumentException
+ */
+ public function setEncodingType($type)
+ {
+ if ($type === false || $type === self::RFC1738 || $type === self::RFC3986) {
+ $this->encoding = $type;
+ } else {
+ throw new \InvalidArgumentException('Invalid URL encoding type');
+ }
+
+ return $this;
+ }
+
+ /**
+ * Query string aggregator that does not aggregate nested query string
+ * values and allows duplicates in the resulting array.
+ *
+ * Example: http://test.com?q=1&q=2
+ *
+ * @return callable
+ */
+ public static function duplicateAggregator()
+ {
+ return function (array $data) {
+ return self::walkQuery($data, '', function ($key, $prefix) {
+ return is_int($key) ? $prefix : "{$prefix}[{$key}]";
+ });
+ };
+ }
+
+ /**
+ * Aggregates nested query string variables using the same technique as
+ * ``http_build_query()``.
+ *
+ * @param bool $numericIndices Pass false to not include numeric indices
+ * when multi-values query string parameters are present.
+ *
+ * @return callable
+ */
+ public static function phpAggregator($numericIndices = true)
+ {
+ return function (array $data) use ($numericIndices) {
+ return self::walkQuery(
+ $data,
+ '',
+ function ($key, $prefix) use ($numericIndices) {
+ return !$numericIndices && is_int($key)
+ ? "{$prefix}[]"
+ : "{$prefix}[{$key}]";
+ }
+ );
+ };
+ }
+
+ /**
+ * Easily create query aggregation functions by providing a key prefix
+ * function to this query string array walker.
+ *
+ * @param array $query Query string to walk
+ * @param string $keyPrefix Key prefix (start with '')
+ * @param callable $prefixer Function used to create a key prefix
+ *
+ * @return array
+ */
+ public static function walkQuery(array $query, $keyPrefix, callable $prefixer)
+ {
+ $result = [];
+ foreach ($query as $key => $value) {
+ if ($keyPrefix) {
+ $key = $prefixer($key, $keyPrefix);
+ }
+ if (is_array($value)) {
+ $result += self::walkQuery($value, $key, $prefixer);
+ } elseif (isset($result[$key])) {
+ $result[$key][] = $value;
+ } else {
+ $result[$key] = array($value);
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/Cookie.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/Cookie.php
new file mode 100644
index 0000000..4b8a2c0
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/Cookie.php
@@ -0,0 +1,59 @@
+cookieJar = $cookieJar ?: new CookieJar();
+ }
+
+ public function getEvents()
+ {
+ // Fire the cookie plugin complete event before redirecting
+ return [
+ 'before' => ['onBefore'],
+ 'complete' => ['onComplete', RequestEvents::REDIRECT_RESPONSE + 10]
+ ];
+ }
+
+ /**
+ * Get the cookie cookieJar
+ *
+ * @return CookieJarInterface
+ */
+ public function getCookieJar()
+ {
+ return $this->cookieJar;
+ }
+
+ public function onBefore(BeforeEvent $event)
+ {
+ $this->cookieJar->addCookieHeader($event->getRequest());
+ }
+
+ public function onComplete(CompleteEvent $event)
+ {
+ $this->cookieJar->extractCookies(
+ $event->getRequest(),
+ $event->getResponse()
+ );
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/History.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/History.php
new file mode 100644
index 0000000..b2a49e0
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/History.php
@@ -0,0 +1,138 @@
+limit = $limit;
+ }
+
+ public function getEvents()
+ {
+ return [
+ 'complete' => ['onComplete', RequestEvents::EARLY],
+ 'error' => ['onError', RequestEvents::EARLY],
+ ];
+ }
+
+ /**
+ * Convert to a string that contains all request and response headers
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $lines = array();
+ foreach ($this->transactions as $entry) {
+ $response = isset($entry['response']) ? $entry['response'] : '';
+ $lines[] = '> ' . trim($entry['request']) . "\n\n< " . trim($response) . "\n";
+ }
+
+ return implode("\n", $lines);
+ }
+
+ public function onComplete(CompleteEvent $event)
+ {
+ $this->add($event->getRequest(), $event->getResponse());
+ }
+
+ public function onError(ErrorEvent $event)
+ {
+ $this->add($event->getRequest(), $event->getResponse());
+ }
+
+ /**
+ * Returns an Iterator that yields associative array values where each
+ * associative array contains a 'request' and 'response' key.
+ *
+ * @return \Iterator
+ */
+ public function getIterator()
+ {
+ return new \ArrayIterator($this->transactions);
+ }
+
+ /**
+ * Get all of the requests sent through the plugin
+ *
+ * @return RequestInterface[]
+ */
+ public function getRequests()
+ {
+ return array_map(function ($t) {
+ return $t['request'];
+ }, $this->transactions);
+ }
+
+ /**
+ * Get the number of requests in the history
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->transactions);
+ }
+
+ /**
+ * Get the last request sent
+ *
+ * @return RequestInterface
+ */
+ public function getLastRequest()
+ {
+ return end($this->transactions)['request'];
+ }
+
+ /**
+ * Get the last response in the history
+ *
+ * @return ResponseInterface|null
+ */
+ public function getLastResponse()
+ {
+ return end($this->transactions)['response'];
+ }
+
+ /**
+ * Clears the history
+ */
+ public function clear()
+ {
+ $this->transactions = array();
+ }
+
+ /**
+ * Add a request to the history
+ *
+ * @param RequestInterface $request Request to add
+ * @param ResponseInterface $response Response of the request
+ */
+ private function add(
+ RequestInterface $request,
+ ResponseInterface $response = null
+ ) {
+ $this->transactions[] = ['request' => $request, 'response' => $response];
+ if (count($this->transactions) > $this->limit) {
+ array_shift($this->transactions);
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/HttpError.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/HttpError.php
new file mode 100644
index 0000000..f2f72f1
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/HttpError.php
@@ -0,0 +1,34 @@
+ ['onComplete', RequestEvents::VERIFY_RESPONSE]];
+ }
+
+ /**
+ * Throw a RequestException on an HTTP protocol error
+ *
+ * @param CompleteEvent $event Emitted event
+ * @throws RequestException
+ */
+ public function onComplete(CompleteEvent $event)
+ {
+ $code = (string) $event->getResponse()->getStatusCode();
+ // Throw an exception for an unsuccessful response
+ if ($code[0] === '4' || $code[0] === '5') {
+ throw RequestException::create($event->getRequest(), $event->getResponse());
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/Mock.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/Mock.php
new file mode 100644
index 0000000..99a3d18
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/Mock.php
@@ -0,0 +1,143 @@
+factory = new MessageFactory();
+ $this->readBodies = $readBodies;
+ $this->addMultiple($items);
+ }
+
+ public function getEvents()
+ {
+ // Fire the event last, after signing
+ return ['before' => ['onBefore', RequestEvents::SIGN_REQUEST - 10]];
+ }
+
+ /**
+ * @throws \OutOfBoundsException|\Exception
+ */
+ public function onBefore(BeforeEvent $event)
+ {
+ if (!$item = array_shift($this->queue)) {
+ throw new \OutOfBoundsException('Mock queue is empty');
+ } elseif ($item instanceof RequestException) {
+ throw $item;
+ }
+
+ // Emulate the receiving of the response headers
+ $request = $event->getRequest();
+ $transaction = new Transaction($event->getClient(), $request);
+ $transaction->setResponse($item);
+ $request->getEmitter()->emit(
+ 'headers',
+ new HeadersEvent($transaction)
+ );
+
+ // Emulate reading a response body
+ if ($this->readBodies && $request->getBody()) {
+ while (!$request->getBody()->eof()) {
+ $request->getBody()->read(8096);
+ }
+ }
+
+ $event->intercept($item);
+ }
+
+ public function count()
+ {
+ return count($this->queue);
+ }
+
+ /**
+ * Add a response to the end of the queue
+ *
+ * @param string|ResponseInterface $response Response or path to response file
+ *
+ * @return self
+ * @throws \InvalidArgumentException if a string or Response is not passed
+ */
+ public function addResponse($response)
+ {
+ if (is_string($response)) {
+ $response = file_exists($response)
+ ? $this->factory->fromMessage(file_get_contents($response))
+ : $this->factory->fromMessage($response);
+ } elseif (!($response instanceof ResponseInterface)) {
+ throw new \InvalidArgumentException('Response must a message '
+ . 'string, response object, or path to a file');
+ }
+
+ $this->queue[] = $response;
+
+ return $this;
+ }
+
+ /**
+ * Add an exception to the end of the queue
+ *
+ * @param RequestException $e Exception to throw when the request is executed
+ *
+ * @return self
+ */
+ public function addException(RequestException $e)
+ {
+ $this->queue[] = $e;
+
+ return $this;
+ }
+
+ /**
+ * Add multiple items to the queue
+ *
+ * @param array $items Items to add
+ */
+ public function addMultiple(array $items)
+ {
+ foreach ($items as $item) {
+ if ($item instanceof RequestException) {
+ $this->addException($item);
+ } else {
+ $this->addResponse($item);
+ }
+ }
+ }
+
+ /**
+ * Clear the queue
+ */
+ public function clearQueue()
+ {
+ $this->queue = [];
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/Prepare.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/Prepare.php
new file mode 100644
index 0000000..2d82acd
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/Prepare.php
@@ -0,0 +1,136 @@
+ ['onBefore', RequestEvents::PREPARE_REQUEST]];
+ }
+
+ public function onBefore(BeforeEvent $event)
+ {
+ $request = $event->getRequest();
+
+ // Set the appropriate Content-Type for a request if one is not set and
+ // there are form fields
+ if (!($body = $request->getBody())) {
+ return;
+ }
+
+ $this->addContentLength($request, $body);
+
+ if ($body instanceof PostBodyInterface) {
+ // Synchronize the POST body with the request's headers
+ $body->applyRequestHeaders($request);
+ } elseif (!$request->hasHeader('Content-Type')) {
+ $this->addContentType($request, $body);
+ }
+
+ $this->addExpectHeader($request, $body);
+ }
+
+ private function addContentType(
+ RequestInterface $request,
+ StreamInterface $body
+ ) {
+ if (!($body instanceof MetadataStreamInterface)) {
+ return;
+ }
+
+ if (!($uri = $body->getMetadata('uri'))) {
+ return;
+ }
+
+ // Guess the content-type based on the stream's "uri" metadata value.
+ // The file extension is used to determine the appropriate mime-type.
+ if ($contentType = Mimetypes::getInstance()->fromFilename($uri)) {
+ $request->setHeader('Content-Type', $contentType);
+ }
+ }
+
+ private function addContentLength(
+ RequestInterface $request,
+ StreamInterface $body
+ ) {
+ // Set the Content-Length header if it can be determined, and never
+ // send a Transfer-Encoding: chunked and Content-Length header in
+ // the same request.
+ if ($request->hasHeader('Content-Length')) {
+ // Remove transfer-encoding if content-length is set.
+ $request->removeHeader('Transfer-Encoding');
+ return;
+ }
+
+ if ($request->hasHeader('Transfer-Encoding')) {
+ return;
+ }
+
+ if (null !== ($size = $body->getSize())) {
+ $request->setHeader('Content-Length', $size)
+ ->removeHeader('Transfer-Encoding');
+ } elseif ('1.1' == $request->getProtocolVersion()) {
+ // Use chunked Transfer-Encoding if there is no determinable
+ // content-length header and we're using HTTP/1.1.
+ $request->setHeader('Transfer-Encoding', 'chunked')
+ ->removeHeader('Content-Length');
+ }
+ }
+
+ private function addExpectHeader(
+ RequestInterface $request,
+ StreamInterface $body
+ ) {
+ // Determine if the Expect header should be used
+ if ($request->hasHeader('Expect')) {
+ return;
+ }
+
+ $expect = $request->getConfig()['expect'];
+
+ // Return if disabled or if you're not using HTTP/1.1
+ if ($expect === false || $request->getProtocolVersion() !== '1.1') {
+ return;
+ }
+
+ // The expect header is unconditionally enabled
+ if ($expect === true) {
+ $request->setHeader('Expect', '100-Continue');
+ return;
+ }
+
+ // By default, send the expect header when the payload is > 1mb
+ if ($expect === null) {
+ $expect = 1048576;
+ }
+
+ // Always add if the body cannot be rewound, the size cannot be
+ // determined, or the size is greater than the cutoff threshold
+ $size = $body->getSize();
+ if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
+ $request->setHeader('Expect', '100-Continue');
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/Redirect.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/Redirect.php
new file mode 100644
index 0000000..bd8988d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Subscriber/Redirect.php
@@ -0,0 +1,172 @@
+ ['onComplete', RequestEvents::REDIRECT_RESPONSE]];
+ }
+
+ /**
+ * Rewind the entity body of the request if needed
+ *
+ * @param RequestInterface $redirectRequest
+ * @throws CouldNotRewindStreamException
+ */
+ public static function rewindEntityBody(RequestInterface $redirectRequest)
+ {
+ // Rewind the entity body of the request if needed
+ if ($redirectRequest->getBody()) {
+ $body = $redirectRequest->getBody();
+ // Only rewind the body if some of it has been read already, and
+ // throw an exception if the rewind fails
+ if ($body->tell() && !$body->seek(0)) {
+ throw new CouldNotRewindStreamException(
+ 'Unable to rewind the non-seekable request body after redirecting',
+ $redirectRequest
+ );
+ }
+ }
+ }
+
+ /**
+ * Called when a request receives a redirect response
+ *
+ * @param CompleteEvent $event Event emitted
+ * @throws TooManyRedirectsException
+ */
+ public function onComplete(CompleteEvent $event)
+ {
+ $response = $event->getResponse();
+
+ if (substr($response->getStatusCode(), 0, 1) != '3' ||
+ !$response->hasHeader('Location')
+ ) {
+ return;
+ }
+
+ $redirectCount = 0;
+ $request = $event->getRequest();
+ $redirectResponse = $response;
+ $max = $request->getConfig()->getPath('redirect/max') ?: 5;
+
+ do {
+ if (++$redirectCount > $max) {
+ throw new TooManyRedirectsException(
+ "Will not follow more than {$redirectCount} redirects",
+ $request
+ );
+ }
+ $redirectRequest = $this->createRedirectRequest($request, $redirectResponse);
+ $redirectResponse = $event->getClient()->send($redirectRequest);
+ } while (substr($redirectResponse->getStatusCode(), 0, 1) == '3' &&
+ $redirectResponse->hasHeader('Location')
+ );
+
+ if ($redirectResponse !== $response) {
+ $event->intercept($redirectResponse);
+ }
+ }
+
+ /**
+ * Create a redirect request for a specific request object
+ *
+ * Takes into account strict RFC compliant redirection (e.g. redirect POST
+ * with POST) vs doing what most clients do (e.g. redirect POST with GET).
+ *
+ * @param RequestInterface $request
+ * @param ResponseInterface $response
+ *
+ * @return RequestInterface Returns a new redirect request
+ * @throws CouldNotRewindStreamException If the body cannot be rewound.
+ */
+ private function createRedirectRequest(
+ RequestInterface $request,
+ ResponseInterface $response
+ ) {
+ $config = $request->getConfig();
+
+ // Use a GET request if this is an entity enclosing request and we are
+ // not forcing RFC compliance, but rather emulating what all browsers
+ // would do. Be sure to disable redirects on the clone.
+ $redirectRequest = clone $request;
+ $redirectRequest->getEmitter()->detach($this);
+ $statusCode = $response->getStatusCode();
+
+ if ($statusCode == 303 ||
+ ($statusCode <= 302 && $request->getBody() &&
+ !$config->getPath('redirect/strict'))
+ ) {
+ $redirectRequest->setMethod('GET');
+ $redirectRequest->setBody(null);
+ }
+
+ $this->setRedirectUrl($redirectRequest, $response);
+ $this->rewindEntityBody($redirectRequest);
+
+ // Add the Referer header if it is told to do so and only
+ // add the header if we are not redirecting from https to http.
+ if ($config->getPath('redirect/referer') && (
+ $redirectRequest->getScheme() == 'https' ||
+ $redirectRequest->getScheme() == $request->getScheme()
+ )) {
+ $url = Url::fromString($request->getUrl());
+ $url->setUsername(null)->setPassword(null);
+ $redirectRequest->setHeader('Referer', (string) $url);
+ }
+
+ return $redirectRequest;
+ }
+
+ /**
+ * Set the appropriate URL on the request based on the location header
+ *
+ * @param RequestInterface $redirectRequest
+ * @param ResponseInterface $response
+ */
+ private function setRedirectUrl(
+ RequestInterface $redirectRequest,
+ ResponseInterface $response
+ ) {
+ $location = $response->getHeader('Location');
+ $location = Url::fromString($location);
+
+ // Combine location with the original URL if it is not absolute.
+ if (!$location->isAbsolute()) {
+ $originalUrl = Url::fromString($redirectRequest->getUrl());
+ // Remove query string parameters and just take what is present on
+ // the redirect Location header
+ $originalUrl->getQuery()->clear();
+ $location = $originalUrl->combine($location);
+ }
+
+ $redirectRequest->setUrl($location);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/ToArrayInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/ToArrayInterface.php
new file mode 100644
index 0000000..7c4120f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/ToArrayInterface.php
@@ -0,0 +1,16 @@
+ array('prefix' => '', 'joiner' => ',', 'query' => false),
+ '+' => array('prefix' => '', 'joiner' => ',', 'query' => false),
+ '#' => array('prefix' => '#', 'joiner' => ',', 'query' => false),
+ '.' => array('prefix' => '.', 'joiner' => '.', 'query' => false),
+ '/' => array('prefix' => '/', 'joiner' => '/', 'query' => false),
+ ';' => array('prefix' => ';', 'joiner' => ';', 'query' => true),
+ '?' => array('prefix' => '?', 'joiner' => '&', 'query' => true),
+ '&' => array('prefix' => '&', 'joiner' => '&', 'query' => true)
+ );
+
+ /** @var array Delimiters */
+ private static $delims = array(':', '/', '?', '#', '[', ']', '@', '!', '$',
+ '&', '\'', '(', ')', '*', '+', ',', ';', '=');
+
+ /** @var array Percent encoded delimiters */
+ private static $delimsPct = array('%3A', '%2F', '%3F', '%23', '%5B', '%5D',
+ '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C',
+ '%3B', '%3D');
+
+ public function expand($template, array $variables)
+ {
+ if (false === strpos($template, '{')) {
+ return $template;
+ }
+
+ $this->template = $template;
+ $this->variables = $variables;
+
+ return preg_replace_callback(
+ '/\{([^\}]+)\}/',
+ [$this, 'expandMatch'],
+ $this->template
+ );
+ }
+
+ /**
+ * Parse an expression into parts
+ *
+ * @param string $expression Expression to parse
+ *
+ * @return array Returns an associative array of parts
+ */
+ private function parseExpression($expression)
+ {
+ $result = array();
+
+ if (isset(self::$operatorHash[$expression[0]])) {
+ $result['operator'] = $expression[0];
+ $expression = substr($expression, 1);
+ } else {
+ $result['operator'] = '';
+ }
+
+ foreach (explode(',', $expression) as $value) {
+ $value = trim($value);
+ $varspec = array();
+ if ($colonPos = strpos($value, ':')) {
+ $varspec['value'] = substr($value, 0, $colonPos);
+ $varspec['modifier'] = ':';
+ $varspec['position'] = (int) substr($value, $colonPos + 1);
+ } elseif (substr($value, -1) == '*') {
+ $varspec['modifier'] = '*';
+ $varspec['value'] = substr($value, 0, -1);
+ } else {
+ $varspec['value'] = (string) $value;
+ $varspec['modifier'] = '';
+ }
+ $result['values'][] = $varspec;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Process an expansion
+ *
+ * @param array $matches Matches met in the preg_replace_callback
+ *
+ * @return string Returns the replacement string
+ */
+ private function expandMatch(array $matches)
+ {
+ static $rfc1738to3986 = array('+' => '%20', '%7e' => '~');
+
+ $replacements = array();
+ $parsed = self::parseExpression($matches[1]);
+ $prefix = self::$operatorHash[$parsed['operator']]['prefix'];
+ $joiner = self::$operatorHash[$parsed['operator']]['joiner'];
+ $useQuery = self::$operatorHash[$parsed['operator']]['query'];
+
+ foreach ($parsed['values'] as $value) {
+
+ if (!isset($this->variables[$value['value']])) {
+ continue;
+ }
+
+ $variable = $this->variables[$value['value']];
+ $actuallyUseQuery = $useQuery;
+ $expanded = '';
+
+ if (is_array($variable)) {
+
+ $isAssoc = $this->isAssoc($variable);
+ $kvp = array();
+ foreach ($variable as $key => $var) {
+
+ if ($isAssoc) {
+ $key = rawurlencode($key);
+ $isNestedArray = is_array($var);
+ } else {
+ $isNestedArray = false;
+ }
+
+ if (!$isNestedArray) {
+ $var = rawurlencode($var);
+ if ($parsed['operator'] == '+' ||
+ $parsed['operator'] == '#'
+ ) {
+ $var = $this->decodeReserved($var);
+ }
+ }
+
+ if ($value['modifier'] == '*') {
+ if ($isAssoc) {
+ if ($isNestedArray) {
+ // Nested arrays must allow for deeply nested
+ // structures.
+ $var = strtr(
+ http_build_query([$key => $var]),
+ $rfc1738to3986
+ );
+ } else {
+ $var = $key . '=' . $var;
+ }
+ } elseif ($key > 0 && $actuallyUseQuery) {
+ $var = $value['value'] . '=' . $var;
+ }
+ }
+
+ $kvp[$key] = $var;
+ }
+
+ if (empty($variable)) {
+ $actuallyUseQuery = false;
+ } elseif ($value['modifier'] == '*') {
+ $expanded = implode($joiner, $kvp);
+ if ($isAssoc) {
+ // Don't prepend the value name when using the explode
+ // modifier with an associative array.
+ $actuallyUseQuery = false;
+ }
+ } else {
+ if ($isAssoc) {
+ // When an associative array is encountered and the
+ // explode modifier is not set, then the result must be
+ // a comma separated list of keys followed by their
+ // respective values.
+ foreach ($kvp as $k => &$v) {
+ $v = $k . ',' . $v;
+ }
+ }
+ $expanded = implode(',', $kvp);
+ }
+
+ } else {
+ if ($value['modifier'] == ':') {
+ $variable = substr($variable, 0, $value['position']);
+ }
+ $expanded = rawurlencode($variable);
+ if ($parsed['operator'] == '+' || $parsed['operator'] == '#') {
+ $expanded = $this->decodeReserved($expanded);
+ }
+ }
+
+ if ($actuallyUseQuery) {
+ if (!$expanded && $joiner != '&') {
+ $expanded = $value['value'];
+ } else {
+ $expanded = $value['value'] . '=' . $expanded;
+ }
+ }
+
+ $replacements[] = $expanded;
+ }
+
+ $ret = implode($joiner, $replacements);
+ if ($ret && $prefix) {
+ return $prefix . $ret;
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Determines if an array is associative.
+ *
+ * This makes the assumption that input arrays are sequences or hashes.
+ * This assumption is a tradeoff for accuracy in favor of speed, but it
+ * should work in almost every case where input is supplied for a URI
+ * template.
+ *
+ * @param array $array Array to check
+ *
+ * @return bool
+ */
+ private function isAssoc(array $array)
+ {
+ return $array && array_keys($array)[0] !== 0;
+ }
+
+ /**
+ * Removes percent encoding on reserved characters (used with + and #
+ * modifiers).
+ *
+ * @param string $string String to fix
+ *
+ * @return string
+ */
+ private function decodeReserved($string)
+ {
+ return str_replace(self::$delimsPct, self::$delims, $string);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Url.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Url.php
new file mode 100644
index 0000000..a305a76
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/Url.php
@@ -0,0 +1,585 @@
+ 80, 'https' => 443, 'ftp' => 21];
+
+ /** @var Query Query part of the URL */
+ private $query;
+
+ /**
+ * Factory method to create a new URL from a URL string
+ *
+ * @param string $url Full URL used to create a Url object
+ *
+ * @return Url
+ * @throws \InvalidArgumentException
+ */
+ public static function fromString($url)
+ {
+ static $defaults = array('scheme' => null, 'host' => null,
+ 'path' => null, 'port' => null, 'query' => null,
+ 'user' => null, 'pass' => null, 'fragment' => null);
+
+ if (false === ($parts = parse_url($url))) {
+ throw new \InvalidArgumentException('Unable to parse malformed '
+ . 'url: ' . $url);
+ }
+
+ $parts += $defaults;
+
+ // Convert the query string into a Query object
+ if ($parts['query'] || 0 !== strlen($parts['query'])) {
+ $parts['query'] = Query::fromString($parts['query']);
+ }
+
+ return new static($parts['scheme'], $parts['host'], $parts['user'],
+ $parts['pass'], $parts['port'], $parts['path'], $parts['query'],
+ $parts['fragment']);
+ }
+
+ /**
+ * Build a URL from parse_url parts. The generated URL will be a relative
+ * URL if a scheme or host are not provided.
+ *
+ * @param array $parts Array of parse_url parts
+ *
+ * @return string
+ */
+ public static function buildUrl(array $parts)
+ {
+ $url = $scheme = '';
+
+ if (!empty($parts['scheme'])) {
+ $scheme = $parts['scheme'];
+ $url .= $scheme . ':';
+ }
+
+ if (!empty($parts['host'])) {
+ $url .= '//';
+ if (isset($parts['user'])) {
+ $url .= $parts['user'];
+ if (isset($parts['pass'])) {
+ $url .= ':' . $parts['pass'];
+ }
+ $url .= '@';
+ }
+
+ $url .= $parts['host'];
+
+ // Only include the port if it is not the default port of the scheme
+ if (isset($parts['port']) &&
+ (!isset(self::$defaultPorts[$scheme]) ||
+ $parts['port'] != self::$defaultPorts[$scheme])
+ ) {
+ $url .= ':' . $parts['port'];
+ }
+ }
+
+ // Add the path component if present
+ if (isset($parts['path']) && strlen($parts['path'])) {
+ // Always ensure that the path begins with '/' if set and something
+ // is before the path
+ if (isset($parts['host']) && $parts['path'][0] != '/') {
+ $url .= '/';
+ }
+ $url .= $parts['path'];
+ }
+
+ // Add the query string if present
+ if (isset($parts['query'])) {
+ $queryStr = (string) $parts['query'];
+ if ($queryStr || $queryStr === '0') {
+ $url .= '?' . $queryStr;
+ }
+ }
+
+ // Ensure that # is only added to the url if fragment contains anything.
+ if (isset($parts['fragment'])) {
+ $url .= '#' . $parts['fragment'];
+ }
+
+ return $url;
+ }
+
+ /**
+ * Create a new URL from URL parts
+ *
+ * @param string $scheme Scheme of the URL
+ * @param string $host Host of the URL
+ * @param string $username Username of the URL
+ * @param string $password Password of the URL
+ * @param int $port Port of the URL
+ * @param string $path Path of the URL
+ * @param Query|array|string $query Query string of the URL
+ * @param string $fragment Fragment of the URL
+ */
+ public function __construct(
+ $scheme,
+ $host,
+ $username = null,
+ $password = null,
+ $port = null,
+ $path = null,
+ Query $query = null,
+ $fragment = null
+ ) {
+ $this->scheme = $scheme;
+ $this->host = $host;
+ $this->port = $port;
+ $this->username = $username;
+ $this->password = $password;
+ $this->fragment = $fragment;
+ if (!$query) {
+ $this->query = new Query();
+ } else {
+ $this->setQuery($query);
+ }
+ $this->setPath($path);
+ }
+
+ /**
+ * Clone the URL
+ */
+ public function __clone()
+ {
+ $this->query = clone $this->query;
+ }
+
+ /**
+ * Returns the URL as a URL string
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return static::buildUrl($this->getParts());
+ }
+
+ /**
+ * Get the parts of the URL as an array
+ *
+ * @return array
+ */
+ public function getParts()
+ {
+ return array(
+ 'scheme' => $this->scheme,
+ 'user' => $this->username,
+ 'pass' => $this->password,
+ 'host' => $this->host,
+ 'port' => $this->port,
+ 'path' => $this->path,
+ 'query' => $this->query,
+ 'fragment' => $this->fragment,
+ );
+ }
+
+ /**
+ * Set the host of the request.
+ *
+ * @param string $host Host to set (e.g. www.yahoo.com, yahoo.com)
+ *
+ * @return Url
+ */
+ public function setHost($host)
+ {
+ if (strpos($host, ':') === false) {
+ $this->host = $host;
+ } else {
+ list($host, $port) = explode(':', $host);
+ $this->host = $host;
+ $this->setPort($port);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the host part of the URL
+ *
+ * @return string
+ */
+ public function getHost()
+ {
+ return $this->host;
+ }
+
+ /**
+ * Set the scheme part of the URL (http, https, ftp, etc.)
+ *
+ * @param string $scheme Scheme to set
+ *
+ * @return Url
+ */
+ public function setScheme($scheme)
+ {
+ // Remove the default port if one is specified
+ if ($this->port && isset(self::$defaultPorts[$this->scheme]) &&
+ self::$defaultPorts[$this->scheme] == $this->port
+ ) {
+ $this->port = null;
+ }
+
+ $this->scheme = $scheme;
+
+ return $this;
+ }
+
+ /**
+ * Get the scheme part of the URL
+ *
+ * @return string
+ */
+ public function getScheme()
+ {
+ return $this->scheme;
+ }
+
+ /**
+ * Set the port part of the URL
+ *
+ * @param int $port Port to set
+ *
+ * @return Url
+ */
+ public function setPort($port)
+ {
+ $this->port = $port;
+
+ return $this;
+ }
+
+ /**
+ * Get the port part of the URl.
+ *
+ * If no port was set, this method will return the default port for the
+ * scheme of the URI.
+ *
+ * @return int|null
+ */
+ public function getPort()
+ {
+ if ($this->port) {
+ return $this->port;
+ } elseif (isset(self::$defaultPorts[$this->scheme])) {
+ return self::$defaultPorts[$this->scheme];
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the path part of the URL
+ *
+ * @param string $path Path string to set
+ *
+ * @return Url
+ */
+ public function setPath($path)
+ {
+ static $search = [' ', '?'];
+ static $replace = ['%20', '%3F'];
+ $this->path = str_replace($search, $replace, $path);
+
+ return $this;
+ }
+
+ /**
+ * Removes dot segments from a URL
+ *
+ * @return Url
+ * @link http://tools.ietf.org/html/rfc3986#section-5.2.4
+ */
+ public function removeDotSegments()
+ {
+ static $noopPaths = ['' => true, '/' => true, '*' => true];
+ static $ignoreSegments = ['' => true, '.' => true, '..' => true];
+
+ if (isset($noopPaths[$this->path])) {
+ return $this;
+ }
+
+ $results = [];
+ $segments = $this->getPathSegments();
+ foreach ($segments as $segment) {
+ if ($segment == '..') {
+ array_pop($results);
+ } elseif (!isset($ignoreSegments[$segment])) {
+ $results[] = $segment;
+ }
+ }
+
+ // Combine the normalized parts and add the leading slash if needed
+ if ($this->path[0] == '/') {
+ $this->path = '/' . implode('/', $results);
+ } else {
+ $this->path = implode('/', $results);
+ }
+
+ // Add the trailing slash if necessary
+ if ($this->path != '/' && isset($ignoreSegments[end($segments)])) {
+ $this->path .= '/';
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add a relative path to the currently set path.
+ *
+ * @param string $relativePath Relative path to add
+ *
+ * @return Url
+ */
+ public function addPath($relativePath)
+ {
+ if ($relativePath != '/' &&
+ is_string($relativePath) &&
+ strlen($relativePath) > 0
+ ) {
+ // Add a leading slash if needed
+ if ($relativePath[0] != '/') {
+ $relativePath = '/' . $relativePath;
+ }
+ $this->setPath(str_replace('//', '/', $this->path . $relativePath));
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the path part of the URL
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ /**
+ * Get the path segments of the URL as an array
+ *
+ * @return array
+ */
+ public function getPathSegments()
+ {
+ return explode('/', $this->path);
+ }
+
+ /**
+ * Set the password part of the URL
+ *
+ * @param string $password Password to set
+ *
+ * @return Url
+ */
+ public function setPassword($password)
+ {
+ $this->password = $password;
+
+ return $this;
+ }
+
+ /**
+ * Get the password part of the URL
+ *
+ * @return null|string
+ */
+ public function getPassword()
+ {
+ return $this->password;
+ }
+
+ /**
+ * Set the username part of the URL
+ *
+ * @param string $username Username to set
+ *
+ * @return Url
+ */
+ public function setUsername($username)
+ {
+ $this->username = $username;
+
+ return $this;
+ }
+
+ /**
+ * Get the username part of the URl
+ *
+ * @return null|string
+ */
+ public function getUsername()
+ {
+ return $this->username;
+ }
+
+ /**
+ * Get the query part of the URL as a Query object
+ *
+ * @return Query
+ */
+ public function getQuery()
+ {
+ return $this->query;
+ }
+
+ /**
+ * Set the query part of the URL
+ *
+ * @param Query|string|array $query Query string value to set. Can
+ * be a string that will be parsed into a Query object, an array
+ * of key value pairs, or a Query object.
+ *
+ * @return Url
+ * @throws \InvalidArgumentException
+ */
+ public function setQuery($query)
+ {
+ if ($query instanceof Query) {
+ $this->query = $query;
+ } elseif (is_string($query)) {
+ $this->query = Query::fromString($query);
+ } elseif (is_array($query)) {
+ $this->query = new Query($query);
+ } else {
+ throw new \InvalidArgumentException('Query must be a '
+ . 'QueryInterface, array, or string');
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the fragment part of the URL
+ *
+ * @return null|string
+ */
+ public function getFragment()
+ {
+ return $this->fragment;
+ }
+
+ /**
+ * Set the fragment part of the URL
+ *
+ * @param string $fragment Fragment to set
+ *
+ * @return Url
+ */
+ public function setFragment($fragment)
+ {
+ $this->fragment = $fragment;
+
+ return $this;
+ }
+
+ /**
+ * Check if this is an absolute URL
+ *
+ * @return bool
+ */
+ public function isAbsolute()
+ {
+ return $this->scheme && $this->host;
+ }
+
+ /**
+ * Combine the URL with another URL and return a new URL instance.
+ *
+ * Follows the rules specific in RFC 3986 section 5.4.
+ *
+ * @param string $url Relative URL to combine with
+ *
+ * @return Url
+ * @throws \InvalidArgumentException
+ * @link http://tools.ietf.org/html/rfc3986#section-5.4
+ */
+ public function combine($url)
+ {
+ $url = static::fromString($url);
+
+ // Use the more absolute URL as the base URL
+ if (!$this->isAbsolute() && $url->isAbsolute()) {
+ $url = $url->combine($this);
+ }
+
+ $parts = $url->getParts();
+
+ // Passing a URL with a scheme overrides everything
+ if ($parts['scheme']) {
+ return new static(
+ $parts['scheme'],
+ $parts['host'],
+ $parts['user'],
+ $parts['pass'],
+ $parts['port'],
+ $parts['path'],
+ clone $parts['query'],
+ $parts['fragment']
+ );
+ }
+
+ // Setting a host overrides the entire rest of the URL
+ if ($parts['host']) {
+ return new static(
+ $this->scheme,
+ $parts['host'],
+ $parts['user'],
+ $parts['pass'],
+ $parts['port'],
+ $parts['path'],
+ clone $parts['query'],
+ $parts['fragment']
+ );
+ }
+
+ if (!$parts['path']) {
+ // The relative URL has no path, so check if it is just a query
+ $path = $this->path ?: '';
+ $query = count($parts['query']) ? $parts['query'] : $this->query;
+ } else {
+ $query = $parts['query'];
+ if ($parts['path'][0] == '/' || !$this->path) {
+ // Overwrite the existing path if the rel path starts with "/"
+ $path = $parts['path'];
+ } else {
+ // If the relative URL does not have a path or the base URL
+ // path does not end in a "/" then overwrite the existing path
+ // up to the last "/"
+ $path = substr($this->path, 0, strrpos($this->path, '/') + 1) . $parts['path'];
+ }
+ }
+
+ $result = new self(
+ $this->scheme,
+ $this->host,
+ $this->username,
+ $this->password,
+ $this->port,
+ $path,
+ clone $query,
+ $parts['fragment']
+ );
+
+ if ($path) {
+ $result->removeDotSegments();
+ }
+
+ return $result;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/cacert.pem b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/cacert.pem
new file mode 100644
index 0000000..9794dfb
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/cacert.pem
@@ -0,0 +1,3866 @@
+##
+## ca-bundle.crt -- Bundle of CA Root Certificates
+##
+## Certificate data from Mozilla as of: Tue Apr 22 08:29:31 2014
+##
+## This is a bundle of X.509 certificates of public Certificate Authorities
+## (CA). These were automatically extracted from Mozilla's root certificates
+## file (certdata.txt). This file can be found in the mozilla source tree:
+## http://mxr.mozilla.org/mozilla-release/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1
+##
+## It contains the certificates in PEM format and therefore
+## can be directly used with curl / libcurl / php_curl, or with
+## an Apache+mod_ssl webserver for SSL client authentication.
+## Just configure this file as the SSLCACertificateFile.
+##
+
+
+GTE CyberTrust Global Root
+==========================
+-----BEGIN CERTIFICATE-----
+MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg
+Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG
+A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz
+MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL
+Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0
+IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u
+sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql
+HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID
+AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW
+M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF
+NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
+-----END CERTIFICATE-----
+
+Thawte Server CA
+================
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
+DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs
+dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE
+AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j
+b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV
+BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u
+c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG
+A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0
+ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl
+/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7
+1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR
+MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J
+GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ
+GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc=
+-----END CERTIFICATE-----
+
+Thawte Premium Server CA
+========================
+-----BEGIN CERTIFICATE-----
+MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT
+DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs
+dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE
+AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl
+ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT
+AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU
+VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2
+aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ
+cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2
+aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh
+Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/
+qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm
+SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf
+8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t
+UCemDaYj+bvLpgcUQg==
+-----END CERTIFICATE-----
+
+Equifax Secure CA
+=================
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE
+ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
+MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT
+B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB
+nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR
+fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW
+8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG
+A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE
+CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG
+A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS
+spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB
+Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961
+zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB
+BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95
+70+sB3c4
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx
+FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5
+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow
+XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz
+IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94
+f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol
+hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA
+TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah
+WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf
+Tqj/ZA1k
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority - G2
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT
+MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy
+eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
+dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT
+MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy
+eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
+dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO
+FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71
+lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB
+MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT
+1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD
+Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9
+-----END CERTIFICATE-----
+
+GlobalSign Root CA
+==================
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx
+GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds
+b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV
+BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD
+VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
+DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc
+THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb
+Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP
+c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX
+gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF
+AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj
+Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG
+j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH
+hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC
+X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----
+
+GlobalSign Root CA - R2
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv
+YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
+bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
+aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
+bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6
+ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp
+s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN
+S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL
+TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C
+ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i
+YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN
+BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp
+9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu
+01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7
+9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+-----END CERTIFICATE-----
+
+ValiCert Class 1 VA
+===================
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp
+b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh
+bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIy
+MjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0
+d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEg
+UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0
+LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIi
+GQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCm
+DuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwG
+lN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkX
+icnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nP
+Orf1LXLI
+-----END CERTIFICATE-----
+
+ValiCert Class 2 VA
+===================
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp
+b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh
+bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw
+MTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0
+d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIg
+UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0
+LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVC
+CSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7Rf
+ZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZ
+SWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbV
+UjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8
+W9ViH0Pd
+-----END CERTIFICATE-----
+
+RSA Root Certificate 1
+======================
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp
+b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh
+bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw
+MjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0
+d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMg
+UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0
+LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td
+3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89H
+BFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs
+3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjF
+V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r
+on+jjBXu
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority - G3
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
+cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
+dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1
+EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc
+cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw
+EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj
+055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
+ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f
+j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
+/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0
+xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa
+t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
+-----END CERTIFICATE-----
+
+Verisign Class 4 Public Primary Certification Authority - G3
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
+cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
+dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS
+tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM
+8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW
+Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX
+Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
+j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt
+mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
+fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd
+RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG
+UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
+-----END CERTIFICATE-----
+
+Entrust.net Secure Server CA
+============================
+-----BEGIN CERTIFICATE-----
+MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV
+BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg
+cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl
+ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv
+cml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIG
+A1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi
+eSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1p
+dGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQ
+aO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5
+gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcw
+ggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQsw
+CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5l
+dC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
+bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
+dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkw
+NTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow
+HQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA
+BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyN
+Ewr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9
+n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
+-----END CERTIFICATE-----
+
+Entrust.net Premium 2048 Secure Server CA
+=========================================
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u
+ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp
+bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
+BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx
+NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3
+d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
+MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u
+ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL
+Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr
+hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW
+nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi
+VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ
+KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy
+T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
+zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT
+J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e
+nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=
+-----END CERTIFICATE-----
+
+Baltimore CyberTrust Root
+=========================
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE
+ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li
+ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC
+SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs
+dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME
+uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB
+UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C
+G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9
+XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr
+l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI
+VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB
+BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh
+cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5
+hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa
+Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
+RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+-----END CERTIFICATE-----
+
+Equifax Secure Global eBusiness CA
+==================================
+-----BEGIN CERTIFICATE-----
+MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
+RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp
+bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx
+HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds
+b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV
+PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN
+qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn
+hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j
+BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs
+MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN
+I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY
+NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
+-----END CERTIFICATE-----
+
+Equifax Secure eBusiness CA 1
+=============================
+-----BEGIN CERTIFICATE-----
+MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
+RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB
+LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE
+ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz
+IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ
+1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a
+IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk
+MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW
+Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF
+AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5
+lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+
+KpYrtWKmpj29f5JZzVoqgrI3eQ==
+-----END CERTIFICATE-----
+
+AddTrust Low-Value Services Root
+================================
+-----BEGIN CERTIFICATE-----
+MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU
+cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw
+CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO
+ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6
+54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr
+oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1
+Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui
+GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w
+HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD
+AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT
+RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw
+HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt
+ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph
+iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
+eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr
+mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj
+ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
+-----END CERTIFICATE-----
+
+AddTrust External Root
+======================
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD
+VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw
+NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU
+cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg
+Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821
++iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw
+Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo
+aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy
+2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7
+7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P
+BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL
+VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk
+VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB
+IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl
+j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355
+e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u
+G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----
+
+AddTrust Public Services Root
+=============================
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU
+cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ
+BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l
+dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu
+nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i
+d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG
+Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw
+HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G
+A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux
+FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G
+A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4
+JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL
++YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao
+GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9
+Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H
+EufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
+-----END CERTIFICATE-----
+
+AddTrust Qualified Certificates Root
+====================================
+-----BEGIN CERTIFICATE-----
+MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU
+cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx
+CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ
+IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx
+64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3
+KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o
+L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR
+wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU
+MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE
+BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y
+azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD
+ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG
+GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X
+dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze
+RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB
+iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE=
+-----END CERTIFICATE-----
+
+Entrust Root Certification Authority
+====================================
+-----BEGIN CERTIFICATE-----
+MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV
+BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw
+b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG
+A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0
+MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu
+MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu
+Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v
+dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz
+A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww
+Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68
+j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN
+rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw
+DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1
+MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH
+hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
+A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM
+Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa
+v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS
+W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
+tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
+-----END CERTIFICATE-----
+
+RSA Security 2048 v3
+====================
+-----BEGIN CERTIFICATE-----
+MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK
+ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy
+MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb
+BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7
+Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb
+WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH
+KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP
++Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/
+MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E
+FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY
+v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj
+0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj
+VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395
+nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA
+pKnXwiJPZ9d37CAFYd4=
+-----END CERTIFICATE-----
+
+GeoTrust Global CA
+==================
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
+Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw
+MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j
+LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo
+BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet
+8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc
+T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU
+vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk
+DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q
+zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4
+d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2
+mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p
+XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm
+Mw==
+-----END CERTIFICATE-----
+
+GeoTrust Global CA 2
+====================
+-----BEGIN CERTIFICATE-----
+MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
+R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw
+MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j
+LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/
+NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k
+LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA
+Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b
+HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH
+K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7
+srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh
+ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL
+OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC
+x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF
+H4z1Ir+rzoPz4iIprn2DQKi6bA==
+-----END CERTIFICATE-----
+
+GeoTrust Universal CA
+=====================
+-----BEGIN CERTIFICATE-----
+MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
+R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1
+MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu
+Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t
+JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e
+RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs
+7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d
+8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V
+qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga
+Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB
+Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu
+KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08
+ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0
+XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB
+hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
+aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2
+qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL
+oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK
+xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF
+KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2
+DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK
+xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU
+p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI
+P/rmMuGNG2+k5o7Y+SlIis5z/iw=
+-----END CERTIFICATE-----
+
+GeoTrust Universal CA 2
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN
+R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0
+MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg
+SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0
+DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17
+j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q
+JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a
+QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2
+WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP
+20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn
+ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC
+SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG
+8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2
++/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E
+BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
+dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ
+4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+
+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq
+A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg
+Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP
+pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d
+FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp
+gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm
+X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
+-----END CERTIFICATE-----
+
+America Online Root Certification Authority 1
+=============================================
+-----BEGIN CERTIFICATE-----
+MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
+QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG
+A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg
+T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG
+v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z
+DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh
+sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP
+8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T
+AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z
+o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf
+GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF
+VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft
+3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g
+Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds
+sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
+-----END CERTIFICATE-----
+
+America Online Root Certification Authority 2
+=============================================
+-----BEGIN CERTIFICATE-----
+MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
+QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkG
+A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg
+T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC206B89en
+fHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8
+f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE18aO6lhO
+qKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JN
+RvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0
+gBe4lL8BPeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn
+6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897Gqid
+FEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6
+Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnj
+B453cMor9H124HhnAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op
+aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE
+AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FY
+T15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p
++DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXg
+JXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//Zoy
+zH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgO
+ZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh
+1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZZLF0Kjhf
+GEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y3WRayhgoPmMEEf0cjQAPuDff
+Z4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuP
+cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk=
+-----END CERTIFICATE-----
+
+Visa eCommerce Root
+===================
+-----BEGIN CERTIFICATE-----
+MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG
+EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug
+QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2
+WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm
+VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv
+bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL
+F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b
+RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0
+TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI
+/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs
+GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG
+MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc
+CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW
+YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz
+zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu
+YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt
+398znM/jra6O1I7mT1GvFpLgXPYHDw==
+-----END CERTIFICATE-----
+
+Certum Root CA
+==============
+-----BEGIN CERTIFICATE-----
+MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK
+ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla
+Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u
+by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x
+wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL
+kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ
+89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K
+Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P
+NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq
+hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+
+GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg
+GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/
+0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS
+qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw==
+-----END CERTIFICATE-----
+
+Comodo AAA Services root
+========================
+-----BEGIN CERTIFICATE-----
+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
+TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw
+MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl
+c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
+BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG
+C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs
+i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW
+Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH
+Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK
+Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f
+BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl
+cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz
+LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm
+7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z
+8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C
+12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+-----END CERTIFICATE-----
+
+Comodo Secure Services root
+===========================
+-----BEGIN CERTIFICATE-----
+MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
+TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw
+MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu
+Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi
+BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP
+9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc
+rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC
+oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V
+p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E
+FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
+gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj
+YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm
+aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm
+4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
+Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL
+DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw
+pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H
+RR3B7Hzs/Sk=
+-----END CERTIFICATE-----
+
+Comodo Trusted Services root
+============================
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS
+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg
+TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw
+MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h
+bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw
+IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7
+3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y
+/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6
+juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS
+ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud
+DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp
+ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl
+cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw
+uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
+pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA
+BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l
+R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O
+9y5Xt5hwXsjEeLBi
+-----END CERTIFICATE-----
+
+QuoVadis Root CA
+================
+-----BEGIN CERTIFICATE-----
+MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE
+ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz
+MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp
+cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD
+EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk
+J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL
+F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL
+YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen
+AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w
+PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y
+ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7
+MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj
+YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs
+ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
+Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW
+Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu
+BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw
+FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6
+tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo
+fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul
+LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x
+gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi
+5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi
+5nrQNiOKSnQ2+Q==
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 2
+==================
+-----BEGIN CERTIFICATE-----
+MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
+EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx
+ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
+aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6
+XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk
+lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB
+lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy
+lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt
+66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn
+wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh
+D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy
+BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie
+J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud
+DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU
+a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
+ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv
+Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3
+UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm
+VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK
++JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW
+IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1
+WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X
+f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II
+4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8
+VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 3
+==================
+-----BEGIN CERTIFICATE-----
+MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT
+EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx
+OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
+aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg
+DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij
+KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K
+DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv
+BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp
+p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8
+nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX
+MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM
+Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz
+uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT
+BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj
+YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
+aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB
+BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD
+VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4
+ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE
+AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV
+qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s
+hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z
+POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2
+Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp
+8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC
+bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu
+g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p
+vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr
+qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=
+-----END CERTIFICATE-----
+
+Security Communication Root CA
+==============================
+-----BEGIN CERTIFICATE-----
+MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
+U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
+HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP
+U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw
+8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM
+DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX
+5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd
+DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2
+JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw
+DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g
+0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a
+mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ
+s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ
+6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi
+FL39vmwLAw==
+-----END CERTIFICATE-----
+
+Sonera Class 2 Root CA
+======================
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG
+U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw
+NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh
+IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3
+/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT
+dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG
+f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P
+tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH
+nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT
+XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt
+0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI
+cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph
+Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx
+EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH
+llpwrN9M
+-----END CERTIFICATE-----
+
+Staat der Nederlanden Root CA
+=============================
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE
+ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g
+Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w
+HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh
+bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt
+vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P
+jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca
+C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth
+vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6
+22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV
+HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v
+dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN
+BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR
+EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw
+MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y
+nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR
+iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==
+-----END CERTIFICATE-----
+
+TDC Internet Root CA
+====================
+-----BEGIN CERTIFICATE-----
+MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMGA1UE
+ChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUx
+NjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJu
+ZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20j
+xsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvL
+znWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc
+5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6
+otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZI
+AYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMM
+VERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JM
+MTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMC
+AQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqe
+UAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0G
+CSqGSIb3DQEBBQUAA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m
+gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+
+2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzb
+O0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU
+Cbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l
+-----END CERTIFICATE-----
+
+UTN DATACorp SGC Root CA
+========================
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE
+BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
+IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ
+BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa
+MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w
+HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy
+dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys
+raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo
+wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA
+9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv
+33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud
+DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9
+BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD
+LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3
+DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0
+I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx
+EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP
+DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI
+-----END CERTIFICATE-----
+
+UTN USERFirst Hardware Root CA
+==============================
+-----BEGIN CERTIFICATE-----
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE
+BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
+IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd
+BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx
+OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0
+eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz
+ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI
+wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd
+tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8
+i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf
+Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw
+gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF
+lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF
+UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF
+BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW
+XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2
+lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn
+iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67
+nfhmqA==
+-----END CERTIFICATE-----
+
+Camerfirma Chambers of Commerce Root
+====================================
+-----BEGIN CERTIFICATE-----
+MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe
+QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i
+ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx
+NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp
+cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn
+MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC
+AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU
+xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH
+NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW
+DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV
+d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud
+EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v
+cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P
+AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh
+bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD
+VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz
+aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi
+fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD
+L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN
+UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n
+ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1
+erfutGWaIZDgqtCYvDi1czyL+Nw=
+-----END CERTIFICATE-----
+
+Camerfirma Global Chambersign Root
+==================================
+-----BEGIN CERTIFICATE-----
+MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe
+QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i
+ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx
+NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt
+YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg
+MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw
+ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J
+1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O
+by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl
+6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c
+8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/
+BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j
+aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B
+Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj
+aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y
+ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh
+bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA
+PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y
+gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ
+PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4
+IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes
+t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==
+-----END CERTIFICATE-----
+
+NetLock Notary (Class A) Root
+=============================
+-----BEGIN CERTIFICATE-----
+MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI
+EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6
+dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j
+ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX
+DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH
+EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD
+VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz
+cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM
+D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ
+z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC
+/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7
+tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6
+4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG
+A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC
+Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv
+bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu
+IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn
+LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0
+ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz
+IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh
+IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu
+b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh
+bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg
+Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp
+bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5
+ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP
+ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB
+CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr
+KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM
+8CgHrTwXZoi1/baI
+-----END CERTIFICATE-----
+
+NetLock Business (Class B) Root
+===============================
+-----BEGIN CERTIFICATE-----
+MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcT
+CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV
+BAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikg
+VGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYD
+VQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRv
+bnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sg
+VXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
+iQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2S
+o/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr
+1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV
+HQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZ
+RUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRh
+dGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0
+ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRv
+c2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg
+YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh
+c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBz
+Oi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA
+bmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl
+IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2
+YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBj
+cHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM
+43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKR
+stE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI
+-----END CERTIFICATE-----
+
+NetLock Express (Class C) Root
+==============================
+-----BEGIN CERTIFICATE-----
+MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcT
+CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV
+BAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBD
+KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJ
+BgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6
+dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9j
+ayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOB
+jQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3Z
+W3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63
+euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQw
+DgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJN
+RklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xn
+YWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBB
+IGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1i
+aXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0
+ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs
+ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBo
+dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y
+emVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5k
+IHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQ
+UyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwg
+YXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2
+xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOW
+gyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A==
+-----END CERTIFICATE-----
+
+XRamp Global CA Root
+====================
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE
+BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj
+dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx
+HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg
+U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu
+IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx
+foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE
+zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs
+AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry
+xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap
+oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC
+AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc
+/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
+qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n
+nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz
+8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=
+-----END CERTIFICATE-----
+
+Go Daddy Class 2 CA
+===================
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY
+VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG
+A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g
+RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD
+ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv
+2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32
+qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j
+YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY
+vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O
+BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o
+atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu
+MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim
+PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt
+I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI
+Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b
+vZ8=
+-----END CERTIFICATE-----
+
+Starfield Class 2 CA
+====================
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc
+U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo
+MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG
+A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG
+SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY
+bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ
+JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm
+epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN
+F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF
+MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f
+hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo
+bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g
+QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs
+afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM
+PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD
+KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3
+QBFGmh95DmK/D5fs4C8fF5Q=
+-----END CERTIFICATE-----
+
+StartCom Certification Authority
+================================
+-----BEGIN CERTIFICATE-----
+MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
+U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu
+ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0
+NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk
+LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg
+U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
+ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y
+o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/
+Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d
+eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt
+2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z
+6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ
+osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/
+untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc
+UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT
+37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
+FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0
+Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj
+YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH
+AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw
+Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg
+U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5
+LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh
+cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT
+dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC
+AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh
+3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm
+vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk
+fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3
+fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ
+EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
+yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl
+1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/
+lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro
+g14=
+-----END CERTIFICATE-----
+
+Taiwan GRCA
+===========
+-----BEGIN CERTIFICATE-----
+MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG
+EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X
+DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv
+dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN
+w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5
+BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O
+1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO
+htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov
+J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7
+Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t
+B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB
+O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8
+lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV
+HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2
+09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ
+TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj
+Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2
+Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU
+D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz
+DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk
+Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk
+7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ
+CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy
++fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS
+-----END CERTIFICATE-----
+
+Swisscom Root CA 1
+==================
+-----BEGIN CERTIFICATE-----
+MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG
+EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy
+dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4
+MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln
+aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC
+IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM
+MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF
+NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe
+AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC
+b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn
+7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN
+cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp
+WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5
+haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY
+MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw
+HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j
+BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9
+MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn
+jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ
+MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H
+VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl
+vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl
+OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3
+1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq
+nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy
+x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW
+NY6E0F/6MBr1mmz0DlP5OlvRHA==
+-----END CERTIFICATE-----
+
+DigiCert Assured ID Root CA
+===========================
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
+IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx
+MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
+ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO
+9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy
+UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW
+/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy
+oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf
+GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF
+66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq
+hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc
+EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn
+SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i
+8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
+-----END CERTIFICATE-----
+
+DigiCert Global Root CA
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
+HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw
+MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
+dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn
+TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5
+BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H
+4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y
+7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB
+o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm
+8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF
+BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr
+EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt
+tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886
+UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----
+
+DigiCert High Assurance EV Root CA
+==================================
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw
+KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw
+MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
+MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu
+Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t
+Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS
+OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3
+MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ
+NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe
+h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB
+Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY
+JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ
+V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp
+myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK
+mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
+-----END CERTIFICATE-----
+
+Certplus Class 2 Primary CA
+===========================
+-----BEGIN CERTIFICATE-----
+MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE
+BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN
+OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy
+dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR
+5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ
+Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO
+YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e
+e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME
+CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ
+YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t
+L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD
+P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R
+TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+
+7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW
+//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
+l7+ijrRU
+-----END CERTIFICATE-----
+
+DST Root CA X3
+==============
+-----BEGIN CERTIFICATE-----
+MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK
+ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X
+DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1
+cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT
+rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9
+UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy
+xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d
+utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T
+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ
+MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug
+dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE
+GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw
+RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS
+fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
+-----END CERTIFICATE-----
+
+DST ACES CA X6
+==============
+-----BEGIN CERTIFICATE-----
+MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG
+EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT
+MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha
+MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE
+CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI
+DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa
+pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow
+GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy
+MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu
+Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy
+dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU
+CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2
+5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t
+Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq
+nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs
+vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3
+oKfN5XozNmr6mis=
+-----END CERTIFICATE-----
+
+TURKTRUST Certificate Services Provider Root 1
+==============================================
+-----BEGIN CERTIFICATE-----
+MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP
+MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0
+acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx
+MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg
+U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB
+TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC
+aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX
+yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i
+Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ
+8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4
+W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME
+BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46
+sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE
+q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy
+B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY
+nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H
+-----END CERTIFICATE-----
+
+TURKTRUST Certificate Services Provider Root 2
+==============================================
+-----BEGIN CERTIFICATE-----
+MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP
+MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg
+QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN
+MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr
+dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G
+A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls
+acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe
+LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI
+x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g
+QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr
+5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB
+AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G
+A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt
+Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4
+Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+
+hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P
+9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5
+UrbnBEI=
+-----END CERTIFICATE-----
+
+SwissSign Gold CA - G2
+======================
+-----BEGIN CERTIFICATE-----
+MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw
+EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN
+MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp
+c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq
+t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C
+jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg
+vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF
+ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR
+AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend
+jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO
+peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR
+7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi
+GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64
+OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov
+L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm
+5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr
+44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf
+Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m
+Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp
+mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk
+vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf
+KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br
+NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj
+viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
+-----END CERTIFICATE-----
+
+SwissSign Silver CA - G2
+========================
+-----BEGIN CERTIFICATE-----
+MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT
+BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X
+DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3
+aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG
+9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644
+N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm
++/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH
+6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu
+MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h
+qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5
+FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs
+ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc
+celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X
+CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB
+tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0
+cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P
+4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F
+kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L
+3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx
+/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa
+DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP
+e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu
+WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ
+DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub
+DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
+-----END CERTIFICATE-----
+
+GeoTrust Primary Certification Authority
+========================================
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx
+CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ
+cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN
+b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9
+nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge
+RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt
+tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI
+hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K
+Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN
+NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa
+Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG
+1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
+-----END CERTIFICATE-----
+
+thawte Primary Root CA
+======================
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE
+BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
+aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3
+MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg
+SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv
+KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT
+FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs
+oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ
+1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc
+q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K
+aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p
+afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
+VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF
+AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE
+uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
+xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89
+jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH
+z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA==
+-----END CERTIFICATE-----
+
+VeriSign Class 3 Public Primary Certification Authority - G5
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
+BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
+ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
+IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB
+yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln
+biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh
+dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz
+j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD
+Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/
+Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r
+fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/
+BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv
+Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
+aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG
+SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+
+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE
+KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC
+Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE
+ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
+-----END CERTIFICATE-----
+
+SecureTrust CA
+==============
+-----BEGIN CERTIFICATE-----
+MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG
+EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy
+dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe
+BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX
+OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t
+DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH
+GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b
+01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH
+ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj
+aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
+KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu
+SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf
+mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ
+nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
+3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
+-----END CERTIFICATE-----
+
+Secure Global CA
+================
+-----BEGIN CERTIFICATE-----
+MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG
+EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH
+bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg
+MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg
+Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx
+YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ
+bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g
+8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV
+HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi
+0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn
+oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA
+MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+
+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn
+CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5
+3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
+f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
+-----END CERTIFICATE-----
+
+COMODO Certification Authority
+==============================
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE
+BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
+A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1
+dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb
+MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD
+T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH
++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww
+xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV
+4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA
+1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI
+rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k
+b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC
+AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP
+OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
+RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc
+IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN
++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==
+-----END CERTIFICATE-----
+
+Network Solutions Certificate Authority
+=======================================
+-----BEGIN CERTIFICATE-----
+MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG
+EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr
+IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx
+MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
+MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx
+jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT
+aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT
+crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc
+/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB
+AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv
+bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA
+A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q
+4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/
+GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
+wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD
+ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
+-----END CERTIFICATE-----
+
+WellsSecure Public Root Certificate Authority
+=============================================
+-----BEGIN CERTIFICATE-----
+MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM
+F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw
+NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN
+MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl
+bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD
+VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1
+iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13
+i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8
+bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB
+K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB
+AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu
+cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm
+lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB
+i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww
+GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg
+Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI
+K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0
+bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj
+qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es
+E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ
+tylv2G0xffX8oRAHh84vWdw+WNs=
+-----END CERTIFICATE-----
+
+COMODO ECC Certification Authority
+==================================
+-----BEGIN CERTIFICATE-----
+MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC
+R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
+ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix
+GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
+Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo
+b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X
+4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni
+wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG
+FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA
+U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
+-----END CERTIFICATE-----
+
+IGC/A
+=====
+-----BEGIN CERTIFICATE-----
+MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD
+VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE
+Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy
+MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI
+EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT
+STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2
+TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW
+So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy
+HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd
+frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ
+tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB
+egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC
+iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK
+q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q
+MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg
+Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI
+lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF
+0mBWWg==
+-----END CERTIFICATE-----
+
+Security Communication EV RootCA1
+=================================
+-----BEGIN CERTIFICATE-----
+MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
+U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh
+dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE
+BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl
+Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO
+/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX
+WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z
+ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4
+bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK
+9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
+SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm
+iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG
+Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW
+mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW
+T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490
+-----END CERTIFICATE-----
+
+OISTE WISeKey Global Root GA CA
+===============================
+-----BEGIN CERTIFICATE-----
+MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE
+BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG
+A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH
+bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD
+VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw
+IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5
+IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9
+Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg
+Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD
+d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ
+/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R
+LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ
+KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm
+MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4
++vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa
+hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY
+okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0=
+-----END CERTIFICATE-----
+
+Microsec e-Szigno Root CA
+=========================
+-----BEGIN CERTIFICATE-----
+MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE
+BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL
+EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0
+MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz
+dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT
+GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG
+d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N
+oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc
+QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ
+PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb
+MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG
+IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD
+VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3
+LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A
+dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn
+AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA
+4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg
+AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA
+egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6
+Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO
+PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv
+c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h
+cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw
+IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT
+WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV
+MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER
+MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp
+Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal
+HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT
+nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE
+aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a
+86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK
+yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB
+S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU=
+-----END CERTIFICATE-----
+
+Certigna
+========
+-----BEGIN CERTIFICATE-----
+MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw
+EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3
+MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI
+Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q
+XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH
+GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p
+ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg
+DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf
+Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ
+tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ
+BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J
+SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA
+hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+
+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu
+PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY
+1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
+WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
+-----END CERTIFICATE-----
+
+AC Ra\xC3\xADz Certic\xC3\xA1mara S.A.
+======================================
+-----BEGIN CERTIFICATE-----
+MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNVBAYT
+AkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERpZ2l0YWwg
+LSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4w
+HhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+
+U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJh
+IFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeGqentLhM0R7LQcNzJPNCN
+yu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU
+2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU3
+4ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP
+2yYe68yQ54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm
+8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhf
+HjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCa
+Mh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK
+5lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1b
+czwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0g
+ADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEF
+BQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2Ug
+cHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEf
+AygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuX
+EpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v
+/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3
+MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR4
+3NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wk
+eZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f
+/RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5h
+RqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecU
+Iw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ==
+-----END CERTIFICATE-----
+
+TC TrustCenter Class 2 CA II
+============================
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC
+REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy
+IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw
+MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1
+c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE
+AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw
+IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2
+xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ
+Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u
+SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB
+7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90
+Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU
+cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i
+SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
+TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G
+dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ
+KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj
+TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP
+JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk
+vQ==
+-----END CERTIFICATE-----
+
+TC TrustCenter Class 3 CA II
+============================
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC
+REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy
+IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw
+MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1
+c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE
+AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W
+yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo
+6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ
+uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk
+2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB
+7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90
+Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU
+cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i
+SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
+TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE
+O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8
+yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9
+IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal
+092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc
+5A==
+-----END CERTIFICATE-----
+
+TC TrustCenter Universal CA I
+=============================
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC
+REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy
+IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN
+MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg
+VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw
+JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC
+qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv
+xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw
+ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O
+gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j
+BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG
+1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy
+vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3
+ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT
+ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a
+7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY
+-----END CERTIFICATE-----
+
+Deutsche Telekom Root CA 2
+==========================
+-----BEGIN CERTIFICATE-----
+MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT
+RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG
+A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5
+MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G
+A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS
+b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5
+bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI
+KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY
+AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK
+Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV
+jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV
+HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr
+E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy
+zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8
+rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G
+dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
+Cm26OWMohpLzGITY+9HPBVZkVw==
+-----END CERTIFICATE-----
+
+ComSign Secured CA
+==================
+-----BEGIN CERTIFICATE-----
+MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE
+AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w
+NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD
+QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs
+49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH
+7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB
+kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1
+9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw
+AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t
+U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA
+j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC
+AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a
+BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp
+FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP
+51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz
+OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw==
+-----END CERTIFICATE-----
+
+Cybertrust Global Root
+======================
+-----BEGIN CERTIFICATE-----
+MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li
+ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4
+MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD
+ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
++Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW
+0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL
+AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin
+89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT
+8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2
+MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G
+A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO
+lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi
+5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2
+hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T
+X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW
+WL1WMRJOEcgh4LMRkWXbtKaIOM5V
+-----END CERTIFICATE-----
+
+ePKI Root Certification Authority
+=================================
+-----BEGIN CERTIFICATE-----
+MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG
+EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg
+Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx
+MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq
+MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs
+IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi
+lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv
+qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX
+12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O
+WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+
+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao
+lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/
+vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi
+Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi
+MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
+ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0
+1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq
+KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV
+xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP
+NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r
+GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE
+xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx
+gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy
+sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD
+BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw=
+-----END CERTIFICATE-----
+
+T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3
+=============================================================================================================================
+-----BEGIN CERTIFICATE-----
+MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH
+DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q
+aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry
+b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV
+BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg
+S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4
+MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl
+IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF
+n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl
+IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft
+dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl
+cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO
+Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1
+xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR
+6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL
+hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd
+BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4
+N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT
+y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh
+LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M
+dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI=
+-----END CERTIFICATE-----
+
+Buypass Class 2 CA 1
+====================
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2
+MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh
+c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M
+cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83
+0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4
+0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R
+uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P
+AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV
+1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt
+7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2
+fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w
+wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho
+-----END CERTIFICATE-----
+
+Buypass Class 3 CA 1
+====================
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1
+MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh
+c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx
+ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0
+n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia
+AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c
+1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P
+AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7
+pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA
+EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5
+htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj
+el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915
+-----END CERTIFICATE-----
+
+EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1
+==========================================================================
+-----BEGIN CERTIFICATE-----
+MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg
+QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe
+Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p
+ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt
+IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by
+X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b
+gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr
+eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ
+TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy
+Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn
+uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI
+qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm
+ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0
+Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
+/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW
+Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t
+FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm
+zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k
+XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT
+bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU
+RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK
+1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt
+2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ
+Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9
+AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT
+-----END CERTIFICATE-----
+
+certSIGN ROOT CA
+================
+-----BEGIN CERTIFICATE-----
+MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD
+VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa
+Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE
+CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I
+JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH
+rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2
+ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD
+0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943
+AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
+Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB
+AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8
+SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0
+x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt
+vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz
+TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD
+-----END CERTIFICATE-----
+
+CNNIC ROOT
+==========
+-----BEGIN CERTIFICATE-----
+MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE
+ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw
+OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD
+o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz
+VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT
+VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or
+czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK
+y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC
+wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S
+lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5
+Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM
+O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8
+BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2
+G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m
+mxE=
+-----END CERTIFICATE-----
+
+ApplicationCA - Japanese Government
+===================================
+-----BEGIN CERTIFICATE-----
+MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT
+SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw
+MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl
+cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4
+fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN
+wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE
+jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu
+nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU
+WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV
+BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD
+vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs
+o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g
+/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD
+io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW
+dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL
+rosot4LKGAfmt1t06SAZf7IbiVQ=
+-----END CERTIFICATE-----
+
+GeoTrust Primary Certification Authority - G3
+=============================================
+-----BEGIN CERTIFICATE-----
+MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE
+BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0
+IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy
+eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz
+NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo
+YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT
+LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j
+K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE
+c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C
+IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu
+dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr
+2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9
+cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE
+Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
+AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s
+t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt
+-----END CERTIFICATE-----
+
+thawte Primary Root CA - G2
+===========================
+-----BEGIN CERTIFICATE-----
+MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC
+VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu
+IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg
+Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV
+MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG
+b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt
+IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS
+LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5
+8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU
+mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN
+G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K
+rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
+-----END CERTIFICATE-----
+
+thawte Primary Root CA - G3
+===========================
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE
+BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2
+aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv
+cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w
+ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
+d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD
+VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG
+A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At
+P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC
++BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY
+7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW
+vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ
+KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK
+A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
+t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC
+8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm
+er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A=
+-----END CERTIFICATE-----
+
+GeoTrust Primary Certification Authority - G2
+=============================================
+-----BEGIN CERTIFICATE-----
+MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC
+VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu
+Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1
+OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
+MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl
+b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG
+BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc
+KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD
+VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+
+EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m
+ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2
+npaqBA+K
+-----END CERTIFICATE-----
+
+VeriSign Universal Root Certification Authority
+===============================================
+-----BEGIN CERTIFICATE-----
+MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE
+BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO
+ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk
+IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u
+IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
+cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj
+1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP
+MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72
+9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I
+AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR
+tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G
+CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O
+a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
+DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3
+Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx
+Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx
+P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P
+wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4
+mJO37M2CYfE45k+XmCpajQ==
+-----END CERTIFICATE-----
+
+VeriSign Class 3 Public Primary Certification Authority - G4
+============================================================
+-----BEGIN CERTIFICATE-----
+MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC
+VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3
+b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz
+ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU
+cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo
+b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5
+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8
+Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz
+rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB
+/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw
+HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u
+Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD
+A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx
+AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
+-----END CERTIFICATE-----
+
+NetLock Arany (Class Gold) Főtanúsítvány
+============================================
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G
+A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610
+dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB
+cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx
+MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO
+ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6
+c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu
+0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw
+/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk
+H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw
+fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1
+neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB
+BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW
+qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta
+YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC
+bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna
+NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu
+dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
+-----END CERTIFICATE-----
+
+Staat der Nederlanden Root CA - G2
+==================================
+-----BEGIN CERTIFICATE-----
+MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE
+CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
+Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC
+TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l
+ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ
+5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn
+vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj
+CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil
+e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR
+OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI
+CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65
+48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi
+trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737
+qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB
+AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC
+ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV
+HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA
+A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz
++51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj
+f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN
+kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk
+CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF
+URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb
+CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h
+oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV
+IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm
+66+KAQ==
+-----END CERTIFICATE-----
+
+CA Disig
+========
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK
+QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw
+MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz
+bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm
+GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD
+Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo
+hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt
+ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w
+gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P
+AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz
+aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff
+ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa
+BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t
+WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3
+mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/
+CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K
+ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA
+4Z7CRneC9VkGjCFMhwnN5ag=
+-----END CERTIFICATE-----
+
+Juur-SK
+=======
+-----BEGIN CERTIFICATE-----
+MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA
+c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw
+DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG
+SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy
+aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf
+TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC
++Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw
+UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa
+Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF
+MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD
+HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh
+AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA
+cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr
+AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw
+cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE
+FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G
+A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo
+ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL
+abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678
+IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh
+Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2
+yyqcjg==
+-----END CERTIFICATE-----
+
+Hongkong Post Root CA 1
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT
+DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx
+NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n
+IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1
+ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr
+auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh
+qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY
+V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV
+HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i
+h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio
+l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei
+IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps
+T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT
+c4afU9hDDl3WY4JxHYB0yvbiAmvZWg==
+-----END CERTIFICATE-----
+
+SecureSign RootCA11
+===================
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi
+SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS
+b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw
+KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1
+cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL
+TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO
+wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq
+g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP
+O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA
+bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX
+t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh
+OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r
+bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ
+Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01
+y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061
+lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I=
+-----END CERTIFICATE-----
+
+ACEDICOM Root
+=============
+-----BEGIN CERTIFICATE-----
+MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD
+T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4
+MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG
+A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk
+WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD
+YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew
+MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb
+m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk
+HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT
+xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2
+3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9
+2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq
+TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz
+4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU
+9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv
+bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg
+aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP
+eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk
+zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1
+ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI
+KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq
+nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE
+I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp
+MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o
+tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA==
+-----END CERTIFICATE-----
+
+Verisign Class 3 Public Primary Certification Authority
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx
+FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5
+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow
+XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz
+IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
+A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94
+f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol
+hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABByUqkFFBky
+CEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWX
+bj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/
+D/xwzoiQ
+-----END CERTIFICATE-----
+
+Microsec e-Szigno Root CA 2009
+==============================
+-----BEGIN CERTIFICATE-----
+MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER
+MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv
+c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o
+dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE
+BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt
+U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA
+fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG
+0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA
+pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm
+1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC
+AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf
+QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE
+FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o
+lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX
+I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775
+tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02
+yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi
+LXpUq3DDfSJlgnCW
+-----END CERTIFICATE-----
+
+E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi
+===================================================
+-----BEGIN CERTIFICATE-----
+MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG
+EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz
+ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3
+MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0
+cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u
+aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY
+8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y
+jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI
+JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk
+9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD
+AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG
+SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d
+F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq
+D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4
+Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq
+fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX
+-----END CERTIFICATE-----
+
+GlobalSign Root CA - R3
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv
+YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
+bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
+aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
+bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt
+iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ
+0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3
+rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl
+OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2
+xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7
+lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8
+EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E
+bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18
+YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r
+kpeDMdmztcpHWD9f
+-----END CERTIFICATE-----
+
+Autoridad de Certificacion Firmaprofesional CIF A62634068
+=========================================================
+-----BEGIN CERTIFICATE-----
+MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA
+BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
+MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw
+QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB
+NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD
+Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P
+B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY
+7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH
+ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI
+plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX
+MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX
+LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK
+bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU
+vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud
+EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH
+DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp
+cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA
+bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx
+ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx
+51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk
+R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP
+T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f
+Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl
+osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR
+crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR
+saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD
+KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi
+6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
+-----END CERTIFICATE-----
+
+Izenpe.com
+==========
+-----BEGIN CERTIFICATE-----
+MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG
+EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz
+MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu
+QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ
+03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK
+ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU
++zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC
+PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT
+OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK
+F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK
+0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+
+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB
+leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID
+AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+
+SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG
+NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
+MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
+BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l
+Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga
+kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q
+hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs
+g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5
+aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5
+nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC
+ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo
+Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z
+WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
+-----END CERTIFICATE-----
+
+Chambers of Commerce Root - 2008
+================================
+-----BEGIN CERTIFICATE-----
+MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD
+MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
+bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
+QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy
+Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl
+ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF
+EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl
+cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA
+XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj
+h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/
+ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk
+NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g
+D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331
+lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ
+0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj
+ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2
+EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI
+G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ
+BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh
+bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh
+bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC
+CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH
+AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1
+wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH
+3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU
+RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6
+M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1
+YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF
+9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK
+zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG
+nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg
+OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ
+-----END CERTIFICATE-----
+
+Global Chambersign Root - 2008
+==============================
+-----BEGIN CERTIFICATE-----
+MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD
+MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
+bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
+QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx
+NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg
+Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ
+QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD
+aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf
+VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf
+XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0
+ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB
+/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA
+TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M
+H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe
+Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF
+HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh
+wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB
+AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT
+BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE
+BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm
+aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm
+aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp
+1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0
+dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG
+/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6
+ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s
+dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg
+9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH
+foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du
+qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr
+P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq
+c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z
+09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B
+-----END CERTIFICATE-----
+
+Go Daddy Root Certificate Authority - G2
+========================================
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu
+MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
+MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
+b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G
+A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq
+9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD
++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd
+fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl
+NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9
+BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac
+vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r
+5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV
+N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
+LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1
+-----END CERTIFICATE-----
+
+Starfield Root Certificate Authority - G2
+=========================================
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
+b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0
+eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw
+DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg
+VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB
+dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv
+W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs
+bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk
+N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf
+ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU
+JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol
+TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx
+4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw
+F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
+pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ
+c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
+-----END CERTIFICATE-----
+
+Starfield Services Root Certificate Authority - G2
+==================================================
+-----BEGIN CERTIFICATE-----
+MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT
+B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s
+b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl
+IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV
+BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT
+dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg
+Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2
+h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa
+hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP
+LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB
+rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
+AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG
+SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP
+E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy
+xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
+iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza
+YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6
+-----END CERTIFICATE-----
+
+AffirmTrust Commercial
+======================
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS
+BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw
+MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
+bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb
+DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV
+C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6
+BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww
+MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV
+HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG
+hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi
+qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv
+0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh
+sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
+-----END CERTIFICATE-----
+
+AffirmTrust Networking
+======================
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS
+BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw
+MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly
+bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE
+Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI
+dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24
+/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb
+h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV
+HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu
+UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6
+12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23
+WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9
+/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
+-----END CERTIFICATE-----
+
+AffirmTrust Premium
+===================
+-----BEGIN CERTIFICATE-----
+MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS
+BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy
+OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy
+dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn
+BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV
+5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs
++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd
+GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R
+p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI
+S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04
+6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5
+/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo
++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv
+MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
+Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC
+6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S
+L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK
++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV
+BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg
+IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60
+g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb
+zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw==
+-----END CERTIFICATE-----
+
+AffirmTrust Premium ECC
+=======================
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV
+BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx
+MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U
+cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ
+N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW
+BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK
+BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X
+57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM
+eQ==
+-----END CERTIFICATE-----
+
+Certum Trusted Network CA
+=========================
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK
+ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy
+MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU
+ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC
+l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J
+J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4
+fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0
+cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB
+Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw
+DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj
+jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1
+mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj
+Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
+03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
+-----END CERTIFICATE-----
+
+Certinomis - Autorité Racine
+=============================
+-----BEGIN CERTIFICATE-----
+MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK
+Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg
+LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG
+A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw
+JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa
+wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly
+Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw
+2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N
+jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q
+c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC
+lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb
+xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g
+530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna
+4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
+A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ
+KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x
+WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva
+R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40
+nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B
+CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv
+JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE
+qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b
+WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE
+wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/
+vgt2Fl43N+bYdJeimUV5
+-----END CERTIFICATE-----
+
+Root CA Generalitat Valenciana
+==============================
+-----BEGIN CERTIFICATE-----
+MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE
+ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290
+IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3
+WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE
+CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2
+F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B
+ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ
+D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte
+JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB
+AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n
+dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB
+ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl
+AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA
+YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy
+AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA
+aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt
+AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA
+YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu
+AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA
+OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0
+dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV
+BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G
+A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S
+b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh
+TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz
+Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63
+NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH
+iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt
++GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM=
+-----END CERTIFICATE-----
+
+A-Trust-nQual-03
+================
+-----BEGIN CERTIFICATE-----
+MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE
+Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy
+a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R
+dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw
+RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0
+ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1
+c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA
+zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n
+yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE
+SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4
+iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V
+cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV
+eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40
+ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr
+sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd
+JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS
+mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6
+ahq97BvIxYSazQ==
+-----END CERTIFICATE-----
+
+TWCA Root Certification Authority
+=================================
+-----BEGIN CERTIFICATE-----
+MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ
+VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG
+EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB
+IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx
+QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC
+oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP
+4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r
+y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB
+BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG
+9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC
+mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW
+QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY
+T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny
+Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
+-----END CERTIFICATE-----
+
+Security Communication RootCA2
+==============================
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
+U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh
+dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC
+SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy
+aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++
++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R
+3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV
+spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K
+EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8
+QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB
+CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj
+u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk
+3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q
+tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29
+mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
+-----END CERTIFICATE-----
+
+EC-ACC
+======
+-----BEGIN CERTIFICATE-----
+MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE
+BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w
+ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD
+VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE
+CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT
+BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7
+MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt
+SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl
+Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh
+cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK
+w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT
+ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4
+HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a
+E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw
+0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD
+VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0
+Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l
+dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ
+lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa
+Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe
+l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2
+E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D
+5EI=
+-----END CERTIFICATE-----
+
+Hellenic Academic and Research Institutions RootCA 2011
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT
+O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y
+aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
+IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT
+AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
+IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo
+IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI
+1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa
+71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u
+8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH
+3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/
+MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8
+MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu
+b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt
+XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8
+TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD
+/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N
+7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4
+-----END CERTIFICATE-----
+
+Actalis Authentication Root CA
+==============================
+-----BEGIN CERTIFICATE-----
+MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM
+BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE
+AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky
+MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz
+IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
+IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ
+wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa
+by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6
+zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f
+YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2
+oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l
+EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7
+hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8
+EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5
+jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY
+iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
+ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI
+WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0
+JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx
+K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+
+Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC
+4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo
+2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz
+lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem
+OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9
+vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
+-----END CERTIFICATE-----
+
+Trustis FPS Root CA
+===================
+-----BEGIN CERTIFICATE-----
+MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG
+EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290
+IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV
+BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ
+RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk
+H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa
+cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt
+o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA
+AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd
+BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c
+GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC
+yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P
+8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV
+l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl
+iB6XzCGcKQENZetX2fNXlrtIzYE=
+-----END CERTIFICATE-----
+
+StartCom Certification Authority
+================================
+-----BEGIN CERTIFICATE-----
+MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
+U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu
+ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0
+NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk
+LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg
+U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
+ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y
+o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/
+Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d
+eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt
+2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z
+6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ
+osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/
+untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc
+UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT
+37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ
+Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0
+dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu
+c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv
+bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0
+aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0
+aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t
+L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG
+cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5
+fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm
+N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN
+Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T
+tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX
+e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA
+2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs
+HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE
+JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib
+D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8=
+-----END CERTIFICATE-----
+
+StartCom Certification Authority G2
+===================================
+-----BEGIN CERTIFICATE-----
+MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN
+U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE
+ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O
+o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG
+4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi
+Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul
+Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs
+O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H
+vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L
+nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS
+FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa
+z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ
+KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K
+2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk
+J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+
+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG
+/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc
+nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld
+blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc
+l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm
+7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm
+obp573PYtlNXLfbQ4ddI
+-----END CERTIFICATE-----
+
+Buypass Class 2 Root CA
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X
+DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
+eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1
+g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn
+9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b
+/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU
+CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff
+awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI
+zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn
+Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX
+Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs
+M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
+AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s
+A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI
+osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S
+aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd
+DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD
+LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0
+oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC
+wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS
+CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN
+rJgWVqA=
+-----END CERTIFICATE-----
+
+Buypass Class 3 Root CA
+=======================
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
+QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X
+DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1
+eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH
+sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR
+5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh
+7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ
+ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH
+2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV
+/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ
+RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA
+Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq
+j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF
+AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV
+cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G
+uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG
+Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8
+ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2
+KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz
+6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug
+UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe
+eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi
+Cp/HuZc=
+-----END CERTIFICATE-----
+
+T-TeleSec GlobalRoot Class 3
+============================
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
+IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
+cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx
+MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
+dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
+ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK
+9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU
+NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF
+iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W
+0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr
+AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb
+fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT
+ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h
+P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
+e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==
+-----END CERTIFICATE-----
+
+EE Certification Centre Root CA
+===============================
+-----BEGIN CERTIFICATE-----
+MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG
+EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy
+dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw
+MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB
+UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy
+ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM
+TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2
+rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw
+93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN
+P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T
+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ
+MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF
+BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj
+xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM
+lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u
+uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU
+3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM
+dcGWxZ0=
+-----END CERTIFICATE-----
+
+TURKTRUST Certificate Services Provider Root 2007
+=================================================
+-----BEGIN CERTIFICATE-----
+MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP
+MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg
+QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X
+DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl
+a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN
+BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp
+bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N
+YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv
+KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya
+KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT
+rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC
+AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s
+Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I
+aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO
+Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb
+BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK
+poRq0Tl9
+-----END CERTIFICATE-----
+
+D-TRUST Root Class 3 CA 2 2009
+==============================
+-----BEGIN CERTIFICATE-----
+MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK
+DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe
+Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE
+LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD
+ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA
+BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv
+KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z
+p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC
+AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ
+4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y
+eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw
+MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G
+PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw
+OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm
+2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
+o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV
+dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph
+X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=
+-----END CERTIFICATE-----
+
+D-TRUST Root Class 3 CA 2 EV 2009
+=================================
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
+DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
+OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
+DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
+OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS
+egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh
+zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T
+7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60
+sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35
+11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv
+cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v
+ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El
+MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp
+b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh
+c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+
+PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05
+nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX
+ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA
+NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv
+w9y4AyHqnxbxLFS1
+-----END CERTIFICATE-----
+
+PSCProcert
+==========
+-----BEGIN CERTIFICATE-----
+MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk
+ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ
+MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz
+dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl
+cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw
+IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw
+MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w
+DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD
+ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp
+Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC
+wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA
+3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh
+RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO
+EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2
+0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH
+0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU
+td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw
+Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp
+r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/
+AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz
+Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId
+xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp
+ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH
+EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h
+Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k
+ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG
+9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG
+MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG
+LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52
+ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy
+YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v
+Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o
+dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq
+T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN
+g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q
+uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1
+n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn
+FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo
+5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq
+3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5
+poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y
+eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km
+-----END CERTIFICATE-----
+
+China Internet Network Information Center EV Certificates Root
+==============================================================
+-----BEGIN CERTIFICATE-----
+MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV
+BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D
+aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg
+Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG
+A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM
+PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl
+cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y
+jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV
+98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H
+klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23
+KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC
+7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD
+glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5
+0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM
+7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws
+ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0
+5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8=
+-----END CERTIFICATE-----
+
+Swisscom Root CA 2
+==================
+-----BEGIN CERTIFICATE-----
+MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG
+EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy
+dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2
+MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln
+aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC
+IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM
+LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo
+ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ
+wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH
+Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a
+SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS
+NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab
+mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY
+Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3
+qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw
+HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O
+BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu
+MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO
+v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ
+82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz
+o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs
+a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx
+OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW
+mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o
++sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC
+rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX
+5OfNeOI5wSsSnqaeG8XmDtkx2Q==
+-----END CERTIFICATE-----
+
+Swisscom Root EV CA 2
+=====================
+-----BEGIN CERTIFICATE-----
+MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE
+BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl
+cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN
+MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT
+HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg
+Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz
+o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy
+Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti
+GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li
+qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH
+Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG
+alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa
+m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox
+bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi
+xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/
+BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED
+MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB
+bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL
+j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU
+wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7
+XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH
+59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/
+23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq
+J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA
+HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi
+uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW
+l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc=
+-----END CERTIFICATE-----
+
+CA Disig Root R1
+================
+-----BEGIN CERTIFICATE-----
+MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw
+EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
+ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx
+EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
+c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy
+3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8
+u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2
+m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk
+CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa
+YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6
+vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL
+LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX
+ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is
+XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ
+04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR
+xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B
+LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM
+CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb
+VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85
+YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS
+ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix
+lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N
+UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ
+a7+h89n07eLw4+1knj0vllJPgFOL
+-----END CERTIFICATE-----
+
+CA Disig Root R2
+================
+-----BEGIN CERTIFICATE-----
+MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw
+EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
+ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx
+EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
+c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC
+w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia
+xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7
+A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S
+GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV
+g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa
+5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE
+koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A
+Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i
+Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u
+Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM
+tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV
+sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je
+dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8
+1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx
+mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01
+utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0
+sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg
+UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV
+7+ZtsH8tZ/3zbBt1RqPlShfppNcL
+-----END CERTIFICATE-----
+
+ACCVRAIZ1
+=========
+-----BEGIN CERTIFICATE-----
+MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB
+SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1
+MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH
+UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM
+jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0
+RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD
+aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ
+0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG
+WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7
+8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR
+5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J
+9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK
+Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw
+Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu
+Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2
+VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM
+Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA
+QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh
+AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA
+YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj
+AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA
+IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk
+aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0
+dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2
+MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI
+hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E
+R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN
+YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49
+nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ
+TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3
+sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h
+I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg
+Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd
+3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p
+EfbRD0tVNEYqi4Y7
+-----END CERTIFICATE-----
+
+TWCA Global Root CA
+===================
+-----BEGIN CERTIFICATE-----
+MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT
+CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD
+QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK
+EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg
+Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C
+nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV
+r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR
+Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV
+tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W
+KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99
+sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p
+yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn
+kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI
+zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC
+AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g
+cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn
+LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M
+8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg
+/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg
+lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP
+A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m
+i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8
+EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3
+zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=
+-----END CERTIFICATE-----
+
+TeliaSonera Root CA v1
+======================
+-----BEGIN CERTIFICATE-----
+MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE
+CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4
+MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW
+VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+
+6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA
+3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k
+B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn
+Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH
+oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3
+F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ
+oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7
+gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc
+TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB
+AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW
+DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm
+zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx
+0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW
+pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV
+G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc
+c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT
+JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2
+qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6
+Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems
+WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
+-----END CERTIFICATE-----
+
+E-Tugra Certification Authority
+===============================
+-----BEGIN CERTIFICATE-----
+MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w
+DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls
+ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN
+ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw
+NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx
+QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl
+cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD
+DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd
+hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K
+CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g
+ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ
+BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0
+E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz
+rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq
+jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn
+rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5
+dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB
+/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG
+MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK
+kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO
+XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807
+VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo
+a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc
+dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV
+KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT
+Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0
+8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G
+C7TbO6Orb1wdtn7os4I07QZcJA==
+-----END CERTIFICATE-----
+
+T-TeleSec GlobalRoot Class 2
+============================
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM
+IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU
+cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx
+MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz
+dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD
+ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ
+SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F
+vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970
+2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV
+WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy
+YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4
+r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf
+vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR
+3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN
+9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==
+-----END CERTIFICATE-----
+
+Atos TrustedRoot 2011
+=====================
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU
+cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4
+MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG
+A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV
+hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr
+54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+
+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320
+HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR
+z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R
+l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ
+bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
+CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h
+k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh
+TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9
+61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G
+3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
+-----END CERTIFICATE-----
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/functions.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/functions.php
new file mode 100644
index 0000000..9dcce36
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/GuzzleHttp/functions.php
@@ -0,0 +1,325 @@
+send($client->createRequest($method, $url, $options));
+}
+
+/**
+ * Send a GET request
+ *
+ * @param string $url URL of the request
+ * @param array $options Array of request options
+ *
+ * @return ResponseInterface
+ */
+function get($url, array $options = [])
+{
+ return request('GET', $url, $options);
+}
+
+/**
+ * Send a HEAD request
+ *
+ * @param string $url URL of the request
+ * @param array $options Array of request options
+ *
+ * @return ResponseInterface
+ */
+function head($url, array $options = [])
+{
+ return request('HEAD', $url, $options);
+}
+
+/**
+ * Send a DELETE request
+ *
+ * @param string $url URL of the request
+ * @param array $options Array of request options
+ *
+ * @return ResponseInterface
+ */
+function delete($url, array $options = [])
+{
+ return request('DELETE', $url, $options);
+}
+
+/**
+ * Send a POST request
+ *
+ * @param string $url URL of the request
+ * @param array $options Array of request options
+ *
+ * @return ResponseInterface
+ */
+function post($url, array $options = [])
+{
+ return request('POST', $url, $options);
+}
+
+/**
+ * Send a PUT request
+ *
+ * @param string $url URL of the request
+ * @param array $options Array of request options
+ *
+ * @return ResponseInterface
+ */
+function put($url, array $options = [])
+{
+ return request('PUT', $url, $options);
+}
+
+/**
+ * Send a PATCH request
+ *
+ * @param string $url URL of the request
+ * @param array $options Array of request options
+ *
+ * @return ResponseInterface
+ */
+function patch($url, array $options = [])
+{
+ return request('PATCH', $url, $options);
+}
+
+/**
+ * Send an OPTIONS request
+ *
+ * @param string $url URL of the request
+ * @param array $options Array of request options
+ *
+ * @return ResponseInterface
+ */
+function options($url, array $options = [])
+{
+ return request('OPTIONS', $url, $options);
+}
+
+/**
+ * Convenience method for sending multiple requests in parallel and retrieving
+ * a hash map of requests to response objects or RequestException objects.
+ *
+ * Note: This method keeps every request and response in memory, and as such is
+ * NOT recommended when sending a large number or an indeterminable number of
+ * requests in parallel.
+ *
+ * @param ClientInterface $client Client used to send the requests
+ * @param array|\Iterator $requests Requests to send in parallel
+ * @param array $options Passes through the options available in
+ * {@see GuzzleHttp\ClientInterface::sendAll()}
+ * @return \SplObjectStorage Requests are the key and each value is a
+ * {@see GuzzleHttp\Message\ResponseInterface} if the request succeeded or
+ * a {@see GuzzleHttp\Exception\RequestException} if it failed.
+ * @throws \InvalidArgumentException if the event format is incorrect.
+ */
+function batch(ClientInterface $client, $requests, array $options = [])
+{
+ $hash = new \SplObjectStorage();
+ foreach ($requests as $request) {
+ $hash->attach($request);
+ }
+
+ // Merge the necessary complete and error events to the event listeners so
+ // that as each request succeeds or fails, it is added to the result hash.
+ $options = RequestEvents::convertEventArray(
+ $options,
+ ['complete', 'error'],
+ [
+ 'priority' => RequestEvents::EARLY,
+ 'once' => true,
+ 'fn' => function ($e) use ($hash) { $hash[$e->getRequest()] = $e; }
+ ]
+ );
+
+ // Send the requests in parallel and aggregate the results.
+ $client->sendAll($requests, $options);
+
+ // Update the received value for any of the intercepted requests.
+ foreach ($hash as $request) {
+ if ($hash[$request] instanceof CompleteEvent) {
+ $hash[$request] = $hash[$request]->getResponse();
+ } elseif ($hash[$request] instanceof ErrorEvent) {
+ $hash[$request] = $hash[$request]->getException();
+ }
+ }
+
+ return $hash;
+}
+
+/**
+ * Gets a value from an array using a path syntax to retrieve nested data.
+ *
+ * This method does not allow for keys that contain "/". You must traverse
+ * the array manually or using something more advanced like JMESPath to
+ * work with keys that contain "/".
+ *
+ * // Get the bar key of a set of nested arrays.
+ * // This is equivalent to $collection['foo']['baz']['bar'] but won't
+ * // throw warnings for missing keys.
+ * GuzzleHttp\get_path($data, 'foo/baz/bar');
+ *
+ * @param array $data Data to retrieve values from
+ * @param string $path Path to traverse and retrieve a value from
+ *
+ * @return mixed|null
+ */
+function get_path($data, $path)
+{
+ $path = explode('/', $path);
+
+ while (null !== ($part = array_shift($path))) {
+ if (!is_array($data) || !isset($data[$part])) {
+ return null;
+ }
+ $data = $data[$part];
+ }
+
+ return $data;
+}
+
+/**
+ * Set a value in a nested array key. Keys will be created as needed to set the
+ * value.
+ *
+ * This function does not support keys that contain "/" or "[]" characters
+ * because these are special tokens used when traversing the data structure.
+ * A value may be prepended to an existing array by using "[]" as the final
+ * key of a path.
+ *
+ * GuzzleHttp\get_path($data, 'foo/baz'); // null
+ * GuzzleHttp\set_path($data, 'foo/baz/[]', 'a');
+ * GuzzleHttp\set_path($data, 'foo/baz/[]', 'b');
+ * GuzzleHttp\get_path($data, 'foo/baz');
+ * // Returns ['a', 'b']
+ *
+ * @param array $data Data to modify by reference
+ * @param string $path Path to set
+ * @param mixed $value Value to set at the key
+ * @throws \RuntimeException when trying to setPath using a nested path that
+ * travels through a scalar value.
+ */
+function set_path(&$data, $path, $value)
+{
+ $current =& $data;
+ $queue = explode('/', $path);
+ while (null !== ($key = array_shift($queue))) {
+ if (!is_array($current)) {
+ throw new \RuntimeException("Trying to setPath {$path}, but "
+ . "{$key} is set and is not an array");
+ } elseif (!$queue) {
+ if ($key == '[]') {
+ $current[] = $value;
+ } else {
+ $current[$key] = $value;
+ }
+ } elseif (isset($current[$key])) {
+ $current =& $current[$key];
+ } else {
+ $current[$key] = [];
+ $current =& $current[$key];
+ }
+ }
+}
+
+/**
+ * Expands a URI template
+ *
+ * @param string $template URI template
+ * @param array $variables Template variables
+ *
+ * @return string
+ */
+function uri_template($template, array $variables)
+{
+ if (function_exists('\\uri_template')) {
+ return \uri_template($template, $variables);
+ }
+
+ static $uriTemplate;
+ if (!$uriTemplate) {
+ $uriTemplate = new UriTemplate();
+ }
+
+ return $uriTemplate->expand($template, $variables);
+}
+
+/**
+ * Wrapper for JSON decode that implements error detection with helpful error
+ * messages.
+ *
+ * @param string $json JSON data to parse
+ * @param bool $assoc When true, returned objects will be converted into
+ * associative arrays.
+ * @param int $depth User specified recursion depth.
+ * @param int $options Bitmask of JSON decode options.
+ *
+ * @return mixed
+ * @throws \InvalidArgumentException if the JSON cannot be parsed.
+ * @link http://www.php.net/manual/en/function.json-decode.php
+ */
+function json_decode($json, $assoc = false, $depth = 512, $options = 0)
+{
+ static $jsonErrors = [
+ JSON_ERROR_DEPTH => 'JSON_ERROR_DEPTH - Maximum stack depth exceeded',
+ JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch',
+ JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found',
+ JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON',
+ JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded'
+ ];
+
+ $data = \json_decode($json, $assoc, $depth, $options);
+
+ if (JSON_ERROR_NONE !== json_last_error()) {
+ $last = json_last_error();
+ throw new \InvalidArgumentException(
+ 'Unable to parse JSON data: '
+ . (isset($jsonErrors[$last]) ? $jsonErrors[$last] : 'Unknown error')
+ );
+ }
+
+ return $data;
+}
+
+/**
+ * @internal
+ */
+function deprecation_proxy($object, $name, $arguments, $map)
+{
+ if (!isset($map[$name])) {
+ throw new \BadMethodCallException('Unknown method, ' . $name);
+ }
+
+ $message = sprintf('%s is deprecated and will be removed in a future '
+ . 'version. Update your code to use the equivalent %s method '
+ . 'instead to avoid breaking changes when this shim is removed.',
+ get_class($object) . '::' . $name . '()',
+ get_class($object) . '::' . $map[$name] . '()'
+ );
+
+ trigger_error($message, E_USER_DEPRECATED);
+
+ return call_user_func_array([$object, $map[$name]], $arguments);
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Draw/DrawerInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Draw/DrawerInterface.php
new file mode 100644
index 0000000..c48dff8
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Draw/DrawerInterface.php
@@ -0,0 +1,149 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Draw;
+
+use Imagine\Image\AbstractFont;
+use Imagine\Image\BoxInterface;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\PointInterface;
+use Imagine\Exception\RuntimeException;
+
+/**
+ * Interface for the drawer
+ */
+interface DrawerInterface
+{
+ /**
+ * Draws an arc on a starting at a given x, y coordinates under a given
+ * start and end angles
+ *
+ * @param PointInterface $center
+ * @param BoxInterface $size
+ * @param integer $start
+ * @param integer $end
+ * @param ColorInterface $color
+ * @param integer $thickness
+ *
+ * @throws RuntimeException
+ *
+ * @return DrawerInterface
+ */
+ public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1);
+
+ /**
+ * Same as arc, but also connects end points with a straight line
+ *
+ * @param PointInterface $center
+ * @param BoxInterface $size
+ * @param integer $start
+ * @param integer $end
+ * @param ColorInterface $color
+ * @param Boolean $fill
+ * @param integer $thickness
+ *
+ * @throws RuntimeException
+ *
+ * @return DrawerInterface
+ */
+ public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1);
+
+ /**
+ * Draws and ellipse with center at the given x, y coordinates, and given
+ * width and height
+ *
+ * @param PointInterface $center
+ * @param BoxInterface $size
+ * @param ColorInterface $color
+ * @param Boolean $fill
+ * @param integer $thickness
+ *
+ * @throws RuntimeException
+ *
+ * @return DrawerInterface
+ */
+ public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1);
+
+ /**
+ * Draws a line from start(x, y) to end(x, y) coordinates
+ *
+ * @param PointInterface $start
+ * @param PointInterface $end
+ * @param ColorInterface $outline
+ * @param integer $thickness
+ *
+ * @return DrawerInterface
+ */
+ public function line(PointInterface $start, PointInterface $end, ColorInterface $outline, $thickness = 1);
+
+ /**
+ * Same as arc, but connects end points and the center
+ *
+ * @param PointInterface $center
+ * @param BoxInterface $size
+ * @param integer $start
+ * @param integer $end
+ * @param ColorInterface $color
+ * @param Boolean $fill
+ * @param integer $thickness
+ *
+ * @throws RuntimeException
+ *
+ * @return DrawerInterface
+ */
+ public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1);
+
+ /**
+ * Places a one pixel point at specific coordinates and fills it with
+ * specified color
+ *
+ * @param PointInterface $position
+ * @param ColorInterface $color
+ *
+ * @throws RuntimeException
+ *
+ * @return DrawerInterface
+ */
+ public function dot(PointInterface $position, ColorInterface $color);
+
+ /**
+ * Draws a polygon using array of x, y coordinates. Must contain at least
+ * three coordinates
+ *
+ * @param array $coordinates
+ * @param ColorInterface $color
+ * @param Boolean $fill
+ * @param integer $thickness
+ *
+ * @throws RuntimeException
+ *
+ * @return DrawerInterface
+ */
+ public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1);
+
+ /**
+ * Annotates image with specified text at a given position starting on the
+ * top left of the final text box
+ *
+ * The rotation is done CW
+ *
+ * @param string $string
+ * @param AbstractFont $font
+ * @param PointInterface $position
+ * @param integer $angle
+ * @param integer $width
+ *
+ * @throws RuntimeException
+ *
+ * @return DrawerInterface
+ */
+ public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null);
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Effects/EffectsInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Effects/EffectsInterface.php
new file mode 100644
index 0000000..3593d75
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Effects/EffectsInterface.php
@@ -0,0 +1,80 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Effects;
+
+use Imagine\Exception\RuntimeException;
+use Imagine\Image\Palette\Color\ColorInterface;
+
+/**
+ * Interface for the effects
+ */
+interface EffectsInterface
+{
+ /**
+ * Apply gamma correction
+ *
+ * @param float $correction
+ * @return EffectsInterface
+ *
+ * @throws RuntimeException
+ */
+ public function gamma($correction);
+
+ /**
+ * Invert the colors of the image
+ *
+ * @return EffectsInterface
+ *
+ * @throws RuntimeException
+ */
+ public function negative();
+
+ /**
+ * Grayscale the image
+ *
+ * @return EffectsInterface
+ *
+ * @throws RuntimeException
+ */
+ public function grayscale();
+
+ /**
+ * Colorize the image
+ *
+ * @param ColorInterface $color
+ *
+ * @return EffectsInterface
+ *
+ * @throws RuntimeException
+ */
+ public function colorize(ColorInterface $color);
+
+ /**
+ * Sharpens the image
+ *
+ * @return EffectsInterface
+ *
+ * @throws RuntimeException
+ */
+ public function sharpen();
+
+ /**
+ * Blur the image
+ *
+ * @param float|int $sigma
+ *
+ * @return EffectsInterface
+ *
+ * @throws RuntimeException
+ */
+ public function blur($sigma);
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Exception/Exception.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Exception/Exception.php
new file mode 100644
index 0000000..39a67af
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Exception/Exception.php
@@ -0,0 +1,19 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Exception;
+
+/**
+ * Imagine-specific exception
+ */
+interface Exception
+{
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Exception/InvalidArgumentException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Exception/InvalidArgumentException.php
new file mode 100644
index 0000000..5ac1396
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Exception/InvalidArgumentException.php
@@ -0,0 +1,19 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Exception;
+
+/**
+ * Imagine-specific invalid argument exception
+ */
+class InvalidArgumentException extends \InvalidArgumentException implements Exception
+{
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Exception/NotSupportedException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Exception/NotSupportedException.php
new file mode 100644
index 0000000..fd68ce7
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Exception/NotSupportedException.php
@@ -0,0 +1,19 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Exception;
+
+/**
+ * Should be used when a driver does not support an operation.
+ */
+class NotSupportedException extends RuntimeException implements Exception
+{
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Exception/OutOfBoundsException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Exception/OutOfBoundsException.php
new file mode 100644
index 0000000..f51cc9b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Exception/OutOfBoundsException.php
@@ -0,0 +1,19 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Exception;
+
+/**
+ * Imagine-specific out of bounds exception
+ */
+class OutOfBoundsException extends \OutOfBoundsException implements Exception
+{
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Exception/RuntimeException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Exception/RuntimeException.php
new file mode 100644
index 0000000..205ad85
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Exception/RuntimeException.php
@@ -0,0 +1,19 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Exception;
+
+/**
+ * Imagine-specific runtime exception
+ */
+class RuntimeException extends \RuntimeException implements Exception
+{
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Advanced/Border.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Advanced/Border.php
new file mode 100644
index 0000000..47a3ceb
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Advanced/Border.php
@@ -0,0 +1,98 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Advanced;
+
+use Imagine\Filter\FilterInterface;
+use Imagine\Image\ImageInterface;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\Point;
+
+/**
+ * A border filter
+ */
+class Border implements FilterInterface
+{
+ /**
+ * @var ColorInterface
+ */
+ private $color;
+
+ /**
+ * @var integer
+ */
+ private $width;
+
+ /**
+ * @var integer
+ */
+ private $height;
+
+ /**
+ * Constructs Border filter with given color, width and height
+ *
+ * @param ColorInterface $color
+ * @param integer $width Width of the border on the left and right sides of the image
+ * @param integer $height Height of the border on the top and bottom sides of the image
+ */
+ public function __construct(ColorInterface $color, $width = 1, $height = 1)
+ {
+ $this->color = $color;
+ $this->width = $width;
+ $this->height = $height;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ $size = $image->getSize();
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+
+ $draw = $image->draw();
+
+ // Draw top and bottom lines
+ $draw
+ ->line(
+ new Point(0, 0),
+ new Point($width - 1, 0),
+ $this->color,
+ $this->height
+ )
+ ->line(
+ new Point($width - 1, $height - 1),
+ new Point(0, $height - 1),
+ $this->color,
+ $this->height
+ )
+ ;
+
+ // Draw sides
+ $draw
+ ->line(
+ new Point(0, 0),
+ new Point(0, $height - 1),
+ $this->color,
+ $this->width
+ )
+ ->line(
+ new Point($width - 1, 0),
+ new Point($width - 1, $height - 1),
+ $this->color,
+ $this->width
+ )
+ ;
+
+ return $image;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Advanced/Canvas.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Advanced/Canvas.php
new file mode 100644
index 0000000..685b8ae
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Advanced/Canvas.php
@@ -0,0 +1,74 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Advanced;
+
+use Imagine\Filter\FilterInterface;
+use Imagine\Image\ImageInterface;
+use Imagine\Image\BoxInterface;
+use Imagine\Image\Point;
+use Imagine\Image\PointInterface;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\ImagineInterface;
+
+/**
+ * A canvas filter
+ */
+class Canvas implements FilterInterface
+{
+ /**
+ * @var BoxInterface
+ */
+ private $size;
+
+ /**
+ * @var PointInterface
+ */
+ private $placement;
+
+ /**
+ * @var ColorInterface
+ */
+ private $background;
+
+ /**
+ * @var ImagineInterface
+ */
+ private $imagine;
+
+ /**
+ * Constructs Canvas filter with given width and height and the placement of the current image
+ * inside the new canvas
+ *
+ * @param ImagineInterface $imagine
+ * @param BoxInterface $size
+ * @param PointInterface $placement
+ * @param ColorInterface $background
+ */
+ public function __construct(ImagineInterface $imagine, BoxInterface $size, PointInterface $placement = null, ColorInterface $background = null)
+ {
+ $this->imagine = $imagine;
+ $this->size = $size;
+ $this->placement = $placement ?: new Point(0, 0);
+ $this->background = $background;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ $canvas = $this->imagine->create($this->size, $this->background);
+ $canvas->paste($image, $this->placement);
+
+ return $canvas;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Advanced/Grayscale.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Advanced/Grayscale.php
new file mode 100644
index 0000000..b3a08b4
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Advanced/Grayscale.php
@@ -0,0 +1,30 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Advanced;
+
+use Imagine\Filter\FilterInterface;
+use Imagine\Image\ImageInterface;
+use Imagine\Image\Point;
+
+/**
+ * The Grayscale filter calculates the gray-value based on RGB.
+ */
+class Grayscale extends OnPixelBased implements FilterInterface
+{
+ public function __construct()
+ {
+ parent::__construct(function (ImageInterface $image, Point $point) {
+ $color = $image->getColorAt($point);
+ $image->draw()->dot($point, $color->grayscale());
+ });
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Advanced/OnPixelBased.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Advanced/OnPixelBased.php
new file mode 100644
index 0000000..ef297ea
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Advanced/OnPixelBased.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Advanced;
+
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Filter\FilterInterface;
+use Imagine\Image\ImageInterface;
+use Imagine\Image\Point;
+
+/**
+ * The OnPixelBased takes a callable, and for each pixel, this callable is called with the
+ * image (\Imagine\Image\ImageInterface) and the current point (\Imagine\Image\Point)
+ */
+class OnPixelBased implements FilterInterface
+{
+ protected $callback;
+
+ public function __construct($callback)
+ {
+ if (!is_callable($callback)) {
+ throw new InvalidArgumentException('$callback has to be callable');
+ }
+
+ $this->callback = $callback;
+ }
+
+ /**
+ * Applies scheduled transformation to ImageInterface instance
+ * Returns processed ImageInterface instance
+ *
+ * @param ImageInterface $image
+ *
+ * @return ImageInterface
+ */
+ public function apply(ImageInterface $image)
+ {
+ $w = $image->getSize()->getWidth();
+ $h = $image->getSize()->getHeight();
+
+ for ($x = 0; $x < $w; $x++) {
+ for ($y = 0; $y < $h; $y++) {
+ call_user_func($this->callback, $image, new Point($x, $y));
+ }
+ }
+
+ return $image;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Advanced/RelativeResize.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Advanced/RelativeResize.php
new file mode 100644
index 0000000..954587a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Advanced/RelativeResize.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Advanced;
+
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Filter\FilterInterface;
+use Imagine\Image\ImageInterface;
+
+/**
+ * The RelativeResize filter allows images to be resized relative to their
+ * existing dimensions.
+ */
+class RelativeResize implements FilterInterface
+{
+ private $method;
+ private $parameter;
+
+ /**
+ * Constructs a RelativeResize filter with the given method and argument.
+ *
+ * @param string $method BoxInterface method
+ * @param mixed $parameter Parameter for BoxInterface method
+ */
+ public function __construct($method, $parameter)
+ {
+ if (!in_array($method, array('heighten', 'increase', 'scale', 'widen'))) {
+ throw new InvalidArgumentException(sprintf('Unsupported method: ', $method));
+ }
+
+ $this->method = $method;
+ $this->parameter = $parameter;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ return $image->resize(call_user_func(array($image->getSize(), $this->method), $this->parameter));
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/ApplyMask.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/ApplyMask.php
new file mode 100644
index 0000000..2be2786
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/ApplyMask.php
@@ -0,0 +1,42 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Basic;
+
+use Imagine\Filter\FilterInterface;
+use Imagine\Image\ImageInterface;
+
+/**
+ * An apply mask filter
+ */
+class ApplyMask implements FilterInterface
+{
+ /**
+ * @var ImageInterface
+ */
+ private $mask;
+
+ /**
+ * @param ImageInterface $mask
+ */
+ public function __construct(ImageInterface $mask)
+ {
+ $this->mask = $mask;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ return $image->applyMask($this->mask);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Autorotate.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Autorotate.php
new file mode 100644
index 0000000..3ef7cbe
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Autorotate.php
@@ -0,0 +1,87 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Basic;
+
+use Imagine\Filter\FilterInterface;
+use Imagine\Image\ImageInterface;
+use Imagine\Image\Palette\Color\ColorInterface;
+
+/**
+ * Rotates an image automatically based on exif information.
+ *
+ * Your attention please: This filter requires the use of the
+ * ExifMetadataReader to work.
+ *
+ * @see https://imagine.readthedocs.org/en/latest/usage/metadata.html
+ */
+class Autorotate implements FilterInterface
+{
+ private $color;
+
+ /**
+ * @param string|array|ColorInterface $color A color
+ */
+ public function __construct($color = '000000')
+ {
+ $this->color = $color;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ $metadata = $image->metadata();
+
+ switch (isset($metadata['ifd0.Orientation']) ? $metadata['ifd0.Orientation'] : null) {
+ case 1: // top-left
+ break;
+ case 2: // top-right
+ $image->flipHorizontally();
+ break;
+ case 3: // bottom-right
+ $image->rotate(180, $this->getColor($image));
+ break;
+ case 4: // bottom-left
+ $image->flipHorizontally();
+ $image->rotate(180, $this->getColor($image));
+ break;
+ case 5: // left-top
+ $image->flipHorizontally();
+ $image->rotate(-90, $this->getColor($image));
+ break;
+ case 6: // right-top
+ $image->rotate(90, $this->getColor($image));
+ break;
+ case 7: // right-bottom
+ $image->flipHorizontally();
+ $image->rotate(90, $this->getColor($image));
+ break;
+ case 8: // left-bottom
+ $image->rotate(-90, $this->getColor($image));
+ break;
+ default: // Invalid orientation
+ break;
+ }
+
+ return $image;
+ }
+
+ private function getColor(ImageInterface $image)
+ {
+ if ($this->color instanceof ColorInterface) {
+ return $this->color;
+ }
+
+ return $image->palette()->color($this->color);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Copy.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Copy.php
new file mode 100644
index 0000000..781b23a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Copy.php
@@ -0,0 +1,29 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Basic;
+
+use Imagine\Filter\FilterInterface;
+use Imagine\Image\ImageInterface;
+
+/**
+ * A copy filter
+ */
+class Copy implements FilterInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ return $image->copy();
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Crop.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Crop.php
new file mode 100644
index 0000000..6559e22
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Crop.php
@@ -0,0 +1,54 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Basic;
+
+use Imagine\Image\ImageInterface;
+use Imagine\Image\BoxInterface;
+use Imagine\Image\PointInterface;
+use Imagine\Filter\FilterInterface;
+
+/**
+ * A crop filter
+ */
+class Crop implements FilterInterface
+{
+ /**
+ * @var PointInterface
+ */
+ private $start;
+
+ /**
+ * @var BoxInterface
+ */
+ private $size;
+
+ /**
+ * Constructs a Crop filter with given x, y, coordinates and crop width and
+ * height values
+ *
+ * @param PointInterface $start
+ * @param BoxInterface $size
+ */
+ public function __construct(PointInterface $start, BoxInterface $size)
+ {
+ $this->start = $start;
+ $this->size = $size;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ return $image->crop($this->start, $this->size);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Fill.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Fill.php
new file mode 100644
index 0000000..4be0d0f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Fill.php
@@ -0,0 +1,43 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Basic;
+
+use Imagine\Filter\FilterInterface;
+use Imagine\Image\Fill\FillInterface;
+use Imagine\Image\ImageInterface;
+
+/**
+ * A fill filter
+ */
+class Fill implements FilterInterface
+{
+ /**
+ * @var FillInterface
+ */
+ private $fill;
+
+ /**
+ * @param FillInterface $fill
+ */
+ public function __construct(FillInterface $fill)
+ {
+ $this->fill = $fill;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ return $image->fill($this->fill);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/FlipHorizontally.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/FlipHorizontally.php
new file mode 100644
index 0000000..5020374
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/FlipHorizontally.php
@@ -0,0 +1,29 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Basic;
+
+use Imagine\Image\ImageInterface;
+use Imagine\Filter\FilterInterface;
+
+/**
+ * A "flip horizontally" filter
+ */
+class FlipHorizontally implements FilterInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ return $image->flipHorizontally();
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/FlipVertically.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/FlipVertically.php
new file mode 100644
index 0000000..684c31b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/FlipVertically.php
@@ -0,0 +1,29 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Basic;
+
+use Imagine\Image\ImageInterface;
+use Imagine\Filter\FilterInterface;
+
+/**
+ * A "flip vertically" filter
+ */
+class FlipVertically implements FilterInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ return $image->flipVertically();
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Paste.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Paste.php
new file mode 100644
index 0000000..bd274a1
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Paste.php
@@ -0,0 +1,53 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Basic;
+
+use Imagine\Image\ImageInterface;
+use Imagine\Image\PointInterface;
+use Imagine\Filter\FilterInterface;
+
+/**
+ * A paste filter
+ */
+class Paste implements FilterInterface
+{
+ /**
+ * @var ImageInterface
+ */
+ private $image;
+
+ /**
+ * @var PointInterface
+ */
+ private $start;
+
+ /**
+ * Constructs a Paste filter with given ImageInterface to paste and x, y
+ * coordinates of target position
+ *
+ * @param ImageInterface $image
+ * @param PointInterface $start
+ */
+ public function __construct(ImageInterface $image, PointInterface $start)
+ {
+ $this->image = $image;
+ $this->start = $start;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ return $image->paste($this->image, $this->start);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Resize.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Resize.php
new file mode 100644
index 0000000..934cfe2
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Resize.php
@@ -0,0 +1,48 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Basic;
+
+use Imagine\Filter\FilterInterface;
+use Imagine\Image\ImageInterface;
+use Imagine\Image\BoxInterface;
+
+/**
+ * A resize filter
+ */
+class Resize implements FilterInterface
+{
+ /**
+ * @var BoxInterface
+ */
+ private $size;
+ private $filter;
+
+ /**
+ * Constructs Resize filter with given width and height
+ *
+ * @param BoxInterface $size
+ * @param string $filter
+ */
+ public function __construct(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED)
+ {
+ $this->size = $size;
+ $this->filter = $filter;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ return $image->resize($this->size, $this->filter);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Rotate.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Rotate.php
new file mode 100644
index 0000000..7b5553f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Rotate.php
@@ -0,0 +1,52 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Basic;
+
+use Imagine\Image\ImageInterface;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Filter\FilterInterface;
+
+/**
+ * A rotate filter
+ */
+class Rotate implements FilterInterface
+{
+ /**
+ * @var integer
+ */
+ private $angle;
+
+ /**
+ * @var ColorInterface
+ */
+ private $background;
+
+ /**
+ * Constructs Rotate filter with given angle and background color
+ *
+ * @param integer $angle
+ * @param ColorInterface $background
+ */
+ public function __construct($angle, ColorInterface $background = null)
+ {
+ $this->angle = $angle;
+ $this->background = $background;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ return $image->rotate($this->angle, $this->background);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Save.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Save.php
new file mode 100644
index 0000000..0f76625
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Save.php
@@ -0,0 +1,51 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Basic;
+
+use Imagine\Image\ImageInterface;
+use Imagine\Filter\FilterInterface;
+
+/**
+ * A save filter
+ */
+class Save implements FilterInterface
+{
+ /**
+ * @var string
+ */
+ private $path;
+
+ /**
+ * @var array
+ */
+ private $options;
+
+ /**
+ * Constructs Save filter with given path and options
+ *
+ * @param string $path
+ * @param array $options
+ */
+ public function __construct($path = null, array $options = array())
+ {
+ $this->path = $path;
+ $this->options = $options;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ return $image->save($this->path, $this->options);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Show.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Show.php
new file mode 100644
index 0000000..a7d4cbc
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Show.php
@@ -0,0 +1,51 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Basic;
+
+use Imagine\Image\ImageInterface;
+use Imagine\Filter\FilterInterface;
+
+/**
+ * A show filter
+ */
+class Show implements FilterInterface
+{
+ /**
+ * @var string
+ */
+ private $format;
+
+ /**
+ * @var array
+ */
+ private $options;
+
+ /**
+ * Constructs the Show filter with given format and options
+ *
+ * @param string $format
+ * @param array $options
+ */
+ public function __construct($format, array $options = array())
+ {
+ $this->format = $format;
+ $this->options = $options;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ return $image->show($this->format, $this->options);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Strip.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Strip.php
new file mode 100644
index 0000000..c096a51
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Strip.php
@@ -0,0 +1,29 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Basic;
+
+use Imagine\Image\ImageInterface;
+use Imagine\Filter\FilterInterface;
+
+/**
+ * A strip filter
+ */
+class Strip implements FilterInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ return $image->strip();
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Thumbnail.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Thumbnail.php
new file mode 100644
index 0000000..3176f1c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/Thumbnail.php
@@ -0,0 +1,59 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Basic;
+
+use Imagine\Image\ImageInterface;
+use Imagine\Image\BoxInterface;
+use Imagine\Filter\FilterInterface;
+
+/**
+ * A thumbnail filter
+ */
+class Thumbnail implements FilterInterface
+{
+ /**
+ * @var BoxInterface
+ */
+ private $size;
+
+ /**
+ * @var string
+ */
+ private $mode;
+
+ /**
+ * @var string
+ */
+ private $filter;
+
+ /**
+ * Constructs the Thumbnail filter with given width, height and mode
+ *
+ * @param BoxInterface $size
+ * @param string $mode
+ * @param string $filter
+ */
+ public function __construct(BoxInterface $size, $mode = ImageInterface::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED)
+ {
+ $this->size = $size;
+ $this->mode = $mode;
+ $this->filter = $filter;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ return $image->thumbnail($this->size, $this->mode, $this->filter);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/WebOptimization.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/WebOptimization.php
new file mode 100644
index 0000000..37f5f3f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Basic/WebOptimization.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter\Basic;
+
+use Imagine\Image\ImageInterface;
+use Imagine\Image\Palette\RGB;
+use Imagine\Filter\FilterInterface;
+
+/**
+ * A filter to render web-optimized images
+ */
+class WebOptimization implements FilterInterface
+{
+ private $palette;
+ private $path;
+ private $options;
+
+ public function __construct($path = null, array $options = array())
+ {
+ $this->path = $path;
+ $this->options = array_replace(array(
+ 'resolution-units' => ImageInterface::RESOLUTION_PIXELSPERINCH,
+ 'resolution-y' => 72,
+ 'resolution-x' => 72,
+ ), $options);
+ $this->palette = new RGB();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ $image
+ ->usePalette($this->palette)
+ ->strip();
+
+ if (is_callable($this->path)) {
+ $path = call_user_func($this->path, $image);
+ } elseif (null !== $this->path) {
+ $path = $this->path;
+ } else {
+ return $image;
+ }
+
+ return $image->save($path, $this->options);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/FilterInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/FilterInterface.php
new file mode 100644
index 0000000..e23ab70
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/FilterInterface.php
@@ -0,0 +1,30 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter;
+
+use Imagine\Image\ImageInterface;
+
+/**
+ * Interface for imagine filters
+ */
+interface FilterInterface
+{
+ /**
+ * Applies scheduled transformation to ImageInterface instance
+ * Returns processed ImageInterface instance
+ *
+ * @param ImageInterface $image
+ *
+ * @return ImageInterface
+ */
+ public function apply(ImageInterface $image);
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/ImagineAware.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/ImagineAware.php
new file mode 100644
index 0000000..606c525
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/ImagineAware.php
@@ -0,0 +1,54 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter;
+
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Image\ImagineInterface;
+
+/**
+ * ImagineAware base class
+ */
+abstract class ImagineAware implements FilterInterface
+{
+ /**
+ * An ImagineInterface instance.
+ *
+ * @var ImagineInterface
+ */
+ private $imagine;
+
+ /**
+ * Set ImagineInterface instance.
+ *
+ * @param ImagineInterface $imagine An ImagineInterface instance
+ */
+ public function setImagine(ImagineInterface $imagine)
+ {
+ $this->imagine = $imagine;
+ }
+
+ /**
+ * Get ImagineInterface instance.
+ *
+ * @return ImagineInterface
+ *
+ * @throws InvalidArgumentException
+ */
+ public function getImagine()
+ {
+ if (!$this->imagine instanceof ImagineInterface) {
+ throw new InvalidArgumentException(sprintf('In order to use %s pass an Imagine\Image\ImagineInterface instance to filter constructor', get_class($this)));
+ }
+
+ return $this->imagine;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Transformation.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Transformation.php
new file mode 100644
index 0000000..26c023a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Filter/Transformation.php
@@ -0,0 +1,240 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Filter;
+
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Filter\Basic\ApplyMask;
+use Imagine\Filter\Basic\Copy;
+use Imagine\Filter\Basic\Crop;
+use Imagine\Filter\Basic\Fill;
+use Imagine\Filter\Basic\FlipVertically;
+use Imagine\Filter\Basic\FlipHorizontally;
+use Imagine\Filter\Basic\Paste;
+use Imagine\Filter\Basic\Resize;
+use Imagine\Filter\Basic\Rotate;
+use Imagine\Filter\Basic\Save;
+use Imagine\Filter\Basic\Show;
+use Imagine\Filter\Basic\Strip;
+use Imagine\Filter\Basic\Thumbnail;
+use Imagine\Image\ImageInterface;
+use Imagine\Image\ImagineInterface;
+use Imagine\Image\BoxInterface;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\Fill\FillInterface;
+use Imagine\Image\ManipulatorInterface;
+use Imagine\Image\PointInterface;
+
+/**
+ * A transformation filter
+ */
+final class Transformation implements FilterInterface, ManipulatorInterface
+{
+ /**
+ * @var array
+ */
+ private $filters = array();
+
+ /**
+ * @var array
+ */
+ private $sorted;
+
+ /**
+ * An ImagineInterface instance.
+ *
+ * @var ImagineInterface
+ */
+ private $imagine;
+
+ /**
+ * Class constructor.
+ *
+ * @param ImagineInterface $imagine An ImagineInterface instance
+ */
+ public function __construct(ImagineInterface $imagine = null)
+ {
+ $this->imagine = $imagine;
+ }
+
+ /**
+ * Applies a given FilterInterface onto given ImageInterface and returns
+ * modified ImageInterface
+ *
+ * @param ImageInterface $image
+ * @param FilterInterface $filter
+ *
+ * @return ImageInterface
+ * @throws InvalidArgumentException
+ */
+ public function applyFilter(ImageInterface $image, FilterInterface $filter)
+ {
+ if ($filter instanceof ImagineAware) {
+ if ($this->imagine === null) {
+ throw new InvalidArgumentException(sprintf('In order to use %s pass an Imagine\Image\ImagineInterface instance to Transformation constructor', get_class($filter)));
+ }
+ $filter->setImagine($this->imagine);
+ }
+
+ return $filter->apply($image);
+ }
+
+ /**
+ * Returns a list of filters sorted by their priority. Filters with same priority will be returned in the order they were added.
+ *
+ * @return array
+ */
+ public function getFilters()
+ {
+ if (null === $this->sorted) {
+ if (!empty($this->filters)) {
+ ksort($this->filters);
+ $this->sorted = call_user_func_array('array_merge', $this->filters);
+ } else {
+ $this->sorted = array();
+ }
+ }
+
+ return $this->sorted;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(ImageInterface $image)
+ {
+ return array_reduce(
+ $this->getFilters(),
+ array($this, 'applyFilter'),
+ $image
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function copy()
+ {
+ return $this->add(new Copy());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function crop(PointInterface $start, BoxInterface $size)
+ {
+ return $this->add(new Crop($start, $size));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function flipHorizontally()
+ {
+ return $this->add(new FlipHorizontally());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function flipVertically()
+ {
+ return $this->add(new FlipVertically());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function strip()
+ {
+ return $this->add(new Strip());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function paste(ImageInterface $image, PointInterface $start)
+ {
+ return $this->add(new Paste($image, $start));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function applyMask(ImageInterface $mask)
+ {
+ return $this->add(new ApplyMask($mask));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function fill(FillInterface $fill)
+ {
+ return $this->add(new Fill($fill));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED)
+ {
+ return $this->add(new Resize($size, $filter));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function rotate($angle, ColorInterface $background = null)
+ {
+ return $this->add(new Rotate($angle, $background));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function save($path = null, array $options = array())
+ {
+ return $this->add(new Save($path, $options));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function show($format, array $options = array())
+ {
+ return $this->add(new Show($format, $options));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function thumbnail(BoxInterface $size, $mode = ImageInterface::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED)
+ {
+ return $this->add(new Thumbnail($size, $mode, $filter));
+ }
+
+ /**
+ * Registers a given FilterInterface in an internal array of filters for
+ * later application to an instance of ImageInterface
+ *
+ * @param FilterInterface $filter
+ * @param int $priority
+ * @return Transformation
+ */
+ public function add(FilterInterface $filter, $priority = 0)
+ {
+ $this->filters[$priority][] = $filter;
+ $this->sorted = null;
+
+ return $this;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Drawer.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Drawer.php
new file mode 100644
index 0000000..e5d74e0
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Drawer.php
@@ -0,0 +1,333 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Gd;
+
+use Imagine\Draw\DrawerInterface;
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Exception\RuntimeException;
+use Imagine\Image\AbstractFont;
+use Imagine\Image\BoxInterface;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\Palette\Color\RGB as RGBColor;
+use Imagine\Image\PointInterface;
+
+/**
+ * Drawer implementation using the GD library
+ */
+final class Drawer implements DrawerInterface
+{
+ /**
+ * @var resource
+ */
+ private $resource;
+
+ /**
+ * @var array
+ */
+ private $info;
+
+ /**
+ * Constructs Drawer with a given gd image resource
+ *
+ * @param resource $resource
+ */
+ public function __construct($resource)
+ {
+ $this->loadGdInfo();
+ $this->resource = $resource;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1)
+ {
+ imagesetthickness($this->resource, max(1, (int) $thickness));
+
+ if (false === imagealphablending($this->resource, true)) {
+ throw new RuntimeException('Draw arc operation failed');
+ }
+
+ if (false === imagearc($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $start, $end, $this->getColor($color))) {
+ imagealphablending($this->resource, false);
+ throw new RuntimeException('Draw arc operation failed');
+ }
+
+ if (false === imagealphablending($this->resource, false)) {
+ throw new RuntimeException('Draw arc operation failed');
+ }
+
+ return $this;
+ }
+
+ /**
+ * This function does not work properly because of a bug in GD
+ *
+ * {@inheritdoc}
+ */
+ public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1)
+ {
+ imagesetthickness($this->resource, max(1, (int) $thickness));
+
+ if ($fill) {
+ $style = IMG_ARC_CHORD;
+ } else {
+ $style = IMG_ARC_CHORD | IMG_ARC_NOFILL;
+ }
+
+ if (false === imagealphablending($this->resource, true)) {
+ throw new RuntimeException('Draw chord operation failed');
+ }
+
+ if (false === imagefilledarc($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $start, $end, $this->getColor($color), $style)) {
+ imagealphablending($this->resource, false);
+ throw new RuntimeException('Draw chord operation failed');
+ }
+
+ if (false === imagealphablending($this->resource, false)) {
+ throw new RuntimeException('Draw chord operation failed');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1)
+ {
+ imagesetthickness($this->resource, max(1, (int) $thickness));
+
+ if ($fill) {
+ $callback = 'imagefilledellipse';
+ } else {
+ $callback = 'imageellipse';
+ }
+
+ if (false === imagealphablending($this->resource, true)) {
+ throw new RuntimeException('Draw ellipse operation failed');
+ }
+
+ if (false === $callback($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $this->getColor($color))) {
+ imagealphablending($this->resource, false);
+ throw new RuntimeException('Draw ellipse operation failed');
+ }
+
+ if (false === imagealphablending($this->resource, false)) {
+ throw new RuntimeException('Draw ellipse operation failed');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function line(PointInterface $start, PointInterface $end, ColorInterface $color, $thickness = 1)
+ {
+ imagesetthickness($this->resource, max(1, (int) $thickness));
+
+ if (false === imagealphablending($this->resource, true)) {
+ throw new RuntimeException('Draw line operation failed');
+ }
+
+ if (false === imageline($this->resource, $start->getX(), $start->getY(), $end->getX(), $end->getY(), $this->getColor($color))) {
+ imagealphablending($this->resource, false);
+ throw new RuntimeException('Draw line operation failed');
+ }
+
+ if (false === imagealphablending($this->resource, false)) {
+ throw new RuntimeException('Draw line operation failed');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1)
+ {
+ imagesetthickness($this->resource, max(1, (int) $thickness));
+
+ if ($fill) {
+ $style = IMG_ARC_EDGED;
+ } else {
+ $style = IMG_ARC_EDGED | IMG_ARC_NOFILL;
+ }
+
+ if (false === imagealphablending($this->resource, true)) {
+ throw new RuntimeException('Draw chord operation failed');
+ }
+
+ if (false === imagefilledarc($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $start, $end, $this->getColor($color), $style)) {
+ imagealphablending($this->resource, false);
+ throw new RuntimeException('Draw chord operation failed');
+ }
+
+ if (false === imagealphablending($this->resource, false)) {
+ throw new RuntimeException('Draw chord operation failed');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function dot(PointInterface $position, ColorInterface $color)
+ {
+ if (false === imagealphablending($this->resource, true)) {
+ throw new RuntimeException('Draw point operation failed');
+ }
+
+ if (false === imagesetpixel($this->resource, $position->getX(), $position->getY(), $this->getColor($color))) {
+ imagealphablending($this->resource, false);
+ throw new RuntimeException('Draw point operation failed');
+ }
+
+ if (false === imagealphablending($this->resource, false)) {
+ throw new RuntimeException('Draw point operation failed');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1)
+ {
+ imagesetthickness($this->resource, max(1, (int) $thickness));
+
+ if (count($coordinates) < 3) {
+ throw new InvalidArgumentException(sprintf('A polygon must consist of at least 3 points, %d given', count($coordinates)));
+ }
+
+ $points = call_user_func_array('array_merge', array_map(function (PointInterface $p) {
+ return array($p->getX(), $p->getY());
+ }, $coordinates));
+
+ if ($fill) {
+ $callback = 'imagefilledpolygon';
+ } else {
+ $callback = 'imagepolygon';
+ }
+
+ if (false === imagealphablending($this->resource, true)) {
+ throw new RuntimeException('Draw polygon operation failed');
+ }
+
+ if (false === $callback($this->resource, $points, count($coordinates), $this->getColor($color))) {
+ imagealphablending($this->resource, false);
+ throw new RuntimeException('Draw polygon operation failed');
+ }
+
+ if (false === imagealphablending($this->resource, false)) {
+ throw new RuntimeException('Draw polygon operation failed');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null)
+ {
+ if (!$this->info['FreeType Support']) {
+ throw new RuntimeException('GD is not compiled with FreeType support');
+ }
+
+ $angle = -1 * $angle;
+ $fontsize = $font->getSize();
+ $fontfile = $font->getFile();
+ $x = $position->getX();
+ $y = $position->getY() + $fontsize;
+
+ if ($width !== null) {
+ $string = $this->wrapText($string, $font, $angle, $width);
+ }
+
+ if (false === imagealphablending($this->resource, true)) {
+ throw new RuntimeException('Font mask operation failed');
+ }
+
+ if (false === imagefttext($this->resource, $fontsize, $angle, $x, $y, $this->getColor($font->getColor()), $fontfile, $string)) {
+ imagealphablending($this->resource, false);
+ throw new RuntimeException('Font mask operation failed');
+ }
+
+ if (false === imagealphablending($this->resource, false)) {
+ throw new RuntimeException('Font mask operation failed');
+ }
+
+ return $this;
+ }
+
+ /**
+ * Internal
+ *
+ * Generates a GD color from Color instance
+ *
+ * @param ColorInterface $color
+ *
+ * @return resource
+ *
+ * @throws RuntimeException
+ * @throws InvalidArgumentException
+ */
+ private function getColor(ColorInterface $color)
+ {
+ if (!$color instanceof RGBColor) {
+ throw new InvalidArgumentException('GD driver only supports RGB colors');
+ }
+
+ $gdColor = imagecolorallocatealpha($this->resource, $color->getRed(), $color->getGreen(), $color->getBlue(), (100 - $color->getAlpha()) * 127 / 100);
+ if (false === $gdColor) {
+ throw new RuntimeException(sprintf('Unable to allocate color "RGB(%s, %s, %s)" with transparency of %d percent', $color->getRed(), $color->getGreen(), $color->getBlue(), $color->getAlpha()));
+ }
+
+ return $gdColor;
+ }
+
+ private function loadGdInfo()
+ {
+ if (!function_exists('gd_info')) {
+ throw new RuntimeException('Gd not installed');
+ }
+
+ $this->info = gd_info();
+ }
+
+ /**
+ * Internal
+ *
+ * Fits a string into box with given width
+ */
+ private function wrapText($string, AbstractFont $font, $angle, $width)
+ {
+ $result = '';
+ $words = explode(' ', $string);
+ foreach ($words as $word) {
+ $teststring = $result . ' ' . $word;
+ $testbox = imagettfbbox($font->getSize(), $angle, $font->getFile(), $teststring);
+ if ($testbox[2] > $width) {
+ $result .= ($result == '' ? '' : "\n") . $word;
+ } else {
+ $result .= ($result == '' ? '' : ' ') . $word;
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Effects.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Effects.php
new file mode 100644
index 0000000..d86c4f8
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Effects.php
@@ -0,0 +1,109 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Gd;
+
+use Imagine\Effects\EffectsInterface;
+use Imagine\Exception\RuntimeException;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\Palette\Color\RGB as RGBColor;
+
+/**
+ * Effects implementation using the GD library
+ */
+class Effects implements EffectsInterface
+{
+ private $resource;
+
+ public function __construct($resource)
+ {
+ $this->resource = $resource;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function gamma($correction)
+ {
+ if (false === imagegammacorrect($this->resource, 1.0, $correction)) {
+ throw new RuntimeException('Failed to apply gamma correction to the image');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function negative()
+ {
+ if (false === imagefilter($this->resource, IMG_FILTER_NEGATE)) {
+ throw new RuntimeException('Failed to negate the image');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function grayscale()
+ {
+ if (false === imagefilter($this->resource, IMG_FILTER_GRAYSCALE)) {
+ throw new RuntimeException('Failed to grayscale the image');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function colorize(ColorInterface $color)
+ {
+ if (!$color instanceof RGBColor) {
+ throw new RuntimeException('Colorize effects only accepts RGB color in GD context');
+ }
+
+ if (false === imagefilter($this->resource, IMG_FILTER_COLORIZE, $color->getRed(), $color->getGreen(), $color->getBlue())) {
+ throw new RuntimeException('Failed to colorize the image');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function sharpen()
+ {
+ $sharpenMatrix = array(array(-1,-1,-1), array(-1,16,-1), array(-1,-1,-1));
+ $divisor = array_sum(array_map('array_sum', $sharpenMatrix));
+
+ if (false === imageconvolution($this->resource, $sharpenMatrix, $divisor, 0)) {
+ throw new RuntimeException('Failed to sharpen the image');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function blur($sigma = 1)
+ {
+ if (false === imagefilter($this->resource, IMG_FILTER_GAUSSIAN_BLUR)) {
+ throw new RuntimeException('Failed to blur the image');
+ }
+
+ return $this;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Font.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Font.php
new file mode 100644
index 0000000..8bc2b04
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Font.php
@@ -0,0 +1,41 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Gd;
+
+use Imagine\Exception\RuntimeException;
+use Imagine\Image\AbstractFont;
+use Imagine\Image\Box;
+
+/**
+ * Font implementation using the GD library
+ */
+final class Font extends AbstractFont
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function box($string, $angle = 0)
+ {
+ if (!function_exists('imageftbbox')) {
+ throw new RuntimeException('GD must have been compiled with `--with-freetype-dir` option to use the Font feature.');
+ }
+
+ $angle = -1 * $angle;
+ $info = imageftbbox($this->size, $angle, $this->file, $string);
+ $xs = array($info[0], $info[2], $info[4], $info[6]);
+ $ys = array($info[1], $info[3], $info[5], $info[7]);
+ $width = abs(max($xs) - min($xs));
+ $height = abs(max($ys) - min($ys));
+
+ return new Box($width, $height);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Image.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Image.php
new file mode 100644
index 0000000..73d7b95
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Image.php
@@ -0,0 +1,735 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Gd;
+
+use Imagine\Image\AbstractImage;
+use Imagine\Image\ImageInterface;
+use Imagine\Image\Box;
+use Imagine\Image\BoxInterface;
+use Imagine\Image\Metadata\MetadataBag;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\Fill\FillInterface;
+use Imagine\Image\Point;
+use Imagine\Image\PointInterface;
+use Imagine\Image\Palette\PaletteInterface;
+use Imagine\Image\Palette\Color\RGB as RGBColor;
+use Imagine\Image\ProfileInterface;
+use Imagine\Image\Palette\RGB;
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Exception\OutOfBoundsException;
+use Imagine\Exception\RuntimeException;
+
+/**
+ * Image implementation using the GD library
+ */
+final class Image extends AbstractImage
+{
+ /**
+ * @var resource
+ */
+ private $resource;
+
+ /**
+ * @var Layers|null
+ */
+ private $layers;
+
+ /**
+ * @var PaletteInterface
+ */
+ private $palette;
+
+ /**
+ * Constructs a new Image instance
+ *
+ * @param resource $resource
+ * @param PaletteInterface $palette
+ * @param MetadataBag $metadata
+ */
+ public function __construct($resource, PaletteInterface $palette, MetadataBag $metadata)
+ {
+ $this->metadata = $metadata;
+ $this->palette = $palette;
+ $this->resource = $resource;
+ }
+
+ /**
+ * Makes sure the current image resource is destroyed
+ */
+ public function __destruct()
+ {
+ if (is_resource($this->resource) && 'gd' === get_resource_type($this->resource)) {
+ imagedestroy($this->resource);
+ }
+ }
+
+ /**
+ * Returns Gd resource
+ *
+ * @return resource
+ */
+ public function getGdResource()
+ {
+ return $this->resource;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ final public function copy()
+ {
+ $size = $this->getSize();
+ $copy = $this->createImage($size, 'copy');
+
+ if (false === imagecopy($copy, $this->resource, 0, 0, 0, 0, $size->getWidth(), $size->getHeight())) {
+ throw new RuntimeException('Image copy operation failed');
+ }
+
+ return new Image($copy, $this->palette, $this->metadata);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ final public function crop(PointInterface $start, BoxInterface $size)
+ {
+ if (!$start->in($this->getSize())) {
+ throw new OutOfBoundsException('Crop coordinates must start at minimum 0, 0 position from top left corner, crop height and width must be positive integers and must not exceed the current image borders');
+ }
+
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+
+ $dest = $this->createImage($size, 'crop');
+
+ if (false === imagecopy($dest, $this->resource, 0, 0, $start->getX(), $start->getY(), $width, $height)) {
+ throw new RuntimeException('Image crop operation failed');
+ }
+
+ imagedestroy($this->resource);
+
+ $this->resource = $dest;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ final public function paste(ImageInterface $image, PointInterface $start)
+ {
+ if (!$image instanceof self) {
+ throw new InvalidArgumentException(sprintf('Gd\Image can only paste() Gd\Image instances, %s given', get_class($image)));
+ }
+
+ $size = $image->getSize();
+ if (!$this->getSize()->contains($size, $start)) {
+ throw new OutOfBoundsException('Cannot paste image of the given size at the specified position, as it moves outside of the current image\'s box');
+ }
+
+ imagealphablending($this->resource, true);
+ imagealphablending($image->resource, true);
+
+ if (false === imagecopy($this->resource, $image->resource, $start->getX(), $start->getY(), 0, 0, $size->getWidth(), $size->getHeight())) {
+ throw new RuntimeException('Image paste operation failed');
+ }
+
+ imagealphablending($this->resource, false);
+ imagealphablending($image->resource, false);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ final public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED)
+ {
+ if (ImageInterface::FILTER_UNDEFINED !== $filter) {
+ throw new InvalidArgumentException('Unsupported filter type, GD only supports ImageInterface::FILTER_UNDEFINED filter');
+ }
+
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+
+ $dest = $this->createImage($size, 'resize');
+
+ imagealphablending($this->resource, true);
+ imagealphablending($dest, true);
+
+ if (false === imagecopyresampled($dest, $this->resource, 0, 0, 0, 0, $width, $height, imagesx($this->resource), imagesy($this->resource))) {
+ throw new RuntimeException('Image resize operation failed');
+ }
+
+ imagealphablending($this->resource, false);
+ imagealphablending($dest, false);
+
+ imagedestroy($this->resource);
+
+ $this->resource = $dest;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ final public function rotate($angle, ColorInterface $background = null)
+ {
+ $color = $background ? $background : $this->palette->color('fff');
+ $resource = imagerotate($this->resource, -1 * $angle, $this->getColor($color));
+
+ if (false === $resource) {
+ throw new RuntimeException('Image rotate operation failed');
+ }
+
+ imagedestroy($this->resource);
+ $this->resource = $resource;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ final public function save($path = null, array $options = array())
+ {
+ $path = null === $path ? (isset($this->metadata['filepath']) ? $this->metadata['filepath'] : $path) : $path;
+
+ if (null === $path) {
+ throw new RuntimeException('You can omit save path only if image has been open from a file');
+ }
+
+ if (isset($options['format'])) {
+ $format = $options['format'];
+ } elseif ('' !== $extension = pathinfo($path, \PATHINFO_EXTENSION)) {
+ $format = $extension;
+ } else {
+ $originalPath = isset($this->metadata['filepath']) ? $this->metadata['filepath'] : null;
+ $format = pathinfo($originalPath, \PATHINFO_EXTENSION);
+ }
+
+ $this->saveOrOutput($format, $options, $path);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function show($format, array $options = array())
+ {
+ header('Content-type: '.$this->getMimeType($format));
+
+ $this->saveOrOutput($format, $options);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($format, array $options = array())
+ {
+ ob_start();
+ $this->saveOrOutput($format, $options);
+
+ return ob_get_clean();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ return $this->get('png');
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ final public function flipHorizontally()
+ {
+ $size = $this->getSize();
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+ $dest = $this->createImage($size, 'flip');
+
+ for ($i = 0; $i < $width; $i++) {
+ if (false === imagecopy($dest, $this->resource, $i, 0, ($width - 1) - $i, 0, 1, $height)) {
+ throw new RuntimeException('Horizontal flip operation failed');
+ }
+ }
+
+ imagedestroy($this->resource);
+
+ $this->resource = $dest;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ final public function flipVertically()
+ {
+ $size = $this->getSize();
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+ $dest = $this->createImage($size, 'flip');
+
+ for ($i = 0; $i < $height; $i++) {
+ if (false === imagecopy($dest, $this->resource, 0, $i, 0, ($height - 1) - $i, $width, 1)) {
+ throw new RuntimeException('Vertical flip operation failed');
+ }
+ }
+
+ imagedestroy($this->resource);
+
+ $this->resource = $dest;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ final public function strip()
+ {
+ // GD strips profiles and comment, so there's nothing to do here
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function draw()
+ {
+ return new Drawer($this->resource);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function effects()
+ {
+ return new Effects($this->resource);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ return new Box(imagesx($this->resource), imagesy($this->resource));
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function applyMask(ImageInterface $mask)
+ {
+ if (!$mask instanceof self) {
+ throw new InvalidArgumentException('Cannot mask non-gd images');
+ }
+
+ $size = $this->getSize();
+ $maskSize = $mask->getSize();
+
+ if ($size != $maskSize) {
+ throw new InvalidArgumentException(sprintf('The given mask doesn\'t match current image\'s size, Current mask\'s dimensions are %s, while image\'s dimensions are %s', $maskSize, $size));
+ }
+
+ for ($x = 0, $width = $size->getWidth(); $x < $width; $x++) {
+ for ($y = 0, $height = $size->getHeight(); $y < $height; $y++) {
+ $position = new Point($x, $y);
+ $color = $this->getColorAt($position);
+ $maskColor = $mask->getColorAt($position);
+ $round = (int) round(max($color->getAlpha(), (100 - $color->getAlpha()) * $maskColor->getRed() / 255));
+
+ if (false === imagesetpixel($this->resource, $x, $y, $this->getColor($color->dissolve($round - $color->getAlpha())))) {
+ throw new RuntimeException('Apply mask operation failed');
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function fill(FillInterface $fill)
+ {
+ $size = $this->getSize();
+
+ for ($x = 0, $width = $size->getWidth(); $x < $width; $x++) {
+ for ($y = 0, $height = $size->getHeight(); $y < $height; $y++) {
+ if (false === imagesetpixel($this->resource, $x, $y, $this->getColor($fill->getColor(new Point($x, $y))))) {
+ throw new RuntimeException('Fill operation failed');
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function mask()
+ {
+ $mask = $this->copy();
+
+ if (false === imagefilter($mask->resource, IMG_FILTER_GRAYSCALE)) {
+ throw new RuntimeException('Mask operation failed');
+ }
+
+ return $mask;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function histogram()
+ {
+ $size = $this->getSize();
+ $colors = array();
+
+ for ($x = 0, $width = $size->getWidth(); $x < $width; $x++) {
+ for ($y = 0, $height = $size->getHeight(); $y < $height; $y++) {
+ $colors[] = $this->getColorAt(new Point($x, $y));
+ }
+ }
+
+ return array_unique($colors);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getColorAt(PointInterface $point)
+ {
+ if (!$point->in($this->getSize())) {
+ throw new RuntimeException(sprintf('Error getting color at point [%s,%s]. The point must be inside the image of size [%s,%s]', $point->getX(), $point->getY(), $this->getSize()->getWidth(), $this->getSize()->getHeight()));
+ }
+
+ $index = imagecolorat($this->resource, $point->getX(), $point->getY());
+ $info = imagecolorsforindex($this->resource, $index);
+
+ return $this->palette->color(array($info['red'], $info['green'], $info['blue']), max(min(100 - (int) round($info['alpha'] / 127 * 100), 100), 0));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function layers()
+ {
+ if (null === $this->layers) {
+ $this->layers = new Layers($this, $this->palette, $this->resource);
+ }
+
+ return $this->layers;
+ }
+
+ /**
+ * {@inheritdoc}
+ **/
+ public function interlace($scheme)
+ {
+ static $supportedInterlaceSchemes = array(
+ ImageInterface::INTERLACE_NONE => 0,
+ ImageInterface::INTERLACE_LINE => 1,
+ ImageInterface::INTERLACE_PLANE => 1,
+ ImageInterface::INTERLACE_PARTITION => 1,
+ );
+
+ if (!array_key_exists($scheme, $supportedInterlaceSchemes)) {
+ throw new InvalidArgumentException('Unsupported interlace type');
+ }
+
+ imageinterlace($this->resource, $supportedInterlaceSchemes[$scheme]);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function palette()
+ {
+ return $this->palette;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function profile(ProfileInterface $profile)
+ {
+ throw new RuntimeException('GD driver does not support color profiles');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function usePalette(PaletteInterface $palette)
+ {
+ if (!$palette instanceof RGB) {
+ throw new RuntimeException('GD driver only supports RGB palette');
+ }
+
+ $this->palette = $palette;
+
+ return $this;
+ }
+
+ /**
+ * Internal
+ *
+ * Performs save or show operation using one of GD's image... functions
+ *
+ * @param string $format
+ * @param array $options
+ * @param string $filename
+ *
+ * @throws InvalidArgumentException
+ * @throws RuntimeException
+ */
+ private function saveOrOutput($format, array $options, $filename = null)
+ {
+ $format = $this->normalizeFormat($format);
+
+ if (!$this->supported($format)) {
+ throw new InvalidArgumentException(sprintf('Saving image in "%s" format is not supported, please use one of the following extensions: "%s"', $format, implode('", "', $this->supported())));
+ }
+
+ $save = 'image'.$format;
+ $args = array(&$this->resource, $filename);
+
+ // Preserve BC until version 1.0
+ if (isset($options['quality']) && !isset($options['png_compression_level'])) {
+ $options['png_compression_level'] = round((100 - $options['quality']) * 9 / 100);
+ }
+ if (isset($options['filters']) && !isset($options['png_compression_filter'])) {
+ $options['png_compression_filter'] = $options['filters'];
+ }
+
+ $options = $this->updateSaveOptions($options);
+
+ if ($format === 'jpeg' && isset($options['jpeg_quality'])) {
+ $args[] = $options['jpeg_quality'];
+ }
+
+ if ($format === 'png') {
+ if (isset($options['png_compression_level'])) {
+ if ($options['png_compression_level'] < 0 || $options['png_compression_level'] > 9) {
+ throw new InvalidArgumentException('png_compression_level option should be an integer from 0 to 9');
+ }
+ $args[] = $options['png_compression_level'];
+ } else {
+ $args[] = -1; // use default level
+ }
+
+ if (isset($options['png_compression_filter'])) {
+ if (~PNG_ALL_FILTERS & $options['png_compression_filter']) {
+ throw new InvalidArgumentException('png_compression_filter option should be a combination of the PNG_FILTER_XXX constants');
+ }
+ $args[] = $options['png_compression_filter'];
+ }
+ }
+
+ if (($format === 'wbmp' || $format === 'xbm') && isset($options['foreground'])) {
+ $args[] = $options['foreground'];
+ }
+
+ $this->setExceptionHandler();
+
+ if (false === call_user_func_array($save, $args)) {
+ throw new RuntimeException('Save operation failed');
+ }
+
+ $this->resetExceptionHandler();
+ }
+
+ /**
+ * Internal
+ *
+ * Generates a GD image
+ *
+ * @param BoxInterface $size
+ * @param string the operation initiating the creation
+ *
+ * @return resource
+ *
+ * @throws RuntimeException
+ *
+ */
+ private function createImage(BoxInterface $size, $operation)
+ {
+ $resource = imagecreatetruecolor($size->getWidth(), $size->getHeight());
+
+ if (false === $resource) {
+ throw new RuntimeException('Image '.$operation.' failed');
+ }
+
+ if (false === imagealphablending($resource, false) || false === imagesavealpha($resource, true)) {
+ throw new RuntimeException('Image '.$operation.' failed');
+ }
+
+ if (function_exists('imageantialias')) {
+ imageantialias($resource, true);
+ }
+
+ $transparent = imagecolorallocatealpha($resource, 255, 255, 255, 127);
+ imagefill($resource, 0, 0, $transparent);
+ imagecolortransparent($resource, $transparent);
+
+ return $resource;
+ }
+
+ /**
+ * Internal
+ *
+ * Generates a GD color from Color instance
+ *
+ * @param ColorInterface $color
+ *
+ * @return integer A color identifier
+ *
+ * @throws RuntimeException
+ * @throws InvalidArgumentException
+ */
+ private function getColor(ColorInterface $color)
+ {
+ if (!$color instanceof RGBColor) {
+ throw new InvalidArgumentException('GD driver only supports RGB colors');
+ }
+
+ $index = imagecolorallocatealpha($this->resource, $color->getRed(), $color->getGreen(), $color->getBlue(), round(127 * (100 - $color->getAlpha()) / 100));
+
+ if (false === $index) {
+ throw new RuntimeException(sprintf('Unable to allocate color "RGB(%s, %s, %s)" with transparency of %d percent', $color->getRed(), $color->getGreen(), $color->getBlue(), $color->getAlpha()));
+ }
+
+ return $index;
+ }
+
+ /**
+ * Internal
+ *
+ * Normalizes a given format name
+ *
+ * @param string $format
+ *
+ * @return string
+ */
+ private function normalizeFormat($format)
+ {
+ $format = strtolower($format);
+
+ if ('jpg' === $format || 'pjpeg' === $format) {
+ $format = 'jpeg';
+ }
+
+ return $format;
+ }
+
+ /**
+ * Internal
+ *
+ * Checks whether a given format is supported by GD library
+ *
+ * @param string $format
+ *
+ * @return Boolean
+ */
+ private function supported($format = null)
+ {
+ $formats = array('gif', 'jpeg', 'png', 'wbmp', 'xbm');
+
+ if (null === $format) {
+ return $formats;
+ }
+
+ return in_array($format, $formats);
+ }
+
+ private function setExceptionHandler()
+ {
+ set_error_handler(function ($errno, $errstr, $errfile, $errline) {
+ if (0 === error_reporting()) {
+ return;
+ }
+
+ throw new RuntimeException($errstr, $errno, new \ErrorException($errstr, 0, $errno, $errfile, $errline));
+ }, E_WARNING | E_NOTICE);
+ }
+
+ private function resetExceptionHandler()
+ {
+ restore_error_handler();
+ }
+
+ /**
+ * Internal
+ *
+ * Get the mime type based on format.
+ *
+ * @param string $format
+ *
+ * @return string mime-type
+ *
+ * @throws RuntimeException
+ */
+ private function getMimeType($format)
+ {
+ $format = $this->normalizeFormat($format);
+
+ if (!$this->supported($format)) {
+ throw new RuntimeException('Invalid format');
+ }
+
+ static $mimeTypes = array(
+ 'jpeg' => 'image/jpeg',
+ 'gif' => 'image/gif',
+ 'png' => 'image/png',
+ 'wbmp' => 'image/vnd.wap.wbmp',
+ 'xbm' => 'image/xbm',
+ );
+
+ return $mimeTypes[$format];
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Imagine.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Imagine.php
new file mode 100644
index 0000000..f9e9508
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Imagine.php
@@ -0,0 +1,195 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Gd;
+
+use Imagine\Image\AbstractImagine;
+use Imagine\Image\Metadata\MetadataBag;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\Palette\RGB;
+use Imagine\Image\Palette\PaletteInterface;
+use Imagine\Image\BoxInterface;
+use Imagine\Image\Palette\Color\RGB as RGBColor;
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Exception\RuntimeException;
+
+/**
+ * Imagine implementation using the GD library
+ */
+final class Imagine extends AbstractImagine
+{
+ /**
+ * @var array
+ */
+ private $info;
+
+ /**
+ * @throws RuntimeException
+ */
+ public function __construct()
+ {
+ $this->loadGdInfo();
+ $this->requireGdVersion('2.0.1');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function create(BoxInterface $size, ColorInterface $color = null)
+ {
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+
+ $resource = imagecreatetruecolor($width, $height);
+
+ if (false === $resource) {
+ throw new RuntimeException('Create operation failed');
+ }
+
+ $palette = null !== $color ? $color->getPalette() : new RGB();
+ $color = $color ? $color : $palette->color('fff');
+
+ if (!$color instanceof RGBColor) {
+ throw new InvalidArgumentException('GD driver only supports RGB colors');
+ }
+
+ $index = imagecolorallocatealpha($resource, $color->getRed(), $color->getGreen(), $color->getBlue(), round(127 * (100 - $color->getAlpha()) / 100));
+
+ if (false === $index) {
+ throw new RuntimeException('Unable to allocate color');
+ }
+
+ if (false === imagefill($resource, 0, 0, $index)) {
+ throw new RuntimeException('Could not set background color fill');
+ }
+
+ if ($color->getAlpha() >= 95) {
+ imagecolortransparent($resource, $index);
+ }
+
+ return $this->wrap($resource, $palette, new MetadataBag());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function open($path)
+ {
+ $path = $this->checkPath($path);
+ $data = @file_get_contents($path);
+
+ if (false === $data) {
+ throw new RuntimeException(sprintf('Failed to open file %s', $path));
+ }
+
+ $resource = @imagecreatefromstring($data);
+
+ if (!is_resource($resource)) {
+ throw new RuntimeException(sprintf('Unable to open image %s', $path));
+ }
+
+ return $this->wrap($resource, new RGB(), $this->getMetadataReader()->readFile($path));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function load($string)
+ {
+ return $this->doLoad($string, $this->getMetadataReader()->readData($string));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read($resource)
+ {
+ if (!is_resource($resource)) {
+ throw new InvalidArgumentException('Variable does not contain a stream resource');
+ }
+
+ $content = stream_get_contents($resource);
+
+ if (false === $content) {
+ throw new InvalidArgumentException('Cannot read resource content');
+ }
+
+ return $this->doLoad($content, $this->getMetadataReader()->readStream($resource));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function font($file, $size, ColorInterface $color)
+ {
+ if (!$this->info['FreeType Support']) {
+ throw new RuntimeException('GD is not compiled with FreeType support');
+ }
+
+ return new Font($file, $size, $color);
+ }
+
+ private function wrap($resource, PaletteInterface $palette, MetadataBag $metadata)
+ {
+ if (!imageistruecolor($resource)) {
+ list($width, $height) = array(imagesx($resource), imagesy($resource));
+
+ // create transparent truecolor canvas
+ $truecolor = imagecreatetruecolor($width, $height);
+ $transparent = imagecolorallocatealpha($truecolor, 255, 255, 255, 127);
+
+ imagefill($truecolor, 0, 0, $transparent);
+ imagecolortransparent($truecolor, $transparent);
+
+ imagecopymerge($truecolor, $resource, 0, 0, 0, 0, $width, $height, 100);
+
+ imagedestroy($resource);
+ $resource = $truecolor;
+ }
+
+ if (false === imagealphablending($resource, false) || false === imagesavealpha($resource, true)) {
+ throw new RuntimeException('Could not set alphablending, savealpha and antialias values');
+ }
+
+ if (function_exists('imageantialias')) {
+ imageantialias($resource, true);
+ }
+
+ return new Image($resource, $palette, $metadata);
+ }
+
+ private function loadGdInfo()
+ {
+ if (!function_exists('gd_info')) {
+ throw new RuntimeException('Gd not installed');
+ }
+
+ $this->info = gd_info();
+ }
+
+ private function requireGdVersion($version)
+ {
+ if (version_compare(GD_VERSION, $version, '<')) {
+ throw new RuntimeException(sprintf('GD2 version %s or higher is required', $version));
+ }
+ }
+
+ private function doLoad($string, MetadataBag $metadata)
+ {
+ $resource = @imagecreatefromstring($string);
+
+ if (!is_resource($resource)) {
+ throw new RuntimeException('An image could not be created from the given input');
+ }
+
+ return $this->wrap($resource, new RGB(), $metadata);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Layers.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Layers.php
new file mode 100644
index 0000000..93c7a26
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gd/Layers.php
@@ -0,0 +1,144 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Gd;
+
+use Imagine\Image\AbstractLayers;
+use Imagine\Exception\RuntimeException;
+use Imagine\Image\Metadata\MetadataBag;
+use Imagine\Image\Palette\PaletteInterface;
+use Imagine\Exception\NotSupportedException;
+
+class Layers extends AbstractLayers
+{
+ private $image;
+ private $offset;
+ private $resource;
+ private $palette;
+
+ public function __construct(Image $image, PaletteInterface $palette, $resource)
+ {
+ if (!is_resource($resource)) {
+ throw new RuntimeException('Invalid Gd resource provided');
+ }
+
+ $this->image = $image;
+ $this->resource = $resource;
+ $this->offset = 0;
+ $this->palette = $palette;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function merge()
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function coalesce()
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function animate($format, $delay, $loops)
+ {
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function current()
+ {
+ return new Image($this->resource, $this->palette, new MetadataBag());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function key()
+ {
+ return $this->offset;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function next()
+ {
+ ++$this->offset;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function rewind()
+ {
+ $this->offset = 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function valid()
+ {
+ return $this->offset < 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetExists($offset)
+ {
+ return 0 === $offset;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetGet($offset)
+ {
+ if (0 === $offset) {
+ return new Image($this->resource, $this->palette, new MetadataBag());
+ }
+
+ throw new RuntimeException('GD only supports one layer at offset 0');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetSet($offset, $value)
+ {
+ throw new NotSupportedException('GD does not support layer set');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetUnset($offset)
+ {
+ throw new NotSupportedException('GD does not support layer unset');
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Drawer.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Drawer.php
new file mode 100644
index 0000000..de6cc90
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Drawer.php
@@ -0,0 +1,356 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Gmagick;
+
+use Imagine\Draw\DrawerInterface;
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Exception\NotSupportedException;
+use Imagine\Exception\RuntimeException;
+use Imagine\Image\AbstractFont;
+use Imagine\Image\BoxInterface;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\Point;
+use Imagine\Image\PointInterface;
+
+/**
+ * Drawer implementation using the Gmagick PHP extension
+ */
+final class Drawer implements DrawerInterface
+{
+ /**
+ * @var \Gmagick
+ */
+ private $gmagick;
+
+ /**
+ * @param \Gmagick $gmagick
+ */
+ public function __construct(\Gmagick $gmagick)
+ {
+ $this->gmagick = $gmagick;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1)
+ {
+ $x = $center->getX();
+ $y = $center->getY();
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+
+ try {
+ $pixel = $this->getColor($color);
+ $arc = new \GmagickDraw();
+
+ $arc->setstrokecolor($pixel);
+ $arc->setstrokewidth(max(1, (int) $thickness));
+ $arc->setfillcolor('transparent');
+ $arc->arc(
+ $x - $width / 2,
+ $y - $height / 2,
+ $x + $width / 2,
+ $y + $height / 2,
+ $start,
+ $end
+ );
+
+ $this->gmagick->drawImage($arc);
+
+ $pixel = null;
+
+ $arc = null;
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Draw arc operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1)
+ {
+ $x = $center->getX();
+ $y = $center->getY();
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+
+ try {
+ $pixel = $this->getColor($color);
+ $chord = new \GmagickDraw();
+
+ $chord->setstrokecolor($pixel);
+ $chord->setstrokewidth(max(1, (int) $thickness));
+
+ if ($fill) {
+ $chord->setfillcolor($pixel);
+ } else {
+ $x1 = round($x + $width / 2 * cos(deg2rad($start)));
+ $y1 = round($y + $height / 2 * sin(deg2rad($start)));
+ $x2 = round($x + $width / 2 * cos(deg2rad($end)));
+ $y2 = round($y + $height / 2 * sin(deg2rad($end)));
+
+ $this->line(new Point($x1, $y1), new Point($x2, $y2), $color);
+
+ $chord->setfillcolor('transparent');
+ }
+
+ $chord->arc($x - $width / 2, $y - $height / 2, $x + $width / 2, $y + $height / 2, $start, $end);
+
+ $this->gmagick->drawImage($chord);
+
+ $pixel = null;
+
+ $chord = null;
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Draw chord operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1)
+ {
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+
+ try {
+ $pixel = $this->getColor($color);
+ $ellipse = new \GmagickDraw();
+
+ $ellipse->setstrokecolor($pixel);
+ $ellipse->setstrokewidth(max(1, (int) $thickness));
+
+ if ($fill) {
+ $ellipse->setfillcolor($pixel);
+ } else {
+ $ellipse->setfillcolor('transparent');
+ }
+
+ $ellipse->ellipse(
+ $center->getX(),
+ $center->getY(),
+ $width / 2,
+ $height / 2,
+ 0, 360
+ );
+
+ $this->gmagick->drawImage($ellipse);
+
+ $pixel = null;
+
+ $ellipse = null;
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Draw ellipse operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function line(PointInterface $start, PointInterface $end, ColorInterface $color, $thickness = 1)
+ {
+ try {
+ $pixel = $this->getColor($color);
+ $line = new \GmagickDraw();
+
+ $line->setstrokecolor($pixel);
+ $line->setstrokewidth(max(1, (int) $thickness));
+ $line->setfillcolor($pixel);
+ $line->line(
+ $start->getX(),
+ $start->getY(),
+ $end->getX(),
+ $end->getY()
+ );
+
+ $this->gmagick->drawImage($line);
+
+ $pixel = null;
+
+ $line = null;
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Draw line operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1)
+ {
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+
+ $x1 = round($center->getX() + $width / 2 * cos(deg2rad($start)));
+ $y1 = round($center->getY() + $height / 2 * sin(deg2rad($start)));
+ $x2 = round($center->getX() + $width / 2 * cos(deg2rad($end)));
+ $y2 = round($center->getY() + $height / 2 * sin(deg2rad($end)));
+
+ if ($fill) {
+ $this->chord($center, $size, $start, $end, $color, true, $thickness);
+ $this->polygon(
+ array(
+ $center,
+ new Point($x1, $y1),
+ new Point($x2, $y2),
+ ),
+ $color,
+ true,
+ $thickness
+ );
+ } else {
+ $this->arc($center, $size, $start, $end, $color, $thickness);
+ $this->line($center, new Point($x1, $y1), $color, $thickness);
+ $this->line($center, new Point($x2, $y2), $color, $thickness);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function dot(PointInterface $position, ColorInterface $color)
+ {
+ $x = $position->getX();
+ $y = $position->getY();
+
+ try {
+ $pixel = $this->getColor($color);
+ $point = new \GmagickDraw();
+
+ $point->setfillcolor($pixel);
+ $point->point($x, $y);
+
+ $this->gmagick->drawimage($point);
+
+ $pixel = null;
+ $point = null;
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Draw point operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1)
+ {
+ if (count($coordinates) < 3) {
+ throw new InvalidArgumentException(sprintf('Polygon must consist of at least 3 coordinates, %d given', count($coordinates)));
+ }
+
+ $points = array_map(function (PointInterface $p) {
+ return array('x' => $p->getX(), 'y' => $p->getY());
+ }, $coordinates);
+
+ try {
+ $pixel = $this->getColor($color);
+ $polygon = new \GmagickDraw();
+
+ $polygon->setstrokecolor($pixel);
+ $polygon->setstrokewidth(max(1, (int) $thickness));
+
+ if ($fill) {
+ $polygon->setfillcolor($pixel);
+ } else {
+ $polygon->setfillcolor('transparent');
+ }
+
+ $polygon->polygon($points);
+
+ $this->gmagick->drawImage($polygon);
+
+ unset($pixel, $polygon);
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Draw polygon operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null)
+ {
+ try {
+ $pixel = $this->getColor($font->getColor());
+ $text = new \GmagickDraw();
+
+ $text->setfont($font->getFile());
+ /**
+ * @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027
+ *
+ * ensure font resolution is the same as GD's hard-coded 96
+ */
+ $text->setfontsize((int) ($font->getSize() * (96 / 72)));
+ $text->setfillcolor($pixel);
+
+ $info = $this->gmagick->queryfontmetrics($text, $string);
+ $rad = deg2rad($angle);
+ $cos = cos($rad);
+ $sin = sin($rad);
+
+ $x1 = round(0 * $cos - 0 * $sin);
+ $x2 = round($info['textWidth'] * $cos - $info['textHeight'] * $sin);
+ $y1 = round(0 * $sin + 0 * $cos);
+ $y2 = round($info['textWidth'] * $sin + $info['textHeight'] * $cos);
+
+ $xdiff = 0 - min($x1, $x2);
+ $ydiff = 0 - min($y1, $y2);
+
+ if ($width !== null) {
+ throw new NotSupportedException('Gmagick doesn\'t support queryfontmetrics function for multiline text', 1);
+ }
+
+ $this->gmagick->annotateimage($text, $position->getX() + $x1 + $xdiff, $position->getY() + $y2 + $ydiff, $angle, $string);
+
+ unset($pixel, $text);
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Draw text operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Gets specifically formatted color string from Color instance
+ *
+ * @param ColorInterface $color
+ *
+ * @return \GmagickPixel
+ *
+ * @throws InvalidArgumentException In case a non-opaque color is passed
+ */
+ private function getColor(ColorInterface $color)
+ {
+ if (!$color->isOpaque()) {
+ throw new InvalidArgumentException('Gmagick doesn\'t support transparency');
+ }
+
+ return new \GmagickPixel((string) $color);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Effects.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Effects.php
new file mode 100644
index 0000000..3f9c5cd
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Effects.php
@@ -0,0 +1,106 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Gmagick;
+
+use Imagine\Effects\EffectsInterface;
+use Imagine\Exception\RuntimeException;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Exception\NotSupportedException;
+
+/**
+ * Effects implementation using the Gmagick PHP extension
+ */
+class Effects implements EffectsInterface
+{
+ private $gmagick;
+
+ public function __construct(\Gmagick $gmagick)
+ {
+ $this->gmagick = $gmagick;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function gamma($correction)
+ {
+ try {
+ $this->gmagick->gammaimage($correction);
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Failed to apply gamma correction to the image');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function negative()
+ {
+ if (!method_exists($this->gmagick, 'negateimage')) {
+ throw new NotSupportedException('Gmagick version 1.1.0 RC3 is required for negative effect');
+ }
+
+ try {
+ $this->gmagick->negateimage(false, \Gmagick::CHANNEL_ALL);
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Failed to negate the image');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function grayscale()
+ {
+ try {
+ $this->gmagick->setImageType(2);
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Failed to grayscale the image');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function colorize(ColorInterface $color)
+ {
+ throw new NotSupportedException('Gmagick does not support colorize');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function sharpen()
+ {
+ throw new NotSupportedException('Gmagick does not support sharpen yet');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function blur($sigma = 1)
+ {
+ try {
+ $this->gmagick->blurImage(0, $sigma);
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Failed to blur the image', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Font.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Font.php
new file mode 100644
index 0000000..ad67c56
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Font.php
@@ -0,0 +1,63 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Gmagick;
+
+use Imagine\Image\AbstractFont;
+use Imagine\Image\Box;
+use Imagine\Image\Palette\Color\ColorInterface;
+
+/**
+ * Font implementation using the Gmagick PHP extension
+ */
+final class Font extends AbstractFont
+{
+ /**
+ * @var \Gmagick
+ */
+ private $gmagick;
+
+ /**
+ * @param \Gmagick $gmagick
+ * @param string $file
+ * @param integer $size
+ * @param ColorInterface $color
+ */
+ public function __construct(\Gmagick $gmagick, $file, $size, ColorInterface $color)
+ {
+ $this->gmagick = $gmagick;
+
+ parent::__construct($file, $size, $color);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function box($string, $angle = 0)
+ {
+ $text = new \GmagickDraw();
+
+ $text->setfont($this->file);
+ /**
+ * @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027
+ *
+ * ensure font resolution is the same as GD's hard-coded 96
+ */
+ $text->setfontsize((int) ($this->size * (96 / 72)));
+ $text->setfontstyle(\Gmagick::STYLE_OBLIQUE);
+
+ $info = $this->gmagick->queryfontmetrics($text, $string);
+
+ $box = new Box($info['textWidth'], $info['textHeight']);
+
+ return $box;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Image.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Image.php
new file mode 100644
index 0000000..61ef858
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Image.php
@@ -0,0 +1,786 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Gmagick;
+
+use Imagine\Exception\OutOfBoundsException;
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Exception\RuntimeException;
+use Imagine\Image\AbstractImage;
+use Imagine\Image\Metadata\MetadataBag;
+use Imagine\Image\Palette\PaletteInterface;
+use Imagine\Image\ImageInterface;
+use Imagine\Image\Box;
+use Imagine\Image\BoxInterface;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\Fill\FillInterface;
+use Imagine\Image\Point;
+use Imagine\Image\PointInterface;
+use Imagine\Image\ProfileInterface;
+
+/**
+ * Image implementation using the Gmagick PHP extension
+ */
+final class Image extends AbstractImage
+{
+ /**
+ * @var \Gmagick
+ */
+ private $gmagick;
+ /**
+ * @var Layers
+ */
+ private $layers;
+
+ /**
+ * @var PaletteInterface
+ */
+ private $palette;
+
+ private static $colorspaceMapping = array(
+ PaletteInterface::PALETTE_CMYK => \Gmagick::COLORSPACE_CMYK,
+ PaletteInterface::PALETTE_RGB => \Gmagick::COLORSPACE_RGB,
+ );
+
+ /**
+ * Constructs a new Image instance
+ *
+ * @param \Gmagick $gmagick
+ * @param PaletteInterface $palette
+ * @param MetadataBag $metadata
+ */
+ public function __construct(\Gmagick $gmagick, PaletteInterface $palette, MetadataBag $metadata)
+ {
+ $this->metadata = $metadata;
+ $this->gmagick = $gmagick;
+ $this->setColorspace($palette);
+ $this->layers = new Layers($this, $this->palette, $this->gmagick);
+ }
+
+ /**
+ * Destroys allocated gmagick resources
+ */
+ public function __destruct()
+ {
+ if ($this->gmagick instanceof \Gmagick) {
+ $this->gmagick->clear();
+ $this->gmagick->destroy();
+ }
+ }
+
+ /**
+ * Returns gmagick instance
+ *
+ * @return Gmagick
+ */
+ public function getGmagick()
+ {
+ return $this->gmagick;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function copy()
+ {
+ return new self(clone $this->gmagick, $this->palette, clone $this->metadata);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function crop(PointInterface $start, BoxInterface $size)
+ {
+ if (!$start->in($this->getSize())) {
+ throw new OutOfBoundsException('Crop coordinates must start at minimum 0, 0 position from top left corner, crop height and width must be positive integers and must not exceed the current image borders');
+ }
+
+ try {
+ $this->gmagick->cropimage($size->getWidth(), $size->getHeight(), $start->getX(), $start->getY());
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Crop operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function flipHorizontally()
+ {
+ try {
+ $this->gmagick->flopimage();
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Horizontal flip operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function flipVertically()
+ {
+ try {
+ $this->gmagick->flipimage();
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Vertical flip operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function strip()
+ {
+ try {
+ try {
+ $this->profile($this->palette->profile());
+ } catch (\Exception $e) {
+ // here we discard setting the profile as the previous incorporated profile
+ // is corrupted, let's now strip the image
+ }
+ $this->gmagick->stripimage();
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Strip operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function paste(ImageInterface $image, PointInterface $start)
+ {
+ if (!$image instanceof self) {
+ throw new InvalidArgumentException(sprintf('Gmagick\Image can only paste() Gmagick\Image instances, %s given', get_class($image)));
+ }
+
+ if (!$this->getSize()->contains($image->getSize(), $start)) {
+ throw new OutOfBoundsException('Cannot paste image of the given size at the specified position, as it moves outside of the current image\'s box');
+ }
+
+ try {
+ $this->gmagick->compositeimage($image->gmagick, \Gmagick::COMPOSITE_DEFAULT, $start->getX(), $start->getY());
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Paste operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED)
+ {
+ static $supportedFilters = array(
+ ImageInterface::FILTER_UNDEFINED => \Gmagick::FILTER_UNDEFINED,
+ ImageInterface::FILTER_BESSEL => \Gmagick::FILTER_BESSEL,
+ ImageInterface::FILTER_BLACKMAN => \Gmagick::FILTER_BLACKMAN,
+ ImageInterface::FILTER_BOX => \Gmagick::FILTER_BOX,
+ ImageInterface::FILTER_CATROM => \Gmagick::FILTER_CATROM,
+ ImageInterface::FILTER_CUBIC => \Gmagick::FILTER_CUBIC,
+ ImageInterface::FILTER_GAUSSIAN => \Gmagick::FILTER_GAUSSIAN,
+ ImageInterface::FILTER_HANNING => \Gmagick::FILTER_HANNING,
+ ImageInterface::FILTER_HAMMING => \Gmagick::FILTER_HAMMING,
+ ImageInterface::FILTER_HERMITE => \Gmagick::FILTER_HERMITE,
+ ImageInterface::FILTER_LANCZOS => \Gmagick::FILTER_LANCZOS,
+ ImageInterface::FILTER_MITCHELL => \Gmagick::FILTER_MITCHELL,
+ ImageInterface::FILTER_POINT => \Gmagick::FILTER_POINT,
+ ImageInterface::FILTER_QUADRATIC => \Gmagick::FILTER_QUADRATIC,
+ ImageInterface::FILTER_SINC => \Gmagick::FILTER_SINC,
+ ImageInterface::FILTER_TRIANGLE => \Gmagick::FILTER_TRIANGLE
+ );
+
+ if (!array_key_exists($filter, $supportedFilters)) {
+ throw new InvalidArgumentException('Unsupported filter type');
+ }
+
+ try {
+ $this->gmagick->resizeimage($size->getWidth(), $size->getHeight(), $supportedFilters[$filter], 1);
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Resize operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function rotate($angle, ColorInterface $background = null)
+ {
+ try {
+ $background = $background ?: $this->palette->color('fff');
+ $pixel = $this->getColor($background);
+
+ $this->gmagick->rotateimage($pixel, $angle);
+
+ unset($pixel);
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Rotate operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Internal
+ *
+ * Applies options before save or output
+ *
+ * @param \Gmagick $image
+ * @param array $options
+ * @param string $path
+ *
+ * @throws InvalidArgumentException
+ */
+ private function applyImageOptions(\Gmagick $image, array $options, $path)
+ {
+ if (isset($options['format'])) {
+ $format = $options['format'];
+ } elseif ('' !== $extension = pathinfo($path, \PATHINFO_EXTENSION)) {
+ $format = $extension;
+ } else {
+ $format = pathinfo($image->getImageFilename(), \PATHINFO_EXTENSION);
+ }
+
+ $format = strtolower($format);
+
+ $options = $this->updateSaveOptions($options);
+
+ if (isset($options['jpeg_quality']) && in_array($format, array('jpeg', 'jpg', 'pjpeg'))) {
+ $image->setCompressionQuality($options['jpeg_quality']);
+ }
+
+ if ((isset($options['png_compression_level']) || isset($options['png_compression_filter'])) && $format === 'png') {
+ // first digit: compression level (default: 7)
+ if (isset($options['png_compression_level'])) {
+ if ($options['png_compression_level'] < 0 || $options['png_compression_level'] > 9) {
+ throw new InvalidArgumentException('png_compression_level option should be an integer from 0 to 9');
+ }
+ $compression = $options['png_compression_level'] * 10;
+ } else {
+ $compression = 70;
+ }
+
+ // second digit: compression filter (default: 5)
+ if (isset($options['png_compression_filter'])) {
+ if ($options['png_compression_filter'] < 0 || $options['png_compression_filter'] > 9) {
+ throw new InvalidArgumentException('png_compression_filter option should be an integer from 0 to 9');
+ }
+ $compression += $options['png_compression_filter'];
+ } else {
+ $compression += 5;
+ }
+
+ $image->setCompressionQuality($compression);
+ }
+
+ if (isset($options['resolution-units']) && isset($options['resolution-x']) && isset($options['resolution-y'])) {
+ if ($options['resolution-units'] == ImageInterface::RESOLUTION_PIXELSPERCENTIMETER) {
+ $image->setimageunits(\Gmagick::RESOLUTION_PIXELSPERCENTIMETER);
+ } elseif ($options['resolution-units'] == ImageInterface::RESOLUTION_PIXELSPERINCH) {
+ $image->setimageunits(\Gmagick::RESOLUTION_PIXELSPERINCH);
+ } else {
+ throw new InvalidArgumentException('Unsupported image unit format');
+ }
+
+ $image->setimageresolution($options['resolution-x'], $options['resolution-y']);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function save($path = null, array $options = array())
+ {
+ $path = null === $path ? $this->gmagick->getImageFilename() : $path;
+
+ if ('' === trim($path)) {
+ throw new RuntimeException('You can omit save path only if image has been open from a file');
+ }
+
+ try {
+ $this->prepareOutput($options, $path);
+ $allFrames = !isset($options['animated']) || false === $options['animated'];
+ $this->gmagick->writeimage($path, $allFrames);
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Save operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function show($format, array $options = array())
+ {
+ header('Content-type: '.$this->getMimeType($format));
+ echo $this->get($format, $options);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($format, array $options = array())
+ {
+ try {
+ $options['format'] = $format;
+ $this->prepareOutput($options);
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Get operation failed', $e->getCode(), $e);
+ }
+
+ return $this->gmagick->getimagesblob();
+ }
+
+ /**
+ * @param array $options
+ * @param string $path
+ */
+ private function prepareOutput(array $options, $path = null)
+ {
+ if (isset($options['format'])) {
+ $this->gmagick->setimageformat($options['format']);
+ }
+
+ if (isset($options['animated']) && true === $options['animated']) {
+ $format = isset($options['format']) ? $options['format'] : 'gif';
+ $delay = isset($options['animated.delay']) ? $options['animated.delay'] : null;
+ $loops = isset($options['animated.loops']) ? $options['animated.loops'] : 0;
+
+ $options['flatten'] = false;
+
+ $this->layers->animate($format, $delay, $loops);
+ } else {
+ $this->layers->merge();
+ }
+ $this->applyImageOptions($this->gmagick, $options, $path);
+
+ // flatten only if image has multiple layers
+ if ((!isset($options['flatten']) || $options['flatten'] === true) && count($this->layers) > 1) {
+ $this->flatten();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ return $this->get('png');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function draw()
+ {
+ return new Drawer($this->gmagick);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function effects()
+ {
+ return new Effects($this->gmagick);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ try {
+ $i = $this->gmagick->getimageindex();
+ $this->gmagick->setimageindex(0); //rewind
+ $width = $this->gmagick->getimagewidth();
+ $height = $this->gmagick->getimageheight();
+ $this->gmagick->setimageindex($i);
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Get size operation failed', $e->getCode(), $e);
+ }
+
+ return new Box($width, $height);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function applyMask(ImageInterface $mask)
+ {
+ if (!$mask instanceof self) {
+ throw new InvalidArgumentException('Can only apply instances of Imagine\Gmagick\Image as masks');
+ }
+
+ $size = $this->getSize();
+ $maskSize = $mask->getSize();
+
+ if ($size != $maskSize) {
+ throw new InvalidArgumentException(sprintf('The given mask doesn\'t match current image\'s size, current mask\'s dimensions are %s, while image\'s dimensions are %s', $maskSize, $size));
+ }
+
+ try {
+ $mask = $mask->copy();
+ $this->gmagick->compositeimage($mask->gmagick, \Gmagick::COMPOSITE_DEFAULT, 0, 0);
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Apply mask operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function mask()
+ {
+ $mask = $this->copy();
+
+ try {
+ $mask->gmagick->modulateimage(100, 0, 100);
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Mask operation failed', $e->getCode(), $e);
+ }
+
+ return $mask;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function fill(FillInterface $fill)
+ {
+ try {
+ $draw = new \GmagickDraw();
+ $size = $this->getSize();
+
+ $w = $size->getWidth();
+ $h = $size->getHeight();
+
+ for ($x = 0; $x <= $w; $x++) {
+ for ($y = 0; $y <= $h; $y++) {
+ $pixel = $this->getColor($fill->getColor(new Point($x, $y)));
+
+ $draw->setfillcolor($pixel);
+ $draw->point($x, $y);
+
+ $pixel = null;
+ }
+ }
+
+ $this->gmagick->drawimage($draw);
+
+ $draw = null;
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Fill operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function histogram()
+ {
+ try {
+ $pixels = $this->gmagick->getimagehistogram();
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Error while fetching histogram', $e->getCode(), $e);
+ }
+
+ $image = $this;
+
+ return array_map(function (\GmagickPixel $pixel) use ($image) {
+ return $image->pixelToColor($pixel);
+ }, $pixels);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getColorAt(PointInterface $point)
+ {
+ if (!$point->in($this->getSize())) {
+ throw new InvalidArgumentException(sprintf('Error getting color at point [%s,%s]. The point must be inside the image of size [%s,%s]', $point->getX(), $point->getY(), $this->getSize()->getWidth(), $this->getSize()->getHeight()));
+ }
+
+ try {
+ $cropped = clone $this->gmagick;
+ $histogram = $cropped
+ ->cropImage(1, 1, $point->getX(), $point->getY())
+ ->getImageHistogram();
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Unable to get the pixel');
+ }
+
+ $pixel = array_shift($histogram);
+
+ unset($histogram, $cropped);
+
+ return $this->pixelToColor($pixel);
+ }
+
+ /**
+ * Returns a color given a pixel, depending the Palette context
+ *
+ * Note : this method is public for PHP 5.3 compatibility
+ *
+ * @param \GmagickPixel $pixel
+ *
+ * @return ColorInterface
+ *
+ * @throws InvalidArgumentException In case a unknown color is requested
+ */
+ public function pixelToColor(\GmagickPixel $pixel)
+ {
+ static $colorMapping = array(
+ ColorInterface::COLOR_RED => \Gmagick::COLOR_RED,
+ ColorInterface::COLOR_GREEN => \Gmagick::COLOR_GREEN,
+ ColorInterface::COLOR_BLUE => \Gmagick::COLOR_BLUE,
+ ColorInterface::COLOR_CYAN => \Gmagick::COLOR_CYAN,
+ ColorInterface::COLOR_MAGENTA => \Gmagick::COLOR_MAGENTA,
+ ColorInterface::COLOR_YELLOW => \Gmagick::COLOR_YELLOW,
+ ColorInterface::COLOR_KEYLINE => \Gmagick::COLOR_BLACK,
+ // There is no gray component in \Gmagick, let's use one of the RGB comp
+ ColorInterface::COLOR_GRAY => \Gmagick::COLOR_RED,
+ );
+
+ if ($this->palette->supportsAlpha()) {
+ try {
+ $alpha = (int) round($pixel->getcolorvalue(\Gmagick::COLOR_ALPHA) * 100);
+ } catch (\GmagickPixelException $e) {
+ $alpha = null;
+ }
+ } else {
+ $alpha = null;
+ }
+
+ $palette = $this->palette();
+
+ return $this->palette->color(array_map(function ($color) use ($palette, $pixel, $colorMapping) {
+ if (!isset($colorMapping[$color])) {
+ throw new InvalidArgumentException(sprintf('Color %s is not mapped in Gmagick', $color));
+ }
+ $multiplier = 255;
+ if ($palette->name() === PaletteInterface::PALETTE_CMYK) {
+ $multiplier = 100;
+ }
+
+ return $pixel->getcolorvalue($colorMapping[$color]) * $multiplier;
+ }, $this->palette->pixelDefinition()), $alpha);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function layers()
+ {
+ return $this->layers;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function interlace($scheme)
+ {
+ static $supportedInterlaceSchemes = array(
+ ImageInterface::INTERLACE_NONE => \Gmagick::INTERLACE_NO,
+ ImageInterface::INTERLACE_LINE => \Gmagick::INTERLACE_LINE,
+ ImageInterface::INTERLACE_PLANE => \Gmagick::INTERLACE_PLANE,
+ ImageInterface::INTERLACE_PARTITION => \Gmagick::INTERLACE_PARTITION,
+ );
+
+ if (!array_key_exists($scheme, $supportedInterlaceSchemes)) {
+ throw new InvalidArgumentException('Unsupported interlace type');
+ }
+
+ $this->gmagick->setInterlaceScheme($supportedInterlaceSchemes[$scheme]);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function usePalette(PaletteInterface $palette)
+ {
+ if (!isset(static::$colorspaceMapping[$palette->name()])) {
+ throw new InvalidArgumentException(sprintf('The palette %s is not supported by Gmagick driver',$palette->name()));
+ }
+
+ if ($this->palette->name() === $palette->name()) {
+ return $this;
+ }
+
+ try {
+ try {
+ $hasICCProfile = (Boolean) $this->gmagick->getimageprofile('ICM');
+ } catch (\GmagickException $e) {
+ $hasICCProfile = false;
+ }
+
+ if (!$hasICCProfile) {
+ $this->profile($this->palette->profile());
+ }
+
+ $this->profile($palette->profile());
+
+ $this->setColorspace($palette);
+ $this->palette = $palette;
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Failed to set colorspace', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function palette()
+ {
+ return $this->palette;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function profile(ProfileInterface $profile)
+ {
+ try {
+ $this->gmagick->profileimage('ICM', $profile->data());
+ } catch (\GmagickException $e) {
+ throw new RuntimeException(sprintf('Unable to add profile %s to image', $profile->name()), $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Internal
+ *
+ * Flatten the image.
+ */
+ private function flatten()
+ {
+ /**
+ * @see http://pecl.php.net/bugs/bug.php?id=22435
+ */
+ if (method_exists($this->gmagick, 'flattenImages')) {
+ try {
+ $this->gmagick = $this->gmagick->flattenImages();
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Flatten operation failed', $e->getCode(), $e);
+ }
+ }
+ }
+
+ /**
+ * Gets specifically formatted color string from Color instance
+ *
+ * @param ColorInterface $color
+ *
+ * @return \GmagickPixel
+ *
+ * @throws InvalidArgumentException
+ */
+ private function getColor(ColorInterface $color)
+ {
+ if (!$color->isOpaque()) {
+ throw new InvalidArgumentException('Gmagick doesn\'t support transparency');
+ }
+
+ return new \GmagickPixel((string) $color);
+ }
+
+ /**
+ * Internal
+ *
+ * Get the mime type based on format.
+ *
+ * @param string $format
+ *
+ * @return string mime-type
+ *
+ * @throws InvalidArgumentException
+ */
+ private function getMimeType($format)
+ {
+ static $mimeTypes = array(
+ 'jpeg' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'gif' => 'image/gif',
+ 'png' => 'image/png',
+ 'wbmp' => 'image/vnd.wap.wbmp',
+ 'xbm' => 'image/xbm',
+ );
+
+ if (!isset($mimeTypes[$format])) {
+ throw new InvalidArgumentException(sprintf('Unsupported format given. Only %s are supported, %s given', implode(", ", array_keys($mimeTypes)), $format));
+ }
+
+ return $mimeTypes[$format];
+ }
+
+ /**
+ * Sets colorspace and image type, assigns the palette.
+ *
+ * @param PaletteInterface $palette
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setColorspace(PaletteInterface $palette)
+ {
+ if (!isset(static::$colorspaceMapping[$palette->name()])) {
+ throw new InvalidArgumentException(sprintf('The palette %s is not supported by Gmagick driver', $palette->name()));
+ }
+
+ $this->gmagick->setimagecolorspace(static::$colorspaceMapping[$palette->name()]);
+ $this->palette = $palette;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Imagine.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Imagine.php
new file mode 100644
index 0000000..ce4d4ed
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Imagine.php
@@ -0,0 +1,167 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Gmagick;
+
+use Imagine\Image\AbstractImagine;
+use Imagine\Exception\NotSupportedException;
+use Imagine\Image\BoxInterface;
+use Imagine\Image\Metadata\MetadataBag;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\Palette\Grayscale;
+use Imagine\Image\Palette\CMYK;
+use Imagine\Image\Palette\RGB;
+use Imagine\Image\Palette\Color\CMYK as CMYKColor;
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Exception\RuntimeException;
+
+/**
+ * Imagine implementation using the Gmagick PHP extension
+ */
+class Imagine extends AbstractImagine
+{
+ /**
+ * @throws RuntimeException
+ */
+ public function __construct()
+ {
+ if (!class_exists('Gmagick')) {
+ throw new RuntimeException('Gmagick not installed');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function open($path)
+ {
+ $path = $this->checkPath($path);
+
+ try {
+ $gmagick = new \Gmagick($path);
+ $image = new Image($gmagick, $this->createPalette($gmagick), $this->getMetadataReader()->readFile($path));
+ } catch (\GmagickException $e) {
+ throw new RuntimeException(sprintf('Unable to open image %s', $path), $e->getCode(), $e);
+ }
+
+ return $image;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function create(BoxInterface $size, ColorInterface $color = null)
+ {
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+
+ $palette = null !== $color ? $color->getPalette() : new RGB();
+ $color = null !== $color ? $color : $palette->color('fff');
+
+ try {
+ $gmagick = new \Gmagick();
+ // Gmagick does not support creation of CMYK GmagickPixel
+ // see https://bugs.php.net/bug.php?id=64466
+ if ($color instanceof CMYKColor) {
+ $switchPalette = $palette;
+ $palette = new RGB();
+ $pixel = new \GmagickPixel($palette->color((string) $color));
+ } else {
+ $switchPalette = null;
+ $pixel = new \GmagickPixel((string) $color);
+ }
+
+ if ($color->getPalette()->supportsAlpha() && $color->getAlpha() < 100) {
+ throw new NotSupportedException('alpha transparency is not supported');
+ }
+
+ $gmagick->newimage($width, $height, $pixel->getcolor(false));
+ $gmagick->setimagecolorspace(\Gmagick::COLORSPACE_TRANSPARENT);
+ $gmagick->setimagebackgroundcolor($pixel);
+
+ $image = new Image($gmagick, $palette, new MetadataBag());
+
+ if ($switchPalette) {
+ $image->usePalette($switchPalette);
+ }
+
+ return $image;
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Could not create empty image', $e->getCode(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function load($string)
+ {
+ return $this->doLoad($string, $this->getMetadataReader()->readData($string));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read($resource)
+ {
+ if (!is_resource($resource)) {
+ throw new InvalidArgumentException('Variable does not contain a stream resource');
+ }
+
+ $content = stream_get_contents($resource);
+
+ if (false === $content) {
+ throw new InvalidArgumentException('Couldn\'t read given resource');
+ }
+
+ return $this->doLoad($content, $this->getMetadataReader()->readStream($resource));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function font($file, $size, ColorInterface $color)
+ {
+ $gmagick = new \Gmagick();
+ $gmagick->newimage(1, 1, 'transparent');
+
+ return new Font($gmagick, $file, $size, $color);
+ }
+
+ private function createPalette(\Gmagick $gmagick)
+ {
+ switch ($gmagick->getimagecolorspace()) {
+ case \Gmagick::COLORSPACE_SRGB:
+ case \Gmagick::COLORSPACE_RGB:
+ return new RGB();
+ case \Gmagick::COLORSPACE_CMYK:
+ return new CMYK();
+ case \Gmagick::COLORSPACE_GRAY:
+ return new Grayscale();
+ default:
+ throw new NotSupportedException('Only RGB and CMYK colorspace are currently supported');
+ }
+ }
+
+ private function doLoad($content, MetadataBag $metadata)
+ {
+ try {
+ $gmagick = new \Gmagick();
+ $gmagick->readimageblob($content);
+ } catch (\GmagickException $e) {
+ throw new RuntimeException(
+ 'Could not load image from string', $e->getCode(), $e
+ );
+ }
+
+ return new Image($gmagick, $this->createPalette($gmagick), $metadata);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Layers.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Layers.php
new file mode 100644
index 0000000..d708812
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Gmagick/Layers.php
@@ -0,0 +1,272 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Gmagick;
+
+use Imagine\Image\AbstractLayers;
+use Imagine\Exception\RuntimeException;
+use Imagine\Exception\NotSupportedException;
+use Imagine\Exception\OutOfBoundsException;
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Image\Metadata\MetadataBag;
+use Imagine\Image\Palette\PaletteInterface;
+
+class Layers extends AbstractLayers
+{
+ /**
+ * @var Image
+ */
+ private $image;
+
+ /**
+ * @var \Gmagick
+ */
+ private $resource;
+
+ /**
+ * @var integer
+ */
+ private $offset = 0;
+
+ /**
+ * @var array
+ */
+ private $layers = array();
+
+ /**
+ * @var PaletteInterface
+ */
+ private $palette;
+
+ public function __construct(Image $image, PaletteInterface $palette, \Gmagick $resource)
+ {
+ $this->image = $image;
+ $this->resource = $resource;
+ $this->palette = $palette;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function merge()
+ {
+ foreach ($this->layers as $offset => $image) {
+ try {
+ $this->resource->setimageindex($offset);
+ $this->resource->setimage($image->getGmagick());
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Failed to substitute layer', $e->getCode(), $e);
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function coalesce()
+ {
+ throw new NotSupportedException('Gmagick does not support coalescing');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function animate($format, $delay, $loops)
+ {
+ if ('gif' !== strtolower($format)) {
+ throw new NotSupportedException('Animated picture is currently only supported on gif');
+ }
+
+ if (!is_int($loops) || $loops < 0) {
+ throw new InvalidArgumentException('Loops must be a positive integer.');
+ }
+
+ if (null !== $delay && (!is_int($delay) || $delay < 0)) {
+ throw new InvalidArgumentException('Delay must be either null or a positive integer.');
+ }
+
+ try {
+ foreach ($this as $offset => $layer) {
+ $this->resource->setimageindex($offset);
+ $this->resource->setimageformat($format);
+
+ if (null !== $delay) {
+ $this->resource->setimagedelay($delay / 10);
+ }
+
+ $this->resource->setimageiterations($loops);
+ }
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Failed to animate layers', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function current()
+ {
+ return $this->extractAt($this->offset);
+ }
+
+ /**
+ * Tries to extract layer at given offset
+ *
+ * @param integer $offset
+ * @return Image
+ * @throws RuntimeException
+ */
+ private function extractAt($offset)
+ {
+ if (!isset($this->layers[$offset])) {
+ try {
+ $this->resource->setimageindex($offset);
+ $this->layers[$offset] = new Image($this->resource->getimage(), $this->palette, new MetadataBag());
+ } catch (\GmagickException $e) {
+ throw new RuntimeException(sprintf('Failed to extract layer %d', $offset), $e->getCode(), $e);
+ }
+ }
+
+ return $this->layers[$offset];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function key()
+ {
+ return $this->offset;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function next()
+ {
+ ++$this->offset;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function rewind()
+ {
+ $this->offset = 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function valid()
+ {
+ return $this->offset < count($this);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function count()
+ {
+ try {
+ return $this->resource->getnumberimages();
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Failed to count the number of layers', $e->getCode(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetExists($offset)
+ {
+ return is_int($offset) && $offset >= 0 && $offset < count($this);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetGet($offset)
+ {
+ return $this->extractAt($offset);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetSet($offset, $image)
+ {
+ if (!$image instanceof Image) {
+ throw new InvalidArgumentException('Only a Gmagick Image can be used as layer');
+ }
+
+ if (null === $offset) {
+ $offset = count($this) - 1;
+ } else {
+ if (!is_int($offset)) {
+ throw new InvalidArgumentException('Invalid offset for layer, it must be an integer');
+ }
+
+ if (count($this) < $offset || 0 > $offset) {
+ throw new OutOfBoundsException(sprintf('Invalid offset for layer, it must be a value between 0 and %d, %d given', count($this), $offset));
+ }
+
+ if (isset($this[$offset])) {
+ unset($this[$offset]);
+ $offset = $offset - 1;
+ }
+ }
+
+ $frame = $image->getGmagick();
+
+ try {
+ if (count($this) > 0) {
+ $this->resource->setimageindex($offset);
+ $this->resource->nextimage();
+ }
+ $this->resource->addimage($frame);
+
+ /**
+ * ugly hack to bypass issue https://bugs.php.net/bug.php?id=64623
+ */
+ if (count($this) == 2) {
+ $this->resource->setimageindex($offset+1);
+ $this->resource->nextimage();
+ $this->resource->addimage($frame);
+ unset($this[0]);
+ }
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Unable to set the layer', $e->getCode(), $e);
+ }
+
+ $this->layers = array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetUnset($offset)
+ {
+ try {
+ $this->extractAt($offset);
+ } catch (RuntimeException $e) {
+ return;
+ }
+
+ try {
+ $this->resource->setimageindex($offset);
+ $this->resource->removeimage();
+ } catch (\GmagickException $e) {
+ throw new RuntimeException('Unable to remove layer', $e->getCode(), $e);
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/AbstractFont.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/AbstractFont.php
new file mode 100644
index 0000000..59e9a45
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/AbstractFont.php
@@ -0,0 +1,75 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image;
+
+use Imagine\Image\Palette\Color\ColorInterface;
+
+/**
+ * Abstract font base class
+ */
+abstract class AbstractFont implements FontInterface
+{
+ /**
+ * @var string
+ */
+ protected $file;
+
+ /**
+ * @var integer
+ */
+ protected $size;
+
+ /**
+ * @var ColorInterface
+ */
+ protected $color;
+
+ /**
+ * Constructs a font with specified $file, $size and $color
+ *
+ * The font size is to be specified in points (e.g. 10pt means 10)
+ *
+ * @param string $file
+ * @param integer $size
+ * @param ColorInterface $color
+ */
+ public function __construct($file, $size, ColorInterface $color)
+ {
+ $this->file = $file;
+ $this->size = $size;
+ $this->color = $color;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ final public function getFile()
+ {
+ return $this->file;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ final public function getSize()
+ {
+ return $this->size;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ final public function getColor()
+ {
+ return $this->color;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/AbstractImage.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/AbstractImage.php
new file mode 100644
index 0000000..5c85769
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/AbstractImage.php
@@ -0,0 +1,120 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image;
+
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Image\Metadata\MetadataBag;
+
+abstract class AbstractImage implements ImageInterface
+{
+ /**
+ * @var MetadataBag
+ */
+ protected $metadata;
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function thumbnail(BoxInterface $size, $mode = ImageInterface::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED)
+ {
+ if ($mode !== ImageInterface::THUMBNAIL_INSET &&
+ $mode !== ImageInterface::THUMBNAIL_OUTBOUND) {
+ throw new InvalidArgumentException('Invalid mode specified');
+ }
+
+ $imageSize = $this->getSize();
+ $ratios = array(
+ $size->getWidth() / $imageSize->getWidth(),
+ $size->getHeight() / $imageSize->getHeight()
+ );
+
+ $thumbnail = $this->copy();
+
+ $thumbnail->usePalette($this->palette());
+ $thumbnail->strip();
+ // if target width is larger than image width
+ // AND target height is longer than image height
+ if ($size->contains($imageSize)) {
+ return $thumbnail;
+ }
+
+ if ($mode === ImageInterface::THUMBNAIL_INSET) {
+ $ratio = min($ratios);
+ } else {
+ $ratio = max($ratios);
+ }
+
+ if ($mode === ImageInterface::THUMBNAIL_OUTBOUND) {
+ if (!$imageSize->contains($size)) {
+ $size = new Box(
+ min($imageSize->getWidth(), $size->getWidth()),
+ min($imageSize->getHeight(), $size->getHeight())
+ );
+ } else {
+ $imageSize = $thumbnail->getSize()->scale($ratio);
+ $thumbnail->resize($imageSize, $filter);
+ }
+ $thumbnail->crop(new Point(
+ max(0, round(($imageSize->getWidth() - $size->getWidth()) / 2)),
+ max(0, round(($imageSize->getHeight() - $size->getHeight()) / 2))
+ ), $size);
+ } else {
+ if (!$imageSize->contains($size)) {
+ $imageSize = $imageSize->scale($ratio);
+ $thumbnail->resize($imageSize, $filter);
+ } else {
+ $imageSize = $thumbnail->getSize()->scale($ratio);
+ $thumbnail->resize($imageSize, $filter);
+ }
+ }
+
+ return $thumbnail;
+ }
+
+ /**
+ * Updates a given array of save options for backward compatibility with legacy names
+ *
+ * @param array $options
+ *
+ * @return array
+ */
+ protected function updateSaveOptions(array $options)
+ {
+ // Preserve BC until version 1.0
+ if (isset($options['quality']) && !isset($options['jpeg_quality'])) {
+ $options['jpeg_quality'] = $options['quality'];
+ }
+
+ return $options;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function metadata()
+ {
+ return $this->metadata;
+ }
+
+ /**
+ * Assures the metadata instance will be cloned, too
+ */
+ public function __clone()
+ {
+ if ($this->metadata !== null) {
+ $this->metadata = clone $this->metadata;
+ }
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/AbstractImagine.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/AbstractImagine.php
new file mode 100644
index 0000000..fcb1a3d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/AbstractImagine.php
@@ -0,0 +1,79 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image;
+
+use Imagine\Image\Metadata\DefaultMetadataReader;
+use Imagine\Image\Metadata\ExifMetadataReader;
+use Imagine\Image\Metadata\MetadataReaderInterface;
+use Imagine\Exception\InvalidArgumentException;
+
+abstract class AbstractImagine implements ImagineInterface
+{
+ /** @var MetadataReaderInterface */
+ private $metadataReader;
+
+ /**
+ * @param MetadataReaderInterface $metadataReader
+ *
+ * @return ImagineInterface
+ */
+ public function setMetadataReader(MetadataReaderInterface $metadataReader)
+ {
+ $this->metadataReader = $metadataReader;
+
+ return $this;
+ }
+
+ /**
+ * @return MetadataReaderInterface
+ */
+ public function getMetadataReader()
+ {
+ if (null === $this->metadataReader) {
+ if (ExifMetadataReader::isSupported()) {
+ $this->metadataReader = new ExifMetadataReader();
+ } else {
+ $this->metadataReader = new DefaultMetadataReader();
+ }
+ }
+
+ return $this->metadataReader;
+ }
+
+ /**
+ * Checks a path that could be used with ImagineInterface::open and returns
+ * a proper string.
+ *
+ * @param string|object $path
+ *
+ * @return string
+ *
+ * @throws InvalidArgumentException In case the given path is invalid.
+ */
+ protected function checkPath($path)
+ {
+ // provide compatibility with objects such as \SplFileInfo
+ if (is_object($path) && method_exists($path, '__toString')) {
+ $path = (string) $path;
+ }
+
+ $handle = @fopen($path, 'r');
+
+ if (false === $handle) {
+ throw new InvalidArgumentException(sprintf('File %s does not exist.', $path));
+ }
+
+ fclose($handle);
+
+ return $path;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/AbstractLayers.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/AbstractLayers.php
new file mode 100644
index 0000000..486a722
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/AbstractLayers.php
@@ -0,0 +1,61 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image;
+
+abstract class AbstractLayers implements LayersInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function add(ImageInterface $image)
+ {
+ $this[] = $image;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set($offset, ImageInterface $image)
+ {
+ $this[$offset] = $image;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function remove($offset)
+ {
+ unset($this[$offset]);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($offset)
+ {
+ return $this[$offset];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function has($offset)
+ {
+ return isset($this[$offset]);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Box.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Box.php
new file mode 100644
index 0000000..37b8513
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Box.php
@@ -0,0 +1,122 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image;
+
+use Imagine\Exception\InvalidArgumentException;
+
+/**
+ * A box implementation
+ */
+final class Box implements BoxInterface
+{
+ /**
+ * @var integer
+ */
+ private $width;
+
+ /**
+ * @var integer
+ */
+ private $height;
+
+ /**
+ * Constructs the Size with given width and height
+ *
+ * @param integer $width
+ * @param integer $height
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct($width, $height)
+ {
+ if ($height < 1 || $width < 1) {
+ throw new InvalidArgumentException(sprintf('Length of either side cannot be 0 or negative, current size is %sx%s', $width, $height));
+ }
+
+ $this->width = (int) $width;
+ $this->height = (int) $height;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getWidth()
+ {
+ return $this->width;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getHeight()
+ {
+ return $this->height;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function scale($ratio)
+ {
+ return new Box(round($ratio * $this->width), round($ratio * $this->height));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function increase($size)
+ {
+ return new Box((int) $size + $this->width, (int) $size + $this->height);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function contains(BoxInterface $box, PointInterface $start = null)
+ {
+ $start = $start ? $start : new Point(0, 0);
+
+ return $start->in($this) && $this->width >= $box->getWidth() + $start->getX() && $this->height >= $box->getHeight() + $start->getY();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function square()
+ {
+ return $this->width * $this->height;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ return sprintf('%dx%d px', $this->width, $this->height);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function widen($width)
+ {
+ return $this->scale($width / $this->width);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function heighten($height)
+ {
+ return $this->scale($height / $this->height);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/BoxInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/BoxInterface.php
new file mode 100644
index 0000000..4a086c3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/BoxInterface.php
@@ -0,0 +1,94 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image;
+
+/**
+ * Interface for a box
+ */
+interface BoxInterface
+{
+ /**
+ * Gets current image height
+ *
+ * @return integer
+ */
+ public function getHeight();
+
+ /**
+ * Gets current image width
+ *
+ * @return integer
+ */
+ public function getWidth();
+
+ /**
+ * Creates new BoxInterface instance with ratios applied to both sides
+ *
+ * @param float $ratio
+ *
+ * @return BoxInterface
+ */
+ public function scale($ratio);
+
+ /**
+ * Creates new BoxInterface, adding given size to both sides
+ *
+ * @param integer $size
+ *
+ * @return BoxInterface
+ */
+ public function increase($size);
+
+ /**
+ * Checks whether current box can fit given box at a given start position,
+ * start position defaults to top left corner xy(0,0)
+ *
+ * @param BoxInterface $box
+ * @param PointInterface $start
+ *
+ * @return Boolean
+ */
+ public function contains(BoxInterface $box, PointInterface $start = null);
+
+ /**
+ * Gets current box square, useful for getting total number of pixels in a
+ * given box
+ *
+ * @return integer
+ */
+ public function square();
+
+ /**
+ * Returns a string representation of the current box
+ *
+ * @return string
+ */
+ public function __toString();
+
+ /**
+ * Resizes box to given width, constraining proportions and returns the new box
+ *
+ * @param integer $width
+ *
+ * @return BoxInterface
+ */
+ public function widen($width);
+
+ /**
+ * Resizes box to given height, constraining proportions and returns the new box
+ *
+ * @param integer $height
+ *
+ * @return BoxInterface
+ */
+ public function heighten($height);
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Fill/FillInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Fill/FillInterface.php
new file mode 100644
index 0000000..c8d69e5
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Fill/FillInterface.php
@@ -0,0 +1,30 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Fill;
+
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\PointInterface;
+
+/**
+ * Interface for the fill
+ */
+interface FillInterface
+{
+ /**
+ * Gets color of the fill for the given position
+ *
+ * @param PointInterface $position
+ *
+ * @return ColorInterface
+ */
+ public function getColor(PointInterface $position);
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Fill/Gradient/Horizontal.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Fill/Gradient/Horizontal.php
new file mode 100644
index 0000000..4a42306
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Fill/Gradient/Horizontal.php
@@ -0,0 +1,28 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Fill\Gradient;
+
+use Imagine\Image\PointInterface;
+
+/**
+ * Horizontal gradient fill
+ */
+final class Horizontal extends Linear
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getDistance(PointInterface $position)
+ {
+ return $position->getX();
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Fill/Gradient/Linear.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Fill/Gradient/Linear.php
new file mode 100644
index 0000000..9bf2cf6
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Fill/Gradient/Linear.php
@@ -0,0 +1,95 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Fill\Gradient;
+
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\Fill\FillInterface;
+use Imagine\Image\PointInterface;
+
+/**
+ * Linear gradient fill
+ */
+abstract class Linear implements FillInterface
+{
+ /**
+ * @var integer
+ */
+ private $length;
+
+ /**
+ * @var ColorInterface
+ */
+ private $start;
+
+ /**
+ * @var ColorInterface
+ */
+ private $end;
+
+ /**
+ * Constructs a linear gradient with overall gradient length, and start and
+ * end shades, which default to 0 and 255 accordingly
+ *
+ * @param integer $length
+ * @param ColorInterface $start
+ * @param ColorInterface $end
+ */
+ final public function __construct($length, ColorInterface $start, ColorInterface $end)
+ {
+ $this->length = $length;
+ $this->start = $start;
+ $this->end = $end;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ final public function getColor(PointInterface $position)
+ {
+ $l = $this->getDistance($position);
+
+ if ($l >= $this->length) {
+ return $this->end;
+ }
+
+ if ($l < 0) {
+ return $this->start;
+ }
+
+ return $this->start->getPalette()->blend($this->start, $this->end, $l / $this->length);
+ }
+
+ /**
+ * @return ColorInterface
+ */
+ final public function getStart()
+ {
+ return $this->start;
+ }
+
+ /**
+ * @return ColorInterface
+ */
+ final public function getEnd()
+ {
+ return $this->end;
+ }
+
+ /**
+ * Get the distance of the position relative to the beginning of the gradient
+ *
+ * @param PointInterface $position
+ *
+ * @return integer
+ */
+ abstract protected function getDistance(PointInterface $position);
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Fill/Gradient/Vertical.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Fill/Gradient/Vertical.php
new file mode 100644
index 0000000..9a26b77
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Fill/Gradient/Vertical.php
@@ -0,0 +1,28 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Fill\Gradient;
+
+use Imagine\Image\PointInterface;
+
+/**
+ * Vertical gradient fill
+ */
+final class Vertical extends Linear
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function getDistance(PointInterface $position)
+ {
+ return $position->getY();
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/FontInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/FontInterface.php
new file mode 100644
index 0000000..59d4a26
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/FontInterface.php
@@ -0,0 +1,51 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image;
+
+use Imagine\Image\Palette\Color\ColorInterface;
+
+/**
+ * The font interface
+ */
+interface FontInterface
+{
+ /**
+ * Gets the fontfile for current font
+ *
+ * @return string
+ */
+ public function getFile();
+
+ /**
+ * Gets font's integer point size
+ *
+ * @return integer
+ */
+ public function getSize();
+
+ /**
+ * Gets font's color
+ *
+ * @return ColorInterface
+ */
+ public function getColor();
+
+ /**
+ * Gets BoxInterface of font size on the image based on string and angle
+ *
+ * @param string $string
+ * @param integer $angle
+ *
+ * @return BoxInterface
+ */
+ public function box($string, $angle = 0);
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Histogram/Bucket.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Histogram/Bucket.php
new file mode 100644
index 0000000..34dad5e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Histogram/Bucket.php
@@ -0,0 +1,56 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Histogram;
+
+/**
+ * Bucket histogram
+ */
+final class Bucket implements \Countable
+{
+ /**
+ * @var Range
+ */
+ private $range;
+
+ /**
+ * @var integer
+ */
+ private $count;
+
+ /**
+ * @param Range $range
+ * @param integer $count
+ */
+ public function __construct(Range $range, $count = 0)
+ {
+ $this->range = $range;
+ $this->count = $count;
+ }
+
+ /**
+ * @param integer $value
+ */
+ public function add($value)
+ {
+ if ($this->range->contains($value)) {
+ $this->count++;
+ }
+ }
+
+ /**
+ * @return integer The number of elements in the bucket.
+ */
+ public function count()
+ {
+ return $this->count;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Histogram/Range.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Histogram/Range.php
new file mode 100644
index 0000000..9dc9f99
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Histogram/Range.php
@@ -0,0 +1,56 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Histogram;
+
+use Imagine\Exception\OutOfBoundsException;
+
+/**
+ * Range histogram
+ */
+final class Range
+{
+ /**
+ * @var integer
+ */
+ private $start;
+
+ /**
+ * @var integer
+ */
+ private $end;
+
+ /**
+ * @param integer $start
+ * @param integer $end
+ *
+ * @throws OutOfBoundsException
+ */
+ public function __construct($start, $end)
+ {
+ if ($end <= $start) {
+ throw new OutOfBoundsException(sprintf('Range end cannot be bigger than start, %d %d given accordingly', $this->start, $this->end));
+ }
+
+ $this->start = $start;
+ $this->end = $end;
+ }
+
+ /**
+ * @param integer $value
+ *
+ * @return Boolean
+ */
+ public function contains($value)
+ {
+ return $value >= $this->start && $value < $this->end;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/ImageInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/ImageInterface.php
new file mode 100644
index 0000000..6cf1dd8
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/ImageInterface.php
@@ -0,0 +1,173 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image;
+
+use Imagine\Draw\DrawerInterface;
+use Imagine\Effects\EffectsInterface;
+use Imagine\Image\Palette\PaletteInterface;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Exception\RuntimeException;
+use Imagine\Exception\OutOfBoundsException;
+
+/**
+ * The image interface
+ */
+interface ImageInterface extends ManipulatorInterface
+{
+ const RESOLUTION_PIXELSPERINCH = 'ppi';
+ const RESOLUTION_PIXELSPERCENTIMETER = 'ppc';
+
+ const INTERLACE_NONE = 'none';
+ const INTERLACE_LINE = 'line';
+ const INTERLACE_PLANE = 'plane';
+ const INTERLACE_PARTITION = 'partition';
+
+ const FILTER_UNDEFINED = 'undefined';
+ const FILTER_POINT = 'point';
+ const FILTER_BOX = 'box';
+ const FILTER_TRIANGLE = 'triangle';
+ const FILTER_HERMITE = 'hermite';
+ const FILTER_HANNING = 'hanning';
+ const FILTER_HAMMING = 'hamming';
+ const FILTER_BLACKMAN = 'blackman';
+ const FILTER_GAUSSIAN = 'gaussian';
+ const FILTER_QUADRATIC = 'quadratic';
+ const FILTER_CUBIC = 'cubic';
+ const FILTER_CATROM = 'catrom';
+ const FILTER_MITCHELL = 'mitchell';
+ const FILTER_LANCZOS = 'lanczos';
+ const FILTER_BESSEL = 'bessel';
+ const FILTER_SINC = 'sinc';
+
+ /**
+ * Returns the image content as a binary string
+ *
+ * @param string $format
+ * @param array $options
+ *
+ * @throws RuntimeException
+ *
+ * @return string binary
+ */
+ public function get($format, array $options = array());
+
+ /**
+ * Returns the image content as a PNG binary string
+ *
+ * @throws RuntimeException
+ *
+ * @return string binary
+ */
+ public function __toString();
+
+ /**
+ * Instantiates and returns a DrawerInterface instance for image drawing
+ *
+ * @return DrawerInterface
+ */
+ public function draw();
+
+ /**
+ * @return EffectsInterface
+ */
+ public function effects();
+
+ /**
+ * Returns current image size
+ *
+ * @return BoxInterface
+ */
+ public function getSize();
+
+ /**
+ * Transforms creates a grayscale mask from current image, returns a new
+ * image, while keeping the existing image unmodified
+ *
+ * @return ImageInterface
+ */
+ public function mask();
+
+ /**
+ * Returns array of image colors as Imagine\Image\Palette\Color\ColorInterface instances
+ *
+ * @return array
+ */
+ public function histogram();
+
+ /**
+ * Returns color at specified positions of current image
+ *
+ * @param PointInterface $point
+ *
+ * @throws RuntimeException
+ *
+ * @return ColorInterface
+ */
+ public function getColorAt(PointInterface $point);
+
+ /**
+ * Returns the image layers when applicable.
+ *
+ * @throws RuntimeException In case the layer can not be returned
+ * @throws OutOfBoundsException In case the index is not a valid value
+ *
+ * @return LayersInterface
+ */
+ public function layers();
+
+ /**
+ * Enables or disables interlacing
+ *
+ * @param string $scheme
+ *
+ * @throws InvalidArgumentException When an unsupported Interface type is supplied
+ *
+ * @return ImageInterface
+ */
+ public function interlace($scheme);
+
+ /**
+ * Return the current color palette
+ *
+ * @return PaletteInterface
+ */
+ public function palette();
+
+ /**
+ * Set a palette for the image. Useful to change colorspace.
+ *
+ * @param PaletteInterface $palette
+ *
+ * @return ImageInterface
+ *
+ * @throws RuntimeException
+ */
+ public function usePalette(PaletteInterface $palette);
+
+ /**
+ * Applies a color profile on the Image
+ *
+ * @param ProfileInterface $profile
+ *
+ * @return ImageInterface
+ *
+ * @throws RuntimeException
+ */
+ public function profile(ProfileInterface $profile);
+
+ /**
+ * Returns the Image's meta data
+ *
+ * @return Metadata\MetadataInterface
+ */
+ public function metadata();
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/ImagineInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/ImagineInterface.php
new file mode 100644
index 0000000..b5c942c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/ImagineInterface.php
@@ -0,0 +1,83 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image;
+
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Exception\RuntimeException;
+
+/**
+ * The imagine interface
+ */
+interface ImagineInterface
+{
+ const VERSION = '0.7-dev';
+
+ /**
+ * Creates a new empty image with an optional background color
+ *
+ * @param BoxInterface $size
+ * @param ColorInterface $color
+ *
+ * @throws InvalidArgumentException
+ * @throws RuntimeException
+ *
+ * @return ImageInterface
+ */
+ public function create(BoxInterface $size, ColorInterface $color = null);
+
+ /**
+ * Opens an existing image from $path
+ *
+ * @param string $path
+ *
+ * @throws RuntimeException
+ *
+ * @return ImageInterface
+ */
+ public function open($path);
+
+ /**
+ * Loads an image from a binary $string
+ *
+ * @param string $string
+ *
+ * @throws RuntimeException
+ *
+ * @return ImageInterface
+ */
+ public function load($string);
+
+ /**
+ * Loads an image from a resource $resource
+ *
+ * @param resource $resource
+ *
+ * @throws RuntimeException
+ *
+ * @return ImageInterface
+ */
+ public function read($resource);
+
+ /**
+ * Constructs a font with specified $file, $size and $color
+ *
+ * The font size is to be specified in points (e.g. 10pt means 10)
+ *
+ * @param string $file
+ * @param integer $size
+ * @param ColorInterface $color
+ *
+ * @return FontInterface
+ */
+ public function font($file, $size, ColorInterface $color);
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/LayersInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/LayersInterface.php
new file mode 100644
index 0000000..44df423
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/LayersInterface.php
@@ -0,0 +1,107 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image;
+
+use Imagine\Exception\RuntimeException;
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Exception\OutOfBoundsException;
+
+/**
+ * The layers interface
+ */
+interface LayersInterface extends \Iterator, \Countable, \ArrayAccess
+{
+ /**
+ * Merge layers into the original objects
+ *
+ * @throws RuntimeException
+ */
+ public function merge();
+
+ /**
+ * Animates layers
+ *
+ * @param string $format The output output format
+ * @param integer $delay The delay in milliseconds between two frames
+ * @param integer $loops The number of loops, 0 means infinite
+ *
+ * @return LayersInterface
+ *
+ * @throws InvalidArgumentException In case an invalid argument is provided
+ * @throws RuntimeException In case the driver fails to animate
+ */
+ public function animate($format, $delay, $loops);
+
+ /**
+ * Coalesce layers. Each layer in the sequence is the same size as the first and composited with the next layer in
+ * the sequence.
+ */
+ public function coalesce();
+
+ /**
+ * Adds an image at the end of the layers stack
+ *
+ * @param ImageInterface $image
+ *
+ * @return LayersInterface
+ *
+ * @throws RuntimeException
+ */
+ public function add(ImageInterface $image);
+
+ /**
+ * Set an image at offset
+ *
+ * @param integer $offset
+ * @param ImageInterface $image
+ *
+ * @return LayersInterface
+ *
+ * @throws RuntimeException
+ * @throws InvalidArgumentException
+ * @throws OutOfBoundsException
+ */
+ public function set($offset, ImageInterface $image);
+
+ /**
+ * Removes the image at offset
+ *
+ * @param integer $offset
+ *
+ * @return LayersInterface
+ *
+ * @throws RuntimeException
+ * @throws InvalidArgumentException
+ */
+ public function remove($offset);
+
+ /**
+ * Returns the image at offset
+ *
+ * @param integer $offset
+ *
+ * @return ImageInterface
+ *
+ * @throws RuntimeException
+ * @throws InvalidArgumentException
+ */
+ public function get($offset);
+
+ /**
+ * Returns true if a layer at offset is preset
+ *
+ * @param integer $offset
+ *
+ * @return Boolean
+ */
+ public function has($offset);
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/ManipulatorInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/ManipulatorInterface.php
new file mode 100644
index 0000000..392b908
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/ManipulatorInterface.php
@@ -0,0 +1,181 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image;
+
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Exception\OutOfBoundsException;
+use Imagine\Exception\RuntimeException;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\Fill\FillInterface;
+
+/**
+ * The manipulator interface
+ */
+interface ManipulatorInterface
+{
+ const THUMBNAIL_INSET = 'inset';
+ const THUMBNAIL_OUTBOUND = 'outbound';
+
+ /**
+ * Copies current source image into a new ImageInterface instance
+ *
+ * @throws RuntimeException
+ *
+ * @return static
+ */
+ public function copy();
+
+ /**
+ * Crops a specified box out of the source image (modifies the source image)
+ * Returns cropped self
+ *
+ * @param PointInterface $start
+ * @param BoxInterface $size
+ *
+ * @throws OutOfBoundsException
+ * @throws RuntimeException
+ *
+ * @return static
+ */
+ public function crop(PointInterface $start, BoxInterface $size);
+
+ /**
+ * Resizes current image and returns self
+ *
+ * @param BoxInterface $size
+ * @param string $filter
+ *
+ * @throws RuntimeException
+ *
+ * @return static
+ */
+ public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED);
+
+ /**
+ * Rotates an image at the given angle.
+ * Optional $background can be used to specify the fill color of the empty
+ * area of rotated image.
+ *
+ * @param integer $angle
+ * @param ColorInterface $background
+ *
+ * @throws RuntimeException
+ *
+ * @return static
+ */
+ public function rotate($angle, ColorInterface $background = null);
+
+ /**
+ * Pastes an image into a parent image
+ * Throws exceptions if image exceeds parent image borders or if paste
+ * operation fails
+ *
+ * Returns source image
+ *
+ * @param ImageInterface $image
+ * @param PointInterface $start
+ *
+ * @throws InvalidArgumentException
+ * @throws OutOfBoundsException
+ * @throws RuntimeException
+ *
+ * @return static
+ */
+ public function paste(ImageInterface $image, PointInterface $start);
+
+ /**
+ * Saves the image at a specified path, the target file extension is used
+ * to determine file format, only jpg, jpeg, gif, png, wbmp and xbm are
+ * supported
+ *
+ * @param string $path
+ * @param array $options
+ *
+ * @throws RuntimeException
+ *
+ * @return static
+ */
+ public function save($path = null, array $options = array());
+
+ /**
+ * Outputs the image content
+ *
+ * @param string $format
+ * @param array $options
+ *
+ * @throws RuntimeException
+ *
+ * @return static
+ */
+ public function show($format, array $options = array());
+
+ /**
+ * Flips current image using horizontal axis
+ *
+ * @throws RuntimeException
+ *
+ * @return static
+ */
+ public function flipHorizontally();
+
+ /**
+ * Flips current image using vertical axis
+ *
+ * @throws RuntimeException
+ *
+ * @return static
+ */
+ public function flipVertically();
+
+ /**
+ * Remove all profiles and comments
+ *
+ * @throws RuntimeException
+ *
+ * @return static
+ */
+ public function strip();
+
+ /**
+ * Generates a thumbnail from a current image
+ * Returns it as a new image, doesn't modify the current image
+ *
+ * @param BoxInterface $size
+ * @param string $mode
+ * @param string $filter The filter to use for resizing, one of ImageInterface::FILTER_*
+ *
+ * @throws RuntimeException
+ *
+ * @return static
+ */
+ public function thumbnail(BoxInterface $size, $mode = self::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED);
+
+ /**
+ * Applies a given mask to current image's alpha channel
+ *
+ * @param ImageInterface $mask
+ *
+ * @return static
+ */
+ public function applyMask(ImageInterface $mask);
+
+ /**
+ * Fills image with provided filling, by replacing each pixel's color in
+ * the current image with corresponding color from FillInterface, and
+ * returns modified image
+ *
+ * @param FillInterface $fill
+ *
+ * @return static
+ */
+ public function fill(FillInterface $fill);
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Metadata/AbstractMetadataReader.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Metadata/AbstractMetadataReader.php
new file mode 100644
index 0000000..a709655
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Metadata/AbstractMetadataReader.php
@@ -0,0 +1,101 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Metadata;
+
+use Imagine\Exception\InvalidArgumentException;
+
+abstract class AbstractMetadataReader implements MetadataReaderInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function readFile($file)
+ {
+ if (stream_is_local($file)) {
+ if (!is_file($file)) {
+ throw new InvalidArgumentException(sprintf('File %s does not exist.', $file));
+ }
+
+ return new MetadataBag(array_merge(array('filepath' => realpath($file), 'uri' => $file), $this->extractFromFile($file)));
+ }
+
+ return new MetadataBag(array_merge(array('uri' => $file), $this->extractFromFile($file)));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function readData($data)
+ {
+ return new MetadataBag($this->extractFromData($data));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function readStream($resource)
+ {
+ if (!is_resource($resource)) {
+ throw new InvalidArgumentException('Invalid resource provided.');
+ }
+
+ return new MetadataBag(array_merge($this->getStreamMetadata($resource), $this->extractFromStream($resource)));
+ }
+
+ /**
+ * Gets the URI from a stream resource
+ *
+ * @param resource $resource
+ *
+ * @return string|null The URI f ava
+ */
+ private function getStreamMetadata($resource)
+ {
+ $metadata = array();
+
+ if (false !== $data = @stream_get_meta_data($resource)) {
+ $metadata['uri'] = $data['uri'];
+ if (stream_is_local($resource)) {
+ $metadata['filepath'] = realpath($data['uri']);
+ }
+ }
+
+ return $metadata;
+ }
+
+ /**
+ * Extracts metadata from a file
+ *
+ * @param $file
+ *
+ * @return array An associative array of metadata
+ */
+ abstract protected function extractFromFile($file);
+
+ /**
+ * Extracts metadata from raw data
+ *
+ * @param $data
+ *
+ * @return array An associative array of metadata
+ */
+ abstract protected function extractFromData($data);
+
+ /**
+ * Extracts metadata from a stream
+ *
+ * @param $resource
+ *
+ * @return array An associative array of metadata
+ */
+ abstract protected function extractFromStream($resource);
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Metadata/DefaultMetadataReader.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Metadata/DefaultMetadataReader.php
new file mode 100644
index 0000000..349366e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Metadata/DefaultMetadataReader.php
@@ -0,0 +1,42 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Metadata;
+
+/**
+ * Default metadata reader
+ */
+class DefaultMetadataReader extends AbstractMetadataReader
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function extractFromFile($file)
+ {
+ return array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function extractFromData($data)
+ {
+ return array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function extractFromStream($resource)
+ {
+ return array();
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Metadata/ExifMetadataReader.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Metadata/ExifMetadataReader.php
new file mode 100644
index 0000000..dd8e7d0
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Metadata/ExifMetadataReader.php
@@ -0,0 +1,114 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Metadata;
+
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Exception\NotSupportedException;
+
+/**
+ * Metadata driven by Exif information
+ */
+class ExifMetadataReader extends AbstractMetadataReader
+{
+ public function __construct()
+ {
+ if (!self::isSupported()) {
+ throw new NotSupportedException('PHP exif extension is required to use the ExifMetadataReader');
+ }
+ }
+
+ public static function isSupported()
+ {
+ return function_exists('exif_read_data');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function extractFromFile($file)
+ {
+ if (false === $data = @file_get_contents($file)) {
+ throw new InvalidArgumentException(sprintf('File %s is not readable.', $file));
+ }
+
+ return $this->doReadData($data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function extractFromData($data)
+ {
+ return $this->doReadData($data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function extractFromStream($resource)
+ {
+ if (0 < ftell($resource)) {
+ $metadata = stream_get_meta_data($resource);
+ if ($metadata['seekable']) {
+ rewind($resource);
+ }
+ }
+
+ return $this->doReadData(stream_get_contents($resource));
+ }
+
+ /**
+ * Extracts metadata from raw data, merges with existing metadata
+ *
+ * @param string $data
+ *
+ * @return MetadataBag
+ */
+ private function doReadData($data)
+ {
+ if (substr($data, 0, 2) === 'II') {
+ $mime = 'image/tiff';
+ } else {
+ $mime = 'image/jpeg';
+ }
+
+ return $this->extract('data://' . $mime . ';base64,' . base64_encode($data));
+ }
+
+ /**
+ * Performs the exif data extraction given a path or data-URI representation.
+ *
+ * @param string $path The path to the file or the data-URI representation.
+ *
+ * @return MetadataBag
+ */
+ private function extract($path)
+ {
+ if (false === $exifData = @exif_read_data($path, null, true, false)) {
+ return array();
+ }
+
+ $metadata = array();
+ $sources = array('EXIF' => 'exif', 'IFD0' => 'ifd0');
+
+ foreach ($sources as $name => $prefix) {
+ if (!isset($exifData[$name])) {
+ continue;
+ }
+ foreach ($exifData[$name] as $prop => $value) {
+ $metadata[$prefix.'.'.$prop] = $value;
+ }
+ }
+
+ return $metadata;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Metadata/MetadataBag.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Metadata/MetadataBag.php
new file mode 100644
index 0000000..b7e917a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Metadata/MetadataBag.php
@@ -0,0 +1,97 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Metadata;
+
+/**
+ * An interface for Image Metadata
+ */
+class MetadataBag implements \ArrayAccess, \IteratorAggregate, \Countable
+{
+ /** @var array */
+ private $data;
+
+ public function __construct(array $data = array())
+ {
+ $this->data = $data;
+ }
+
+ /**
+ * Returns the metadata key, default value if it does not exist
+ *
+ * @param string $key
+ * @param mixed|null $default
+ *
+ * @return mixed
+ */
+ public function get($key, $default = null)
+ {
+ return array_key_exists($key, $this->data) ? $this->data[$key] : $default;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function count()
+ {
+ return count($this->data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getIterator()
+ {
+ return new \ArrayIterator($this->data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetExists($offset)
+ {
+ return array_key_exists($offset, $this->data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetSet($offset, $value)
+ {
+ $this->data[$offset] = $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetUnset($offset)
+ {
+ unset($this->data[$offset]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetGet($offset)
+ {
+ return $this->get($offset);
+ }
+
+ /**
+ * Returns metadata as an array
+ *
+ * @return array An associative array
+ */
+ public function toArray()
+ {
+ return $this->data;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Metadata/MetadataReaderInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Metadata/MetadataReaderInterface.php
new file mode 100644
index 0000000..62fcc88
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Metadata/MetadataReaderInterface.php
@@ -0,0 +1,48 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Metadata;
+
+use Imagine\Exception\InvalidArgumentException;
+
+interface MetadataReaderInterface
+{
+ /**
+ * Reads metadata from a file.
+ *
+ * @param $file The path to the file where to read metadata.
+ *
+ * @throws InvalidArgumentException In case the file does not exist.
+ *
+ * @return MetadataBag
+ */
+ public function readFile($file);
+
+ /**
+ * Reads metadata from a binary string.
+ *
+ * @param $data The binary string to read.
+ *
+ * @return MetadataBag
+ */
+ public function readData($data);
+
+ /**
+ * Reads metadata from a stream.
+ *
+ * @param $resource The stream to read.
+ *
+ * @throws InvalidArgumentException In case the resource is not valid.
+ *
+ * @return MetadataBag
+ */
+ public function readStream($resource);
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/CMYK.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/CMYK.php
new file mode 100644
index 0000000..2beecf2
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/CMYK.php
@@ -0,0 +1,118 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Palette;
+
+use Imagine\Image\Palette\Color\CMYK as CMYKColor;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Exception\RuntimeException;
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Image\Profile;
+use Imagine\Image\ProfileInterface;
+
+class CMYK implements PaletteInterface
+{
+ private $parser;
+ private $profile;
+ private static $colors = array();
+
+ public function __construct()
+ {
+ $this->parser = new ColorParser();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function name()
+ {
+ return PaletteInterface::PALETTE_CMYK;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function pixelDefinition()
+ {
+ return array(
+ ColorInterface::COLOR_CYAN,
+ ColorInterface::COLOR_MAGENTA,
+ ColorInterface::COLOR_YELLOW,
+ ColorInterface::COLOR_KEYLINE,
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsAlpha()
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function color($color, $alpha = null)
+ {
+ if (null !== $alpha) {
+ throw new InvalidArgumentException('CMYK palette does not support alpha');
+ }
+
+ $color = $this->parser->parseToCMYK($color);
+ $index = sprintf('cmyk(%d, %d, %d, %d)', $color[0], $color[1], $color[2], $color[3]);
+
+ if (false === array_key_exists($index, self::$colors)) {
+ self::$colors[$index] = new CMYKColor($this, $color);
+ }
+
+ return self::$colors[$index];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function blend(ColorInterface $color1, ColorInterface $color2, $amount)
+ {
+ if (!$color1 instanceof CMYKColor || ! $color2 instanceof CMYKColor) {
+ throw new RuntimeException('CMYK palette can only blend CMYK colors');
+ }
+
+ return $this->color(array(
+ min(100, $color1->getCyan() + $color2->getCyan() * $amount),
+ min(100, $color1->getMagenta() + $color2->getMagenta() * $amount),
+ min(100, $color1->getYellow() + $color2->getYellow() * $amount),
+ min(100, $color1->getKeyline() + $color2->getKeyline() * $amount),
+ ));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function useProfile(ProfileInterface $profile)
+ {
+ $this->profile = $profile;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function profile()
+ {
+ if (!$this->profile) {
+ $this->profile = Profile::fromPath(__DIR__ . '/../../resources/Adobe/CMYK/USWebUncoated.icc');
+ }
+
+ return $this->profile;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/Color/CMYK.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/Color/CMYK.php
new file mode 100644
index 0000000..3165433
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/Color/CMYK.php
@@ -0,0 +1,219 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Palette\Color;
+
+use Imagine\Image\Palette\CMYK as CMYKPalette;
+use Imagine\Exception\RuntimeException;
+use Imagine\Exception\InvalidArgumentException;
+
+final class CMYK implements ColorInterface
+{
+ /**
+ * @var integer
+ */
+ private $c;
+
+ /**
+ * @var integer
+ */
+ private $m;
+
+ /**
+ * @var integer
+ */
+ private $y;
+
+ /**
+ * @var integer
+ */
+ private $k;
+
+ /**
+ *
+ * @var CMYK
+ */
+ private $palette;
+
+ public function __construct(CMYKPalette $palette, array $color)
+ {
+ $this->palette = $palette;
+ $this->setColor($color);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getValue($component)
+ {
+ switch ($component) {
+ case ColorInterface::COLOR_CYAN:
+ return $this->getCyan();
+ case ColorInterface::COLOR_MAGENTA:
+ return $this->getMagenta();
+ case ColorInterface::COLOR_YELLOW:
+ return $this->getYellow();
+ case ColorInterface::COLOR_KEYLINE:
+ return $this->getKeyline();
+ default:
+ throw new InvalidArgumentException(sprintf('Color component %s is not valid', $component));
+ }
+ }
+
+ /**
+ * Returns Cyan value of the color
+ *
+ * @return integer
+ */
+ public function getCyan()
+ {
+ return $this->c;
+ }
+
+ /**
+ * Returns Magenta value of the color
+ *
+ * @return integer
+ */
+ public function getMagenta()
+ {
+ return $this->m;
+ }
+
+ /**
+ * Returns Yellow value of the color
+ *
+ * @return integer
+ */
+ public function getYellow()
+ {
+ return $this->y;
+ }
+
+ /**
+ * Returns Key value of the color
+ *
+ * @return integer
+ */
+ public function getKeyline()
+ {
+ return $this->k;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPalette()
+ {
+ return $this->palette;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAlpha()
+ {
+ return null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function dissolve($alpha)
+ {
+ throw new RuntimeException('CMYK does not support dissolution');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function lighten($shade)
+ {
+ return $this->palette->color(
+ array(
+ $this->c,
+ $this->m,
+ $this->y,
+ max(0, $this->k - $shade),
+ )
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function darken($shade)
+ {
+ return $this->palette->color(
+ array(
+ $this->c,
+ $this->m,
+ $this->y,
+ min(100, $this->k + $shade),
+ )
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function grayscale()
+ {
+ $color = array(
+ $this->c * (1 - $this->k / 100) + $this->k,
+ $this->m * (1 - $this->k / 100) + $this->k,
+ $this->y * (1 - $this->k / 100) + $this->k,
+ );
+
+ $gray = min(100, round(0.299 * $color[0] + 0.587 * $color[1] + 0.114 * $color[2]));
+
+ return $this->palette->color(array($gray, $gray, $gray, $this->k));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isOpaque()
+ {
+ return true;
+ }
+
+ /**
+ * Returns hex representation of the color
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return sprintf('cmyk(%d%%, %d%%, %d%%, %d%%)', $this->c, $this->m, $this->y, $this->k);
+ }
+
+ /**
+ * Internal, Performs checks for color validity (an of array(C, M, Y, K))
+ *
+ * @param array $color
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setColor(array $color)
+ {
+ if (count($color) !== 4) {
+ throw new InvalidArgumentException('Color argument must look like array(C, M, Y, K), where C, M, Y, K are the integer values between 0 and 255 for cyan, magenta, yellow and black color indexes accordingly');
+ }
+
+ $colors = array_values($color);
+ array_walk($colors, function ($color) {
+ return max(0, min(100, $color));
+ });
+
+ list($this->c, $this->m, $this->y, $this->k) = $colors;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/Color/ColorInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/Color/ColorInterface.php
new file mode 100644
index 0000000..8784c4e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/Color/ColorInterface.php
@@ -0,0 +1,95 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Palette\Color;
+
+use Imagine\Image\Palette\PaletteInterface;
+
+interface ColorInterface
+{
+ const COLOR_RED = 'red';
+ const COLOR_GREEN = 'green';
+ const COLOR_BLUE = 'blue';
+
+ const COLOR_CYAN = 'cyan';
+ const COLOR_MAGENTA = 'magenta';
+ const COLOR_YELLOW = 'yellow';
+ const COLOR_KEYLINE = 'keyline';
+
+ const COLOR_GRAY = 'gray';
+
+ /**
+ * Return the value of one of the component.
+ *
+ * @param string $component One of the ColorInterface::COLOR_* component
+ *
+ * @return Integer
+ */
+ public function getValue($component);
+
+ /**
+ * Returns percentage of transparency of the color
+ *
+ * @return integer
+ */
+ public function getAlpha();
+
+ /**
+ * Returns the palette attached to the current color
+ *
+ * @return PaletteInterface
+ */
+ public function getPalette();
+
+ /**
+ * Returns a copy of current color, incrementing the alpha channel by the
+ * given amount
+ *
+ * @param integer $alpha
+ *
+ * @return ColorInterface
+ */
+ public function dissolve($alpha);
+
+ /**
+ * Returns a copy of the current color, lightened by the specified number
+ * of shades
+ *
+ * @param integer $shade
+ *
+ * @return ColorInterface
+ */
+ public function lighten($shade);
+
+ /**
+ * Returns a copy of the current color, darkened by the specified number of
+ * shades
+ *
+ * @param integer $shade
+ *
+ * @return ColorInterface
+ */
+ public function darken($shade);
+
+ /**
+ * Returns a gray related to the current color
+ *
+ * @return ColorInterface
+ */
+ public function grayscale();
+
+ /**
+ * Checks if the current color is opaque
+ *
+ * @return Boolean
+ */
+ public function isOpaque();
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/Color/Gray.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/Color/Gray.php
new file mode 100644
index 0000000..c809645
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/Color/Gray.php
@@ -0,0 +1,164 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Palette\Color;
+
+use Imagine\Image\Palette\Grayscale;
+use Imagine\Exception\InvalidArgumentException;
+
+final class Gray implements ColorInterface
+{
+ /**
+ * @var integer
+ */
+ private $gray;
+
+ /**
+ * @var integer
+ */
+ private $alpha;
+
+ /**
+ *
+ * @var Grayscale
+ */
+ private $palette;
+
+ public function __construct(Grayscale $palette, array $color, $alpha)
+ {
+ $this->palette = $palette;
+ $this->setColor($color);
+ $this->setAlpha($alpha);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getValue($component)
+ {
+ switch ($component) {
+ case ColorInterface::COLOR_GRAY:
+ return $this->getGray();
+ default:
+ throw new InvalidArgumentException(sprintf('Color component %s is not valid', $component));
+ }
+ }
+
+ /**
+ * Returns Gray value of the color
+ *
+ * @return integer
+ */
+ public function getGray()
+ {
+ return $this->gray;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPalette()
+ {
+ return $this->palette;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAlpha()
+ {
+ return $this->alpha;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function dissolve($alpha)
+ {
+ return $this->palette->color(
+ array($this->gray), $this->alpha + $alpha
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function lighten($shade)
+ {
+ return $this->palette->color(array(min(255, $this->gray + $shade)), $this->alpha);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function darken($shade)
+ {
+ return $this->palette->color(array(max(0, $this->gray - $shade)), $this->alpha);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function grayscale()
+ {
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isOpaque()
+ {
+ return 100 === $this->alpha;
+ }
+
+ /**
+ * Returns hex representation of the color
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return sprintf('#%02x%02x%02x', $this->gray, $this->gray, $this->gray);
+ }
+
+ /**
+ * Performs checks for validity of given alpha value and sets it
+ *
+ * @param integer $alpha
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setAlpha($alpha)
+ {
+ if (!is_int($alpha) || $alpha < 0 || $alpha > 100) {
+ throw new InvalidArgumentException(sprintf('Alpha must be an integer between 0 and 100, %s given', $alpha));
+ }
+
+ $this->alpha = $alpha;
+ }
+
+ /**
+ * Performs checks for color validity (array of array(gray))
+ *
+ * @param array $color
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setColor(array $color)
+ {
+ if (count($color) !== 1) {
+ throw new InvalidArgumentException('Color argument must look like array(gray), where gray is the integer value between 0 and 255 for the grayscale');
+ }
+
+ list($this->gray) = array_values($color);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/Color/RGB.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/Color/RGB.php
new file mode 100644
index 0000000..a0b4f0d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/Color/RGB.php
@@ -0,0 +1,214 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Palette\Color;
+
+use Imagine\Image\Palette\RGB as RGBPalette;
+use Imagine\Exception\InvalidArgumentException;
+
+final class RGB implements ColorInterface
+{
+ /**
+ * @var integer
+ */
+ private $r;
+
+ /**
+ * @var integer
+ */
+ private $g;
+
+ /**
+ * @var integer
+ */
+ private $b;
+
+ /**
+ * @var integer
+ */
+ private $alpha;
+
+ /**
+ *
+ * @var RGBPalette
+ */
+ private $palette;
+
+ public function __construct(RGBPalette $palette, array $color, $alpha)
+ {
+ $this->palette = $palette;
+ $this->setColor($color);
+ $this->setAlpha($alpha);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getValue($component)
+ {
+ switch ($component) {
+ case ColorInterface::COLOR_RED:
+ return $this->getRed();
+ case ColorInterface::COLOR_GREEN:
+ return $this->getGreen();
+ case ColorInterface::COLOR_BLUE:
+ return $this->getBlue();
+ default:
+ throw new InvalidArgumentException(sprintf('Color component %s is not valid', $component));
+ }
+ }
+
+ /**
+ * Returns RED value of the color
+ *
+ * @return integer
+ */
+ public function getRed()
+ {
+ return $this->r;
+ }
+
+ /**
+ * Returns GREEN value of the color
+ *
+ * @return integer
+ */
+ public function getGreen()
+ {
+ return $this->g;
+ }
+
+ /**
+ * Returns BLUE value of the color
+ *
+ * @return integer
+ */
+ public function getBlue()
+ {
+ return $this->b;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPalette()
+ {
+ return $this->palette;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAlpha()
+ {
+ return $this->alpha;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function dissolve($alpha)
+ {
+ return $this->palette->color(array($this->r, $this->g, $this->b), $this->alpha + $alpha);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function lighten($shade)
+ {
+ return $this->palette->color(
+ array(
+ min(255, $this->r + $shade),
+ min(255, $this->g + $shade),
+ min(255, $this->b + $shade),
+ ), $this->alpha
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function darken($shade)
+ {
+ return $this->palette->color(
+ array(
+ max(0, $this->r - $shade),
+ max(0, $this->g - $shade),
+ max(0, $this->b - $shade),
+ ), $this->alpha
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function grayscale()
+ {
+ $gray = min(255, round(0.299 * $this->getRed() + 0.114 * $this->getBlue() + 0.587 * $this->getGreen()));
+
+ return $this->palette->color(array($gray, $gray, $gray), $this->alpha);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isOpaque()
+ {
+ return 100 === $this->alpha;
+ }
+
+ /**
+ * Returns hex representation of the color
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return sprintf('#%02x%02x%02x', $this->r, $this->g, $this->b);
+ }
+
+ /**
+ * Internal
+ *
+ * Performs checks for validity of given alpha value and sets it
+ *
+ * @param integer $alpha
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setAlpha($alpha)
+ {
+ if (!is_int($alpha) || $alpha < 0 || $alpha > 100) {
+ throw new InvalidArgumentException(sprintf('Alpha must be an integer between 0 and 100, %s given', $alpha));
+ }
+
+ $this->alpha = $alpha;
+ }
+
+ /**
+ * Internal
+ *
+ * Performs checks for color validity (array of array(R, G, B))
+ *
+ * @param array $color
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setColor(array $color)
+ {
+ if (count($color) !== 3) {
+ throw new InvalidArgumentException('Color argument must look like array(R, G, B), where R, G, B are the integer values between 0 and 255 for red, green and blue color indexes accordingly');
+ }
+
+ list($this->r, $this->g, $this->b) = array_values($color);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/ColorParser.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/ColorParser.php
new file mode 100644
index 0000000..35cf4e9
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/ColorParser.php
@@ -0,0 +1,153 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Palette;
+
+use Imagine\Exception\InvalidArgumentException;
+
+class ColorParser
+{
+ /**
+ * Parses a color to a RGB tuple
+ *
+ * @param string|array|integer $color
+ *
+ * @return array
+ *
+ * @throws InvalidArgumentException
+ */
+ public function parseToRGB($color)
+ {
+ $color = $this->parse($color);
+
+ if (4 === count($color)) {
+ $color = array(
+ 255 * (1 - $color[0] / 100) * (1 - $color[3] / 100),
+ 255 * (1 - $color[1] / 100) * (1 - $color[3] / 100),
+ 255 * (1 - $color[2] / 100) * (1 - $color[3] / 100),
+ );
+ }
+
+ return $color;
+ }
+
+ /**
+ * Parses a color to a CMYK tuple
+ *
+ * @param string|array|integer $color
+ *
+ * @return array
+ *
+ * @throws InvalidArgumentException
+ */
+ public function parseToCMYK($color)
+ {
+ $color = $this->parse($color);
+
+ if (3 === count($color)) {
+ $r = $color[0] / 255;
+ $g = $color[1] / 255;
+ $b = $color[2] / 255;
+
+ $k = 1 - max($r, $g, $b);
+
+ $color = array(
+ 1 === $k ? 0 : round((1 - $r - $k) / (1- $k) * 100),
+ 1 === $k ? 0 : round((1 - $g - $k) / (1- $k) * 100),
+ 1 === $k ? 0 : round((1 - $b - $k) / (1- $k) * 100),
+ round($k * 100)
+ );
+ }
+
+ return $color;
+ }
+
+ /**
+ * Parses a color to a grayscale value
+ *
+ * @param string|array|integer $color
+ *
+ * @return array
+ *
+ * @throws InvalidArgumentException
+ */
+ public function parseToGrayscale($color)
+ {
+ if (is_array($color) && 1 === count($color)) {
+ return array_values($color);
+ }
+
+ $color = array_unique($this->parse($color));
+
+ if (1 !== count($color)) {
+ throw new InvalidArgumentException('The provided color has different values of red, green and blue components. Grayscale colors must have the same values for these.');
+ }
+
+ return $color;
+ }
+
+ /**
+ * Parses a color
+ *
+ * @param string|array|integer $color
+ *
+ * @return array
+ *
+ * @throws InvalidArgumentException
+ */
+ private function parse($color)
+ {
+ if (!is_string($color) && !is_array($color) && !is_int($color)) {
+ throw new InvalidArgumentException(sprintf('Color must be specified as a hexadecimal string, array or integer, %s given', gettype($color)));
+ }
+
+ if (is_array($color)) {
+ if (3 === count($color) || 4 === count($color)) {
+ return array_values($color);
+ }
+ throw new InvalidArgumentException('Color argument if array, must look like array(R, G, B), or array(C, M, Y, K) where R, G, B are the integer values between 0 and 255 for red, green and blue or cyan, magenta, yellow and black color indexes accordingly');
+ }
+
+ if (is_string($color)) {
+ if (0 === strpos($color, 'cmyk(')) {
+ $substrColor = substr($color, 5, strlen($color) - 6);
+
+ $components = array_map(function ($component) {
+ return round(trim($component, ' %'));
+ }, explode(',', $substrColor));
+
+ if (count($components) !== 4) {
+ throw new InvalidArgumentException(sprintf('Unable to parse color %s', $color));
+ }
+
+ return $components;
+ } else {
+ $color = ltrim($color, '#');
+
+ if (strlen($color) !== 3 && strlen($color) !== 6) {
+ throw new InvalidArgumentException(sprintf('Color must be a hex value in regular (6 characters) or short (3 characters) notation, "%s" given', $color));
+ }
+
+ if (strlen($color) === 3) {
+ $color = $color[0] . $color[0] . $color[1] . $color[1] . $color[2] . $color[2];
+ }
+
+ $color = array_map('hexdec', str_split($color, 2));
+ }
+ }
+
+ if (is_int($color)) {
+ $color = array(255 & ($color >> 16), 255 & ($color >> 8), 255 & $color);
+ }
+
+ return $color;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/Grayscale.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/Grayscale.php
new file mode 100644
index 0000000..088b790
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/Grayscale.php
@@ -0,0 +1,123 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Palette;
+
+use Imagine\Image\Palette\Color\Gray as GrayColor;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\ProfileInterface;
+use Imagine\Image\Profile;
+use Imagine\Exception\RuntimeException;
+
+class Grayscale implements PaletteInterface
+{
+ /**
+ * @var ColorParser
+ */
+ private $parser;
+
+ /**
+ * @var ProfileInterface
+ */
+ private $profile;
+
+ /**
+ * @var array
+ */
+ protected static $colors = array();
+
+ public function __construct()
+ {
+ $this->parser = new ColorParser();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function name()
+ {
+ return PaletteInterface::PALETTE_GRAYSCALE;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function pixelDefinition()
+ {
+ return array(ColorInterface::COLOR_GRAY);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsAlpha()
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function useProfile(ProfileInterface $profile)
+ {
+ $this->profile = $profile;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function profile()
+ {
+ if (!$this->profile) {
+ $this->profile = Profile::fromPath(__DIR__ . '/../../resources/colormanagement.org/ISOcoated_v2_grey1c_bas.ICC');
+ }
+
+ return $this->profile;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function color($color, $alpha = null)
+ {
+ if (null === $alpha) {
+ $alpha = 0;
+ }
+
+ $color = $this->parser->parseToGrayscale($color);
+ $index = sprintf('#%02x%02x%02x-%d', $color[0], $color[0], $color[0], $alpha);
+
+ if (false === array_key_exists($index, static::$colors)) {
+ static::$colors[$index] = new GrayColor($this, $color, $alpha);
+ }
+
+ return static::$colors[$index];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function blend(ColorInterface $color1, ColorInterface $color2, $amount)
+ {
+ if (!$color1 instanceof GrayColor || ! $color2 instanceof GrayColor) {
+ throw new RuntimeException('Grayscale palette can only blend Grayscale colors');
+ }
+
+ return $this->color(
+ array(
+ (int) min(255, min($color1->getGray(), $color2->getGray()) + round(abs($color2->getGray() - $color1->getGray()) * $amount)),
+ ),
+ (int) min(100, min($color1->getAlpha(), $color2->getAlpha()) + round(abs($color2->getAlpha() - $color1->getAlpha()) * $amount))
+ );
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/PaletteInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/PaletteInterface.php
new file mode 100644
index 0000000..855c244
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/PaletteInterface.php
@@ -0,0 +1,87 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Palette;
+
+use Imagine\Image\ProfileInterface;
+use Imagine\Image\Palette\Color\ColorInterface;
+
+interface PaletteInterface
+{
+ const PALETTE_GRAYSCALE = 'gray';
+ const PALETTE_RGB = 'rgb';
+ const PALETTE_CMYK = 'cmyk';
+
+ /**
+ * Returns a color given some values
+ *
+ * @param string|array|integer $color A color
+ * @param integer|null $alpha Set alpha to null to disable it
+ *
+ * @return ColorInterface
+ *
+ * @throws InvalidArgumentException In case you pass an alpha value to a
+ * Palette that does not support alpha
+ */
+ public function color($color, $alpha = null);
+
+ /**
+ * Blend two colors given an amount
+ *
+ * @param ColorInterface $color1
+ * @param ColorInterface $color2
+ * @param float $amount The amount of color2 in color1
+ *
+ * @return ColorInterface
+ */
+ public function blend(ColorInterface $color1, ColorInterface $color2, $amount);
+
+ /**
+ * Attachs an ICC profile to this Palette.
+ *
+ * (A default profile is provided by default)
+ *
+ * @param ProfileInterface $profile
+ *
+ * @return PaletteInterface
+ */
+ public function useProfile(ProfileInterface $profile);
+
+ /**
+ * Returns the ICC profile attached to this Palette.
+ *
+ * @return ProfileInterface
+ */
+ public function profile();
+
+ /**
+ * Returns the name of this Palette, one of PaletteInterface::PALETTE_*
+ * constants
+ *
+ * @return String
+ */
+ public function name();
+
+ /**
+ * Returns an array containing ColorInterface::COLOR_* constants that
+ * define the structure of colors for a pixel.
+ *
+ * @return array
+ */
+ public function pixelDefinition();
+
+ /**
+ * Tells if alpha channel is supported in this palette
+ *
+ * @return Boolean
+ */
+ public function supportsAlpha();
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/RGB.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/RGB.php
new file mode 100644
index 0000000..0462ca4
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Palette/RGB.php
@@ -0,0 +1,129 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Palette;
+
+use Imagine\Image\Palette\Color\RGB as RGBColor;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\ProfileInterface;
+use Imagine\Image\Profile;
+use Imagine\Exception\RuntimeException;
+
+class RGB implements PaletteInterface
+{
+ /**
+ * @var ColorParser
+ */
+ private $parser;
+
+ /**
+ * @var ProfileInterface
+ */
+ private $profile;
+
+ /**
+ * @var array
+ */
+ protected static $colors = array();
+
+ public function __construct()
+ {
+ $this->parser = new ColorParser();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function name()
+ {
+ return PaletteInterface::PALETTE_RGB;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function pixelDefinition()
+ {
+ return array(
+ ColorInterface::COLOR_RED,
+ ColorInterface::COLOR_GREEN,
+ ColorInterface::COLOR_BLUE,
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsAlpha()
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function useProfile(ProfileInterface $profile)
+ {
+ $this->profile = $profile;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function profile()
+ {
+ if (!$this->profile) {
+ $this->profile = Profile::fromPath(__DIR__ . '/../../resources/color.org/sRGB_IEC61966-2-1_black_scaled.icc');
+ }
+
+ return $this->profile;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function color($color, $alpha = null)
+ {
+ if (null === $alpha) {
+ $alpha = 100;
+ }
+
+ $color = $this->parser->parseToRGB($color);
+ $index = sprintf('#%02x%02x%02x-%d', $color[0], $color[1], $color[2], $alpha);
+
+ if (false === array_key_exists($index, static::$colors)) {
+ static::$colors[$index] = new RGBColor($this, $color, $alpha);
+ }
+
+ return static::$colors[$index];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function blend(ColorInterface $color1, ColorInterface $color2, $amount)
+ {
+ if (!$color1 instanceof RGBColor || ! $color2 instanceof RGBColor) {
+ throw new RuntimeException('RGB palette can only blend RGB colors');
+ }
+
+ return $this->color(
+ array(
+ (int) min(255, min($color1->getRed(), $color2->getRed()) + round(abs($color2->getRed() - $color1->getRed()) * $amount)),
+ (int) min(255, min($color1->getGreen(), $color2->getGreen()) + round(abs($color2->getGreen() - $color1->getGreen()) * $amount)),
+ (int) min(255, min($color1->getBlue(), $color2->getBlue()) + round(abs($color2->getBlue() - $color1->getBlue()) * $amount)),
+ ),
+ (int) min(100, min($color1->getAlpha(), $color2->getAlpha()) + round(abs($color2->getAlpha() - $color1->getAlpha()) * $amount))
+ );
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Point.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Point.php
new file mode 100644
index 0000000..abfc7c3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Point.php
@@ -0,0 +1,88 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image;
+
+use Imagine\Exception\InvalidArgumentException;
+
+/**
+ * The point class
+ */
+final class Point implements PointInterface
+{
+ /**
+ * @var integer
+ */
+ private $x;
+
+ /**
+ * @var integer
+ */
+ private $y;
+
+ /**
+ * Constructs a point of coordinates
+ *
+ * @param integer $x
+ * @param integer $y
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct($x, $y)
+ {
+ if ($x < 0 || $y < 0) {
+ throw new InvalidArgumentException(sprintf('A coordinate cannot be positioned outside of a bounding box (x: %s, y: %s given)', $x, $y));
+ }
+
+ $this->x = $x;
+ $this->y = $y;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getX()
+ {
+ return $this->x;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getY()
+ {
+ return $this->y;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function in(BoxInterface $box)
+ {
+ return $this->x < $box->getWidth() && $this->y < $box->getHeight();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function move($amount)
+ {
+ return new Point($this->x + $amount, $this->y + $amount);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ return sprintf('(%d, %d)', $this->x, $this->y);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Point/Center.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Point/Center.php
new file mode 100644
index 0000000..0e60349
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Point/Center.php
@@ -0,0 +1,77 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image\Point;
+
+use Imagine\Image\BoxInterface;
+use Imagine\Image\Point as OriginalPoint;
+use Imagine\Image\PointInterface;
+
+/**
+ * Point center
+ */
+final class Center implements PointInterface
+{
+ /**
+ * @var BoxInterface
+ */
+ private $box;
+
+ /**
+ * Constructs coordinate with size instance, it needs to be relative to
+ *
+ * @param BoxInterface $box
+ */
+ public function __construct(BoxInterface $box)
+ {
+ $this->box = $box;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getX()
+ {
+ return ceil($this->box->getWidth() / 2);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getY()
+ {
+ return ceil($this->box->getHeight() / 2);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function in(BoxInterface $box)
+ {
+ return $this->getX() < $box->getWidth() && $this->getY() < $box->getHeight();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function move($amount)
+ {
+ return new OriginalPoint($this->getX() + $amount, $this->getY() + $amount);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ return sprintf('(%d, %d)', $this->getX(), $this->getY());
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/PointInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/PointInterface.php
new file mode 100644
index 0000000..f35fa80
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/PointInterface.php
@@ -0,0 +1,56 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image;
+
+/**
+ * The point interface
+ */
+interface PointInterface
+{
+ /**
+ * Gets points x coordinate
+ *
+ * @return integer
+ */
+ public function getX();
+
+ /**
+ * Gets points y coordinate
+ *
+ * @return integer
+ */
+ public function getY();
+
+ /**
+ * Checks if current coordinate is inside a given bo
+ *
+ * @param BoxInterface $box
+ *
+ * @return Boolean
+ */
+ public function in(BoxInterface $box);
+
+ /**
+ * Returns another point, moved by a given amount from current coordinates
+ *
+ * @param integer $amount
+ * @return ImageInterface
+ */
+ public function move($amount);
+
+ /**
+ * Gets a string representation for the current point
+ *
+ * @return string
+ */
+ public function __toString();
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Profile.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Profile.php
new file mode 100644
index 0000000..fda5415
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/Profile.php
@@ -0,0 +1,60 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image;
+
+use Imagine\Exception\InvalidArgumentException;
+
+class Profile implements ProfileInterface
+{
+ private $data;
+ private $name;
+
+ public function __construct($name, $data)
+ {
+ $this->name = $name;
+ $this->data = $data;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function name()
+ {
+ return $this->name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function data()
+ {
+ return $this->data;
+ }
+
+ /**
+ * Creates a profile from a path to a file
+ *
+ * @param String $path
+ *
+ * @return Profile
+ *
+ * @throws InvalidArgumentException In case the provided path is not valid
+ */
+ public static function fromPath($path)
+ {
+ if (!file_exists($path) || !is_file($path) || !is_readable($path)) {
+ throw new InvalidArgumentException(sprintf('Path %s is an invalid profile file or is not readable', $path));
+ }
+
+ return new static(basename($path), file_get_contents($path));
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/ProfileInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/ProfileInterface.php
new file mode 100644
index 0000000..b2caa9c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Image/ProfileInterface.php
@@ -0,0 +1,29 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Image;
+
+interface ProfileInterface
+{
+ /**
+ * Returns the name of the profile
+ *
+ * @return String
+ */
+ public function name();
+
+ /**
+ * Returns the profile data
+ *
+ * @return String
+ */
+ public function data();
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Drawer.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Drawer.php
new file mode 100644
index 0000000..2f86364
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Drawer.php
@@ -0,0 +1,404 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Imagick;
+
+use Imagine\Draw\DrawerInterface;
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Exception\RuntimeException;
+use Imagine\Image\AbstractFont;
+use Imagine\Image\BoxInterface;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\Point;
+use Imagine\Image\PointInterface;
+
+/**
+ * Drawer implementation using the Imagick PHP extension
+ */
+final class Drawer implements DrawerInterface
+{
+ /**
+ * @var Imagick
+ */
+ private $imagick;
+
+ /**
+ * @param \Imagick $imagick
+ */
+ public function __construct(\Imagick $imagick)
+ {
+ $this->imagick = $imagick;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1)
+ {
+ $x = $center->getX();
+ $y = $center->getY();
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+
+ try {
+ $pixel = $this->getColor($color);
+ $arc = new \ImagickDraw();
+
+ $arc->setStrokeColor($pixel);
+ $arc->setStrokeWidth(max(1, (int) $thickness));
+ $arc->setFillColor('transparent');
+ $arc->arc($x - $width / 2, $y - $height / 2, $x + $width / 2, $y + $height / 2, $start, $end);
+
+ $this->imagick->drawImage($arc);
+
+ $pixel->clear();
+ $pixel->destroy();
+
+ $arc->clear();
+ $arc->destroy();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Draw arc operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1)
+ {
+ $x = $center->getX();
+ $y = $center->getY();
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+
+ try {
+ $pixel = $this->getColor($color);
+ $chord = new \ImagickDraw();
+
+ $chord->setStrokeColor($pixel);
+ $chord->setStrokeWidth(max(1, (int) $thickness));
+
+ if ($fill) {
+ $chord->setFillColor($pixel);
+ } else {
+ $this->line(
+ new Point(round($x + $width / 2 * cos(deg2rad($start))), round($y + $height / 2 * sin(deg2rad($start)))),
+ new Point(round($x + $width / 2 * cos(deg2rad($end))), round($y + $height / 2 * sin(deg2rad($end)))),
+ $color
+ );
+
+ $chord->setFillColor('transparent');
+ }
+
+ $chord->arc(
+ $x - $width / 2,
+ $y - $height / 2,
+ $x + $width / 2,
+ $y + $height / 2,
+ $start,
+ $end
+ );
+
+ $this->imagick->drawImage($chord);
+
+ $pixel->clear();
+ $pixel->destroy();
+
+ $chord->clear();
+ $chord->destroy();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Draw chord operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1)
+ {
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+
+ try {
+ $pixel = $this->getColor($color);
+ $ellipse = new \ImagickDraw();
+
+ $ellipse->setStrokeColor($pixel);
+ $ellipse->setStrokeWidth(max(1, (int) $thickness));
+
+ if ($fill) {
+ $ellipse->setFillColor($pixel);
+ } else {
+ $ellipse->setFillColor('transparent');
+ }
+
+ $ellipse->ellipse(
+ $center->getX(),
+ $center->getY(),
+ $width / 2,
+ $height / 2,
+ 0, 360
+ );
+
+ if (false === $this->imagick->drawImage($ellipse)) {
+ throw new RuntimeException('Ellipse operation failed');
+ }
+
+ $pixel->clear();
+ $pixel->destroy();
+
+ $ellipse->clear();
+ $ellipse->destroy();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Draw ellipse operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function line(PointInterface $start, PointInterface $end, ColorInterface $color, $thickness = 1)
+ {
+ try {
+ $pixel = $this->getColor($color);
+ $line = new \ImagickDraw();
+
+ $line->setStrokeColor($pixel);
+ $line->setStrokeWidth(max(1, (int) $thickness));
+ $line->setFillColor($pixel);
+ $line->line(
+ $start->getX(),
+ $start->getY(),
+ $end->getX(),
+ $end->getY()
+ );
+
+ $this->imagick->drawImage($line);
+
+ $pixel->clear();
+ $pixel->destroy();
+
+ $line->clear();
+ $line->destroy();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Draw line operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1)
+ {
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+
+ $x1 = round($center->getX() + $width / 2 * cos(deg2rad($start)));
+ $y1 = round($center->getY() + $height / 2 * sin(deg2rad($start)));
+ $x2 = round($center->getX() + $width / 2 * cos(deg2rad($end)));
+ $y2 = round($center->getY() + $height / 2 * sin(deg2rad($end)));
+
+ if ($fill) {
+ $this->chord($center, $size, $start, $end, $color, true, $thickness);
+ $this->polygon(
+ array(
+ $center,
+ new Point($x1, $y1),
+ new Point($x2, $y2),
+ ),
+ $color,
+ true,
+ $thickness
+ );
+ } else {
+ $this->arc($center, $size, $start, $end, $color, $thickness);
+ $this->line($center, new Point($x1, $y1), $color, $thickness);
+ $this->line($center, new Point($x2, $y2), $color, $thickness);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function dot(PointInterface $position, ColorInterface $color)
+ {
+ $x = $position->getX();
+ $y = $position->getY();
+
+ try {
+ $pixel = $this->getColor($color);
+ $point = new \ImagickDraw();
+
+ $point->setFillColor($pixel);
+ $point->point($x, $y);
+
+ $this->imagick->drawimage($point);
+
+ $pixel->clear();
+ $pixel->destroy();
+
+ $point->clear();
+ $point->destroy();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Draw point operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1)
+ {
+ if (count($coordinates) < 3) {
+ throw new InvalidArgumentException(sprintf('Polygon must consist of at least 3 coordinates, %d given', count($coordinates)));
+ }
+
+ $points = array_map(function (PointInterface $p) {
+ return array('x' => $p->getX(), 'y' => $p->getY());
+ }, $coordinates);
+
+ try {
+ $pixel = $this->getColor($color);
+ $polygon = new \ImagickDraw();
+
+ $polygon->setStrokeColor($pixel);
+ $polygon->setStrokeWidth(max(1, (int) $thickness));
+
+ if ($fill) {
+ $polygon->setFillColor($pixel);
+ } else {
+ $polygon->setFillColor('transparent');
+ }
+
+ $polygon->polygon($points);
+ $this->imagick->drawImage($polygon);
+
+ $pixel->clear();
+ $pixel->destroy();
+
+ $polygon->clear();
+ $polygon->destroy();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Draw polygon operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null)
+ {
+ try {
+ $pixel = $this->getColor($font->getColor());
+ $text = new \ImagickDraw();
+
+ $text->setFont($font->getFile());
+ /**
+ * @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027
+ *
+ * ensure font resolution is the same as GD's hard-coded 96
+ */
+ if (version_compare(phpversion("imagick"), "3.0.2", ">=")) {
+ $text->setResolution(96, 96);
+ $text->setFontSize($font->getSize());
+ } else {
+ $text->setFontSize((int) ($font->getSize() * (96 / 72)));
+ }
+ $text->setFillColor($pixel);
+ $text->setTextAntialias(true);
+
+ $info = $this->imagick->queryFontMetrics($text, $string);
+ $rad = deg2rad($angle);
+ $cos = cos($rad);
+ $sin = sin($rad);
+
+ // round(0 * $cos - 0 * $sin)
+ $x1 = 0;
+ $x2 = round($info['characterWidth'] * $cos - $info['characterHeight'] * $sin);
+ // round(0 * $sin + 0 * $cos)
+ $y1 = 0;
+ $y2 = round($info['characterWidth'] * $sin + $info['characterHeight'] * $cos);
+
+ $xdiff = 0 - min($x1, $x2);
+ $ydiff = 0 - min($y1, $y2);
+
+ if ($width !== null) {
+ $string = $this->wrapText($string, $text, $angle, $width);
+ }
+
+ $this->imagick->annotateImage(
+ $text, $position->getX() + $x1 + $xdiff,
+ $position->getY() + $y2 + $ydiff, $angle, $string
+ );
+
+ $pixel->clear();
+ $pixel->destroy();
+
+ $text->clear();
+ $text->destroy();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Draw text operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Gets specifically formatted color string from ColorInterface instance
+ *
+ * @param ColorInterface $color
+ *
+ * @return string
+ */
+ private function getColor(ColorInterface $color)
+ {
+ $pixel = new \ImagickPixel((string) $color);
+ $pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100);
+
+ return $pixel;
+ }
+
+ /**
+ * Internal
+ *
+ * Fits a string into box with given width
+ */
+ private function wrapText($string, $text, $angle, $width)
+ {
+ $result = '';
+ $words = explode(' ', $string);
+ foreach ($words as $word) {
+ $teststring = $result . ' ' . $word;
+ $testbox = $this->imagick->queryFontMetrics($text, $teststring, true);
+ if ($testbox['textWidth'] > $width) {
+ $result .= ($result == '' ? '' : "\n") . $word;
+ } else {
+ $result .= ($result == '' ? '' : ' ') . $word;
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Effects.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Effects.php
new file mode 100644
index 0000000..debe32a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Effects.php
@@ -0,0 +1,113 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Imagick;
+
+use Imagine\Effects\EffectsInterface;
+use Imagine\Exception\RuntimeException;
+use Imagine\Image\Palette\Color\ColorInterface;
+
+/**
+ * Effects implementation using the Imagick PHP extension
+ */
+class Effects implements EffectsInterface
+{
+ private $imagick;
+
+ public function __construct(\Imagick $imagick)
+ {
+ $this->imagick = $imagick;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function gamma($correction)
+ {
+ try {
+ $this->imagick->gammaImage($correction, \Imagick::CHANNEL_ALL);
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Failed to apply gamma correction to the image');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function negative()
+ {
+ try {
+ $this->imagick->negateImage(false, \Imagick::CHANNEL_ALL);
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Failed to negate the image');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function grayscale()
+ {
+ try {
+ $this->imagick->setImageType(\Imagick::IMGTYPE_GRAYSCALE);
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Failed to grayscale the image');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function colorize(ColorInterface $color)
+ {
+ try {
+ $this->imagick->colorizeImage((string) $color, 1);
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Failed to colorize the image');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function sharpen()
+ {
+ try {
+ $this->imagick->sharpenImage(2, 1);
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Failed to sharpen the image');
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function blur($sigma = 1)
+ {
+ try {
+ $this->imagick->gaussianBlurImage(0, $sigma);
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Failed to blur the image', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Font.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Font.php
new file mode 100644
index 0000000..3fc41dd
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Font.php
@@ -0,0 +1,68 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Imagick;
+
+use Imagine\Image\AbstractFont;
+use Imagine\Image\Box;
+use Imagine\Image\Palette\Color\ColorInterface;
+
+/**
+ * Font implementation using the Imagick PHP extension
+ */
+final class Font extends AbstractFont
+{
+ /**
+ * @var \Imagick
+ */
+ private $imagick;
+
+ /**
+ * @param \Imagick $imagick
+ * @param string $file
+ * @param integer $size
+ * @param ColorInterface $color
+ */
+ public function __construct(\Imagick $imagick, $file, $size, ColorInterface $color)
+ {
+ $this->imagick = $imagick;
+
+ parent::__construct($file, $size, $color);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function box($string, $angle = 0)
+ {
+ $text = new \ImagickDraw();
+
+ $text->setFont($this->file);
+
+ /**
+ * @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027
+ *
+ * ensure font resolution is the same as GD's hard-coded 96
+ */
+ if (version_compare(phpversion("imagick"), "3.0.2", ">=")) {
+ $text->setResolution(96, 96);
+ $text->setFontSize($this->size);
+ } else {
+ $text->setFontSize((int) ($this->size * (96 / 72)));
+ }
+
+ $info = $this->imagick->queryFontMetrics($text, $string);
+
+ $box = new Box($info['textWidth'], $info['textHeight']);
+
+ return $box;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Image.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Image.php
new file mode 100644
index 0000000..c94f605
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Image.php
@@ -0,0 +1,880 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Imagick;
+
+use Imagine\Exception\OutOfBoundsException;
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Exception\RuntimeException;
+use Imagine\Image\AbstractImage;
+use Imagine\Image\Box;
+use Imagine\Image\BoxInterface;
+use Imagine\Image\Metadata\MetadataBag;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Image\Fill\FillInterface;
+use Imagine\Image\Fill\Gradient\Horizontal;
+use Imagine\Image\Fill\Gradient\Linear;
+use Imagine\Image\Point;
+use Imagine\Image\PointInterface;
+use Imagine\Image\ProfileInterface;
+use Imagine\Image\ImageInterface;
+use Imagine\Image\Palette\PaletteInterface;
+
+/**
+ * Image implementation using the Imagick PHP extension
+ */
+final class Image extends AbstractImage
+{
+ /**
+ * @var \Imagick
+ */
+ private $imagick;
+ /**
+ * @var Layers
+ */
+ private $layers;
+ /**
+ * @var PaletteInterface
+ */
+ private $palette;
+
+ /**
+ * @var Boolean
+ */
+ private static $supportsColorspaceConversion;
+
+ private static $colorspaceMapping = array(
+ PaletteInterface::PALETTE_CMYK => \Imagick::COLORSPACE_CMYK,
+ PaletteInterface::PALETTE_RGB => \Imagick::COLORSPACE_RGB,
+ PaletteInterface::PALETTE_GRAYSCALE => \Imagick::COLORSPACE_GRAY,
+ );
+
+ /**
+ * Constructs a new Image instance
+ *
+ * @param \Imagick $imagick
+ * @param PaletteInterface $palette
+ * @param MetadataBag $metadata
+ */
+ public function __construct(\Imagick $imagick, PaletteInterface $palette, MetadataBag $metadata)
+ {
+ $this->metadata = $metadata;
+ $this->detectColorspaceConversionSupport();
+ $this->imagick = $imagick;
+ if (static::$supportsColorspaceConversion) {
+ $this->setColorspace($palette);
+ }
+ $this->palette = $palette;
+ $this->layers = new Layers($this, $this->palette, $this->imagick);
+ }
+
+ /**
+ * Destroys allocated imagick resources
+ */
+ public function __destruct()
+ {
+ if ($this->imagick instanceof \Imagick) {
+ $this->imagick->clear();
+ $this->imagick->destroy();
+ }
+ }
+
+ /**
+ * Returns the underlying \Imagick instance
+ *
+ * @return \Imagick
+ */
+ public function getImagick()
+ {
+ return $this->imagick;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function copy()
+ {
+ try {
+ if (version_compare(phpversion("imagick"), "3.1.0b1", ">=") || defined("HHVM_VERSION")) {
+ $clone = clone $this->imagick;
+ } else {
+ $clone = $this->imagick->clone();
+ }
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Copy operation failed', $e->getCode(), $e);
+ }
+
+ return new self($clone, $this->palette, clone $this->metadata);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function crop(PointInterface $start, BoxInterface $size)
+ {
+ if (!$start->in($this->getSize())) {
+ throw new OutOfBoundsException('Crop coordinates must start at minimum 0, 0 position from top left corner, crop height and width must be positive integers and must not exceed the current image borders');
+ }
+
+ try {
+ $this->imagick->cropImage($size->getWidth(), $size->getHeight(), $start->getX(), $start->getY());
+ // Reset canvas for gif format
+ $this->imagick->setImagePage(0, 0, 0, 0);
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Crop operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function flipHorizontally()
+ {
+ try {
+ $this->imagick->flopImage();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Horizontal Flip operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function flipVertically()
+ {
+ try {
+ $this->imagick->flipImage();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Vertical flip operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function strip()
+ {
+ try {
+ try {
+ $this->profile($this->palette->profile());
+ } catch (\Exception $e) {
+ // here we discard setting the profile as the previous incorporated profile
+ // is corrupted, let's now strip the image
+ }
+ $this->imagick->stripImage();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Strip operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function paste(ImageInterface $image, PointInterface $start)
+ {
+ if (!$image instanceof self) {
+ throw new InvalidArgumentException(sprintf('Imagick\Image can only paste() Imagick\Image instances, %s given', get_class($image)));
+ }
+
+ if (!$this->getSize()->contains($image->getSize(), $start)) {
+ throw new OutOfBoundsException('Cannot paste image of the given size at the specified position, as it moves outside of the current image\'s box');
+ }
+
+ try {
+ $this->imagick->compositeImage($image->imagick, \Imagick::COMPOSITE_DEFAULT, $start->getX(), $start->getY());
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Paste operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED)
+ {
+ try {
+ $this->imagick->resizeImage($size->getWidth(), $size->getHeight(), $this->getFilter($filter), 1);
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Resize operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function rotate($angle, ColorInterface $background = null)
+ {
+ $color = $background ? $background : $this->palette->color('fff');
+
+ try {
+ $pixel = $this->getColor($color);
+
+ $this->imagick->rotateimage($pixel, $angle);
+
+ $pixel->clear();
+ $pixel->destroy();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Rotate operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function save($path = null, array $options = array())
+ {
+ $path = null === $path ? $this->imagick->getImageFilename() : $path;
+ if (null === $path) {
+ throw new RuntimeException('You can omit save path only if image has been open from a file');
+ }
+
+ try {
+ $this->prepareOutput($options, $path);
+ $this->imagick->writeImages($path, true);
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Save operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function show($format, array $options = array())
+ {
+ header('Content-type: '.$this->getMimeType($format));
+ echo $this->get($format, $options);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($format, array $options = array())
+ {
+ try {
+ $options['format'] = $format;
+ $this->prepareOutput($options);
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Get operation failed', $e->getCode(), $e);
+ }
+
+ return $this->imagick->getImagesBlob();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function interlace($scheme)
+ {
+ static $supportedInterlaceSchemes = array(
+ ImageInterface::INTERLACE_NONE => \Imagick::INTERLACE_NO,
+ ImageInterface::INTERLACE_LINE => \Imagick::INTERLACE_LINE,
+ ImageInterface::INTERLACE_PLANE => \Imagick::INTERLACE_PLANE,
+ ImageInterface::INTERLACE_PARTITION => \Imagick::INTERLACE_PARTITION,
+ );
+
+ if (!array_key_exists($scheme, $supportedInterlaceSchemes)) {
+ throw new InvalidArgumentException('Unsupported interlace type');
+ }
+
+ $this->imagick->setInterlaceScheme($supportedInterlaceSchemes[$scheme]);
+
+ return $this;
+ }
+
+ /**
+ * @param array $options
+ * @param string $path
+ */
+ private function prepareOutput(array $options, $path = null)
+ {
+ if (isset($options['format'])) {
+ $this->imagick->setImageFormat($options['format']);
+ }
+
+ if (isset($options['animated']) && true === $options['animated']) {
+ $format = isset($options['format']) ? $options['format'] : 'gif';
+ $delay = isset($options['animated.delay']) ? $options['animated.delay'] : null;
+ $loops = isset($options['animated.loops']) ? $options['animated.loops'] : 0;
+
+ $options['flatten'] = false;
+
+ $this->layers->animate($format, $delay, $loops);
+ } else {
+ $this->layers->merge();
+ }
+ $this->applyImageOptions($this->imagick, $options, $path);
+
+ // flatten only if image has multiple layers
+ if ((!isset($options['flatten']) || $options['flatten'] === true) && count($this->layers) > 1) {
+ $this->flatten();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ return $this->get('png');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function draw()
+ {
+ return new Drawer($this->imagick);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function effects()
+ {
+ return new Effects($this->imagick);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ try {
+ $i = $this->imagick->getIteratorIndex();
+ $this->imagick->rewind();
+ $width = $this->imagick->getImageWidth();
+ $height = $this->imagick->getImageHeight();
+ $this->imagick->setIteratorIndex($i);
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Could not get size', $e->getCode(), $e);
+ }
+
+ return new Box($width, $height);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function applyMask(ImageInterface $mask)
+ {
+ if (!$mask instanceof self) {
+ throw new InvalidArgumentException('Can only apply instances of Imagine\Imagick\Image as masks');
+ }
+
+ $size = $this->getSize();
+ $maskSize = $mask->getSize();
+
+ if ($size != $maskSize) {
+ throw new InvalidArgumentException(sprintf('The given mask doesn\'t match current image\'s size, Current mask\'s dimensions are %s, while image\'s dimensions are %s', $maskSize, $size));
+ }
+
+ $mask = $mask->mask();
+ $mask->imagick->negateImage(true);
+
+ try {
+ // remove transparent areas of the original from the mask
+ $mask->imagick->compositeImage($this->imagick, \Imagick::COMPOSITE_DSTIN, 0, 0);
+ $this->imagick->compositeImage($mask->imagick, \Imagick::COMPOSITE_COPYOPACITY, 0, 0);
+
+ $mask->imagick->clear();
+ $mask->imagick->destroy();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Apply mask operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function mask()
+ {
+ $mask = $this->copy();
+
+ try {
+ $mask->imagick->modulateImage(100, 0, 100);
+ $mask->imagick->setImageMatte(false);
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Mask operation failed', $e->getCode(), $e);
+ }
+
+ return $mask;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return ImageInterface
+ */
+ public function fill(FillInterface $fill)
+ {
+ try {
+ if ($this->isLinearOpaque($fill)) {
+ $this->applyFastLinear($fill);
+ } else {
+ $iterator = $this->imagick->getPixelIterator();
+
+ foreach ($iterator as $y => $pixels) {
+ foreach ($pixels as $x => $pixel) {
+ $color = $fill->getColor(new Point($x, $y));
+
+ $pixel->setColor((string) $color);
+ $pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100);
+ }
+
+ $iterator->syncIterator();
+ }
+ }
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Fill operation failed', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function histogram()
+ {
+ try {
+ $pixels = $this->imagick->getImageHistogram();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Error while fetching histogram', $e->getCode(), $e);
+ }
+
+ $image = $this;
+
+ return array_map(function (\ImagickPixel $pixel) use ($image) {
+ return $image->pixelToColor($pixel);
+ },$pixels);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getColorAt(PointInterface $point)
+ {
+ if (!$point->in($this->getSize())) {
+ throw new RuntimeException(sprintf('Error getting color at point [%s,%s]. The point must be inside the image of size [%s,%s]', $point->getX(), $point->getY(), $this->getSize()->getWidth(), $this->getSize()->getHeight()));
+ }
+
+ try {
+ $pixel = $this->imagick->getImagePixelColor($point->getX(), $point->getY());
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Error while getting image pixel color', $e->getCode(), $e);
+ }
+
+ return $this->pixelToColor($pixel);
+ }
+
+ /**
+ * Returns a color given a pixel, depending the Palette context
+ *
+ * Note : this method is public for PHP 5.3 compatibility
+ *
+ * @param \ImagickPixel $pixel
+ *
+ * @return ColorInterface
+ *
+ * @throws InvalidArgumentException In case a unknown color is requested
+ */
+ public function pixelToColor(\ImagickPixel $pixel)
+ {
+ static $colorMapping = array(
+ ColorInterface::COLOR_RED => \Imagick::COLOR_RED,
+ ColorInterface::COLOR_GREEN => \Imagick::COLOR_GREEN,
+ ColorInterface::COLOR_BLUE => \Imagick::COLOR_BLUE,
+ ColorInterface::COLOR_CYAN => \Imagick::COLOR_CYAN,
+ ColorInterface::COLOR_MAGENTA => \Imagick::COLOR_MAGENTA,
+ ColorInterface::COLOR_YELLOW => \Imagick::COLOR_YELLOW,
+ ColorInterface::COLOR_KEYLINE => \Imagick::COLOR_BLACK,
+ // There is no gray component in \Imagick, let's use one of the RGB comp
+ ColorInterface::COLOR_GRAY => \Imagick::COLOR_RED,
+ );
+
+ $alpha = $this->palette->supportsAlpha() ? (int) round($pixel->getColorValue(\Imagick::COLOR_ALPHA) * 100) : null;
+ $palette = $this->palette();
+
+ return $this->palette->color(array_map(function ($color) use ($palette, $pixel, $colorMapping) {
+ if (!isset($colorMapping[$color])) {
+ throw new InvalidArgumentException(sprintf('Color %s is not mapped in Imagick', $color));
+ }
+ $multiplier = 255;
+ if ($palette->name() === PaletteInterface::PALETTE_CMYK) {
+ $multiplier = 100;
+ }
+
+ return $pixel->getColorValue($colorMapping[$color]) * $multiplier;
+ }, $this->palette->pixelDefinition()), $alpha);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function layers()
+ {
+ return $this->layers;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function usePalette(PaletteInterface $palette)
+ {
+ if (!isset(static::$colorspaceMapping[$palette->name()])) {
+ throw new InvalidArgumentException(sprintf('The palette %s is not supported by Imagick driver', $palette->name()));
+ }
+
+ if ($this->palette->name() === $palette->name()) {
+ return $this;
+ }
+
+ if (!static::$supportsColorspaceConversion) {
+ throw new RuntimeException('Your version of Imagick does not support colorspace conversions.');
+ }
+
+ try {
+ try {
+ $hasICCProfile = (Boolean) $this->imagick->getImageProfile('icc');
+ } catch (\ImagickException $e) {
+ $hasICCProfile = false;
+ }
+
+ if (!$hasICCProfile) {
+ $this->profile($this->palette->profile());
+ }
+
+ $this->profile($palette->profile());
+ $this->setColorspace($palette);
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Failed to set colorspace', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function palette()
+ {
+ return $this->palette;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function profile(ProfileInterface $profile)
+ {
+ try {
+ $this->imagick->profileImage('icc', $profile->data());
+ } catch (\ImagickException $e) {
+ throw new RuntimeException(sprintf('Unable to add profile %s to image', $profile->name()), $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Internal
+ *
+ * Flatten the image.
+ */
+ private function flatten()
+ {
+ /**
+ * @see https://github.com/mkoppanen/imagick/issues/45
+ */
+ try {
+ if (method_exists($this->imagick, 'mergeImageLayers') && defined('Imagick::LAYERMETHOD_UNDEFINED')) {
+ $this->imagick = $this->imagick->mergeImageLayers(\Imagick::LAYERMETHOD_UNDEFINED);
+ } elseif (method_exists($this->imagick, 'flattenImages')) {
+ $this->imagick = $this->imagick->flattenImages();
+ }
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Flatten operation failed', $e->getCode(), $e);
+ }
+ }
+
+ /**
+ * Internal
+ *
+ * Applies options before save or output
+ *
+ * @param \Imagick $image
+ * @param array $options
+ * @param string $path
+ *
+ * @throws InvalidArgumentException
+ * @throws RuntimeException
+ */
+ private function applyImageOptions(\Imagick $image, array $options, $path)
+ {
+ if (isset($options['format'])) {
+ $format = $options['format'];
+ } elseif ('' !== $extension = pathinfo($path, \PATHINFO_EXTENSION)) {
+ $format = $extension;
+ } else {
+ $format = pathinfo($image->getImageFilename(), \PATHINFO_EXTENSION);
+ }
+
+ $format = strtolower($format);
+
+ $options = $this->updateSaveOptions($options);
+
+ if (isset($options['jpeg_quality']) && in_array($format, array('jpeg', 'jpg', 'pjpeg'))) {
+ $image->setImageCompressionQuality($options['jpeg_quality']);
+ }
+
+ if ((isset($options['png_compression_level']) || isset($options['png_compression_filter'])) && $format === 'png') {
+ // first digit: compression level (default: 7)
+ if (isset($options['png_compression_level'])) {
+ if ($options['png_compression_level'] < 0 || $options['png_compression_level'] > 9) {
+ throw new InvalidArgumentException('png_compression_level option should be an integer from 0 to 9');
+ }
+ $compression = $options['png_compression_level'] * 10;
+ } else {
+ $compression = 70;
+ }
+
+ // second digit: compression filter (default: 5)
+ if (isset($options['png_compression_filter'])) {
+ if ($options['png_compression_filter'] < 0 || $options['png_compression_filter'] > 9) {
+ throw new InvalidArgumentException('png_compression_filter option should be an integer from 0 to 9');
+ }
+ $compression += $options['png_compression_filter'];
+ } else {
+ $compression += 5;
+ }
+
+ $image->setImageCompressionQuality($compression);
+ }
+
+ if (isset($options['resolution-units']) && isset($options['resolution-x']) && isset($options['resolution-y'])) {
+ if ($options['resolution-units'] == ImageInterface::RESOLUTION_PIXELSPERCENTIMETER) {
+ $image->setImageUnits(\Imagick::RESOLUTION_PIXELSPERCENTIMETER);
+ } elseif ($options['resolution-units'] == ImageInterface::RESOLUTION_PIXELSPERINCH) {
+ $image->setImageUnits(\Imagick::RESOLUTION_PIXELSPERINCH);
+ } else {
+ throw new RuntimeException('Unsupported image unit format');
+ }
+
+ $filter = ImageInterface::FILTER_UNDEFINED;
+ if (!empty($options['resampling-filter'])) {
+ $filter = $options['resampling-filter'];
+ }
+
+ $image->setImageResolution($options['resolution-x'], $options['resolution-y']);
+ $image->resampleImage($options['resolution-x'], $options['resolution-y'], $this->getFilter($filter), 0);
+ }
+ }
+
+ /**
+ * Gets specifically formatted color string from Color instance
+ *
+ * @param ColorInterface $color
+ *
+ * @return \ImagickPixel
+ */
+ private function getColor(ColorInterface $color)
+ {
+ $pixel = new \ImagickPixel((string) $color);
+ $pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100);
+
+ return $pixel;
+ }
+
+ /**
+ * Checks whether given $fill is linear and opaque
+ *
+ * @param FillInterface $fill
+ *
+ * @return Boolean
+ */
+ private function isLinearOpaque(FillInterface $fill)
+ {
+ return $fill instanceof Linear && $fill->getStart()->isOpaque() && $fill->getEnd()->isOpaque();
+ }
+
+ /**
+ * Performs optimized gradient fill for non-opaque linear gradients
+ *
+ * @param Linear $fill
+ */
+ private function applyFastLinear(Linear $fill)
+ {
+ $gradient = new \Imagick();
+ $size = $this->getSize();
+ $color = sprintf('gradient:%s-%s', (string) $fill->getStart(), (string) $fill->getEnd());
+
+ if ($fill instanceof Horizontal) {
+ $gradient->newPseudoImage($size->getHeight(), $size->getWidth(), $color);
+ $gradient->rotateImage(new \ImagickPixel(), 90);
+ } else {
+ $gradient->newPseudoImage($size->getWidth(), $size->getHeight(), $color);
+ }
+
+ $this->imagick->compositeImage($gradient, \Imagick::COMPOSITE_OVER, 0, 0);
+ $gradient->clear();
+ $gradient->destroy();
+ }
+
+ /**
+ * Internal
+ *
+ * Get the mime type based on format.
+ *
+ * @param string $format
+ *
+ * @return string mime-type
+ *
+ * @throws RuntimeException
+ */
+ private function getMimeType($format)
+ {
+ static $mimeTypes = array(
+ 'jpeg' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'gif' => 'image/gif',
+ 'png' => 'image/png',
+ 'wbmp' => 'image/vnd.wap.wbmp',
+ 'xbm' => 'image/xbm',
+ );
+
+ if (!isset($mimeTypes[$format])) {
+ throw new RuntimeException(sprintf('Unsupported format given. Only %s are supported, %s given', implode(", ", array_keys($mimeTypes)), $format));
+ }
+
+ return $mimeTypes[$format];
+ }
+
+ /**
+ * Sets colorspace and image type, assigns the palette.
+ *
+ * @param PaletteInterface $palette
+ *
+ * @throws InvalidArgumentException
+ */
+ private function setColorspace(PaletteInterface $palette)
+ {
+ static $typeMapping = array(
+ // We use Matte variants to preserve alpha
+ PaletteInterface::PALETTE_CMYK => \Imagick::IMGTYPE_TRUECOLORMATTE,
+ PaletteInterface::PALETTE_RGB => \Imagick::IMGTYPE_TRUECOLORMATTE,
+ PaletteInterface::PALETTE_GRAYSCALE => \Imagick::IMGTYPE_GRAYSCALEMATTE,
+ );
+
+ if (!isset(static::$colorspaceMapping[$palette->name()])) {
+ throw new InvalidArgumentException(sprintf('The palette %s is not supported by Imagick driver', $palette->name()));
+ }
+
+ $this->imagick->setType($typeMapping[$palette->name()]);
+ $this->imagick->setColorspace(static::$colorspaceMapping[$palette->name()]);
+ $this->palette = $palette;
+ }
+
+ /**
+ * Older imagemagick versions does not support colorspace conversions.
+ * Let's detect if it is supported.
+ *
+ * @return Boolean
+ */
+ private function detectColorspaceConversionSupport()
+ {
+ if (null !== static::$supportsColorspaceConversion) {
+ return static::$supportsColorspaceConversion;
+ }
+
+ return static::$supportsColorspaceConversion = method_exists('Imagick', 'setColorspace');
+ }
+
+ /**
+ * Returns the filter if it's supported.
+ *
+ * @param string $filter
+ *
+ * @return string
+ *
+ * @throws InvalidArgumentException If the filter is unsupported.
+ */
+ private function getFilter($filter = ImageInterface::FILTER_UNDEFINED)
+ {
+ static $supportedFilters = array(
+ ImageInterface::FILTER_UNDEFINED => \Imagick::FILTER_UNDEFINED,
+ ImageInterface::FILTER_BESSEL => \Imagick::FILTER_BESSEL,
+ ImageInterface::FILTER_BLACKMAN => \Imagick::FILTER_BLACKMAN,
+ ImageInterface::FILTER_BOX => \Imagick::FILTER_BOX,
+ ImageInterface::FILTER_CATROM => \Imagick::FILTER_CATROM,
+ ImageInterface::FILTER_CUBIC => \Imagick::FILTER_CUBIC,
+ ImageInterface::FILTER_GAUSSIAN => \Imagick::FILTER_GAUSSIAN,
+ ImageInterface::FILTER_HANNING => \Imagick::FILTER_HANNING,
+ ImageInterface::FILTER_HAMMING => \Imagick::FILTER_HAMMING,
+ ImageInterface::FILTER_HERMITE => \Imagick::FILTER_HERMITE,
+ ImageInterface::FILTER_LANCZOS => \Imagick::FILTER_LANCZOS,
+ ImageInterface::FILTER_MITCHELL => \Imagick::FILTER_MITCHELL,
+ ImageInterface::FILTER_POINT => \Imagick::FILTER_POINT,
+ ImageInterface::FILTER_QUADRATIC => \Imagick::FILTER_QUADRATIC,
+ ImageInterface::FILTER_SINC => \Imagick::FILTER_SINC,
+ ImageInterface::FILTER_TRIANGLE => \Imagick::FILTER_TRIANGLE
+ );
+
+ if (!array_key_exists($filter, $supportedFilters)) {
+ throw new InvalidArgumentException(sprintf(
+ 'The resampling filter "%s" is not supported by Imagick driver.',
+ $filter
+ ));
+ }
+
+ return $supportedFilters[$filter];
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Imagine.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Imagine.php
new file mode 100644
index 0000000..aa6e926
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Imagine.php
@@ -0,0 +1,176 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Imagick;
+
+use Imagine\Exception\NotSupportedException;
+use Imagine\Image\AbstractImagine;
+use Imagine\Image\BoxInterface;
+use Imagine\Image\Metadata\MetadataBag;
+use Imagine\Image\Palette\Color\ColorInterface;
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Exception\RuntimeException;
+use Imagine\Image\Palette\CMYK;
+use Imagine\Image\Palette\RGB;
+use Imagine\Image\Palette\Grayscale;
+
+/**
+ * Imagine implementation using the Imagick PHP extension
+ */
+final class Imagine extends AbstractImagine
+{
+ /**
+ * @throws RuntimeException
+ */
+ public function __construct()
+ {
+ if (!class_exists('Imagick')) {
+ throw new RuntimeException('Imagick not installed');
+ }
+
+ if (version_compare('6.2.9', $this->getVersion(new \Imagick())) > 0) {
+ throw new RuntimeException('ImageMagick version 6.2.9 or higher is required');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function open($path)
+ {
+ $path = $this->checkPath($path);
+
+ try {
+ $imagick = new \Imagick($path);
+ $image = new Image($imagick, $this->createPalette($imagick), $this->getMetadataReader()->readFile($path));
+ } catch (\Exception $e) {
+ throw new RuntimeException(sprintf('Unable to open image %s', $path), $e->getCode(), $e);
+ }
+
+ return $image;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function create(BoxInterface $size, ColorInterface $color = null)
+ {
+ $width = $size->getWidth();
+ $height = $size->getHeight();
+
+ $palette = null !== $color ? $color->getPalette() : new RGB();
+ $color = null !== $color ? $color : $palette->color('fff');
+
+ try {
+ $pixel = new \ImagickPixel((string) $color);
+ $pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100);
+
+ $imagick = new \Imagick();
+ $imagick->newImage($width, $height, $pixel);
+ $imagick->setImageMatte(true);
+ $imagick->setImageBackgroundColor($pixel);
+
+ if (version_compare('6.3.1', $this->getVersion($imagick)) < 0) {
+ $imagick->setImageOpacity($pixel->getColorValue(\Imagick::COLOR_ALPHA));
+ }
+
+ $pixel->clear();
+ $pixel->destroy();
+
+ return new Image($imagick, $palette, new MetadataBag());
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Could not create empty image', $e->getCode(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function load($string)
+ {
+ try {
+ $imagick = new \Imagick();
+
+ $imagick->readImageBlob($string);
+ $imagick->setImageMatte(true);
+
+ return new Image($imagick, $this->createPalette($imagick), $this->getMetadataReader()->readData($string));
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Could not load image from string', $e->getCode(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read($resource)
+ {
+ if (!is_resource($resource)) {
+ throw new InvalidArgumentException('Variable does not contain a stream resource');
+ }
+
+ try {
+ $imagick = new \Imagick();
+ $imagick->readImageFile($resource);
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Could not read image from resource', $e->getCode(), $e);
+ }
+
+ return new Image($imagick, $this->createPalette($imagick), $this->getMetadataReader()->readStream($resource));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function font($file, $size, ColorInterface $color)
+ {
+ return new Font(new \Imagick(), $file, $size, $color);
+ }
+
+ /**
+ * Returns the palette corresponding to an \Imagick resource colorspace
+ *
+ * @param \Imagick $imagick
+ *
+ * @return CMYK|Grayscale|RGB
+ *
+ * @throws NotSupportedException
+ */
+ private function createPalette(\Imagick $imagick)
+ {
+ switch ($imagick->getImageColorspace()) {
+ case \Imagick::COLORSPACE_RGB:
+ case \Imagick::COLORSPACE_SRGB:
+ return new RGB();
+ case \Imagick::COLORSPACE_CMYK:
+ return new CMYK();
+ case \Imagick::COLORSPACE_GRAY:
+ return new Grayscale();
+ default:
+ throw new NotSupportedException('Only RGB and CMYK colorspace are currently supported');
+ }
+ }
+
+ /**
+ * Returns ImageMagick version
+ *
+ * @param \Imagick $imagick
+ *
+ * @return string
+ */
+ private function getVersion(\Imagick $imagick)
+ {
+ $v = $imagick->getVersion();
+ list($version) = sscanf($v['versionString'], 'ImageMagick %s %04d-%02d-%02d %s %s');
+
+ return $version;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Layers.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Layers.php
new file mode 100644
index 0000000..7809447
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Imagine/Imagick/Layers.php
@@ -0,0 +1,271 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Imagine\Imagick;
+
+use Imagine\Image\AbstractLayers;
+use Imagine\Image\Metadata\MetadataBag;
+use Imagine\Exception\RuntimeException;
+use Imagine\Exception\OutOfBoundsException;
+use Imagine\Exception\InvalidArgumentException;
+use Imagine\Image\Palette\PaletteInterface;
+
+class Layers extends AbstractLayers
+{
+ /**
+ * @var Image
+ */
+ private $image;
+ /**
+ * @var \Imagick
+ */
+ private $resource;
+ /**
+ * @var integer
+ */
+ private $offset = 0;
+ /**
+ * @var array
+ */
+ private $layers = array();
+
+ private $palette;
+
+ public function __construct(Image $image, PaletteInterface $palette, \Imagick $resource)
+ {
+ $this->image = $image;
+ $this->resource = $resource;
+ $this->palette = $palette;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function merge()
+ {
+ foreach ($this->layers as $offset => $image) {
+ try {
+ $this->resource->setIteratorIndex($offset);
+ $this->resource->setImage($image->getImagick());
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Failed to substitute layer', $e->getCode(), $e);
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function animate($format, $delay, $loops)
+ {
+ if ('gif' !== strtolower($format)) {
+ throw new InvalidArgumentException('Animated picture is currently only supported on gif');
+ }
+
+ if (!is_int($loops) || $loops < 0) {
+ throw new InvalidArgumentException('Loops must be a positive integer.');
+ }
+
+ if (null !== $delay && (!is_int($delay) || $delay < 0)) {
+ throw new InvalidArgumentException('Delay must be either null or a positive integer.');
+ }
+
+ try {
+ foreach ($this as $offset => $layer) {
+ $this->resource->setIteratorIndex($offset);
+ $this->resource->setFormat($format);
+
+ if (null !== $delay) {
+ $layer->getImagick()->setImageDelay($delay / 10);
+ $layer->getImagick()->setImageTicksPerSecond(100);
+ }
+ $layer->getImagick()->setImageIterations($loops);
+
+ $this->resource->setImage($layer->getImagick());
+ }
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Failed to animate layers', $e->getCode(), $e);
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function coalesce()
+ {
+ try {
+ $coalescedResource = $this->resource->coalesceImages();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Failed to coalesce layers', $e->getCode(), $e);
+ }
+
+ $count = $coalescedResource->getNumberImages();
+ for ($offset = 0; $offset < $count; $offset++) {
+ try {
+ $coalescedResource->setIteratorIndex($offset);
+ $this->layers[$offset] = new Image($coalescedResource->getImage(), $this->palette, new MetadataBag());
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Failed to retrieve layer', $e->getCode(), $e);
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function current()
+ {
+ return $this->extractAt($this->offset);
+ }
+
+ /**
+ * Tries to extract layer at given offset
+ *
+ * @param integer $offset
+ *
+ * @return Image
+ * @throws RuntimeException
+ */
+ private function extractAt($offset)
+ {
+ if (!isset($this->layers[$offset])) {
+ try {
+ $this->resource->setIteratorIndex($offset);
+ $this->layers[$offset] = new Image($this->resource->getImage(), $this->palette, new MetadataBag());
+ } catch (\ImagickException $e) {
+ throw new RuntimeException(sprintf('Failed to extract layer %d', $offset), $e->getCode(), $e);
+ }
+ }
+
+ return $this->layers[$offset];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function key()
+ {
+ return $this->offset;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function next()
+ {
+ ++$this->offset;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function rewind()
+ {
+ $this->offset = 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function valid()
+ {
+ return $this->offset < count($this);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function count()
+ {
+ try {
+ return $this->resource->getNumberImages();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Failed to count the number of layers', $e->getCode(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetExists($offset)
+ {
+ return is_int($offset) && $offset >= 0 && $offset < count($this);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetGet($offset)
+ {
+ return $this->extractAt($offset);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetSet($offset, $image)
+ {
+ if (!$image instanceof Image) {
+ throw new InvalidArgumentException('Only an Imagick Image can be used as layer');
+ }
+
+ if (null === $offset) {
+ $offset = count($this) - 1;
+ } else {
+ if (!is_int($offset)) {
+ throw new InvalidArgumentException('Invalid offset for layer, it must be an integer');
+ }
+
+ if (count($this) < $offset || 0 > $offset) {
+ throw new OutOfBoundsException(sprintf('Invalid offset for layer, it must be a value between 0 and %d, %d given', count($this), $offset));
+ }
+
+ if (isset($this[$offset])) {
+ unset($this[$offset]);
+ $offset = $offset - 1;
+ }
+ }
+
+ $frame = $image->getImagick();
+
+ try {
+ if (count($this) > 0) {
+ $this->resource->setIteratorIndex($offset);
+ }
+ $this->resource->addImage($frame);
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Unable to set the layer', $e->getCode(), $e);
+ }
+
+ $this->layers = array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetUnset($offset)
+ {
+ try {
+ $this->extractAt($offset);
+ } catch (RuntimeException $e) {
+ return;
+ }
+
+ try {
+ $this->resource->setIteratorIndex($offset);
+ $this->resource->removeImage();
+ } catch (\ImagickException $e) {
+ throw new RuntimeException('Unable to remove layer', $e->getCode(), $e);
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/Collection.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/Collection.php
new file mode 100644
index 0000000..61dcbeb
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/Collection.php
@@ -0,0 +1,192 @@
+aItems = array();
+ }
+
+ /**
+ * @param mixed $mItem
+ * @param bool $bToTop = false
+ * @return self
+ */
+ public function Add($mItem, $bToTop = false)
+ {
+ if ($bToTop)
+ {
+ \array_unshift($this->aItems, $mItem);
+ }
+ else
+ {
+ \array_push($this->aItems, $mItem);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param array $aItems
+ * @return self
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function AddArray($aItems)
+ {
+ if (!\is_array($aItems))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ foreach ($aItems as $mItem)
+ {
+ $this->Add($mItem);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return self
+ */
+ public function Clear()
+ {
+ $this->aItems = array();
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function CloneAsArray()
+ {
+ return $this->aItems;
+ }
+
+ /**
+ * @return int
+ */
+ public function Count()
+ {
+ return \count($this->aItems);
+ }
+
+ /**
+ * @return array
+ */
+ public function &GetAsArray()
+ {
+ return $this->aItems;
+ }
+
+ /**
+ * @param mixed $mCallback
+ */
+ public function MapList($mCallback)
+ {
+ $aResult = array();
+ if (\is_callable($mCallback))
+ {
+ foreach ($this->aItems as $oItem)
+ {
+ $aResult[] = \call_user_func($mCallback, $oItem);
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param mixed $mCallback
+ * @return array
+ */
+ public function FilterList($mCallback)
+ {
+ $aResult = array();
+ if (\is_callable($mCallback))
+ {
+ foreach ($this->aItems as $oItem)
+ {
+ if (\call_user_func($mCallback, $oItem))
+ {
+ $aResult[] = $oItem;
+ }
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param mixed $mCallback
+ * @return void
+ */
+ public function ForeachList($mCallback)
+ {
+ if (\is_callable($mCallback))
+ {
+ foreach ($this->aItems as $oItem)
+ {
+ \call_user_func($mCallback, $oItem);
+ }
+ }
+ }
+
+ /**
+ * @return mixed | null
+ * @return mixed
+ */
+ public function &GetByIndex($iIndex)
+ {
+ $mResult = null;
+ if (\key_exists($iIndex, $this->aItems))
+ {
+ $mResult = $this->aItems[$iIndex];
+ }
+
+ return $mResult;
+ }
+
+ /**
+ * @param array $aItems
+ * @return self
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetAsArray($aItems)
+ {
+ if (!\is_array($aItems))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->aItems = $aItems;
+
+ return $this;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/Crypt.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/Crypt.php
new file mode 100644
index 0000000..3ef6fc5
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/Crypt.php
@@ -0,0 +1,189 @@
+> 2 & 3;
+ for ($iPIndex = 0; $iPIndex < $iN; $iPIndex++)
+ {
+ $iY = $aV[$iPIndex + 1];
+ $iMx = self::int32((($iZ >> 5 & 0x07ffffff) ^ $iY << 2) +
+ (($iY >> 3 & 0x1fffffff) ^ $iZ << 4)) ^ self::int32(($iSum ^ $iY) + ($aK[$iPIndex & 3 ^ $iE] ^ $iZ));
+ $iZ = $aV[$iPIndex] = self::int32($aV[$iPIndex] + $iMx);
+ }
+ $iY = $aV[0];
+ $iMx = self::int32((($iZ >> 5 & 0x07ffffff) ^ $iY << 2) +
+ (($iY >> 3 & 0x1fffffff) ^ $iZ << 4)) ^ self::int32(($iSum ^ $iY) + ($aK[$iPIndex & 3 ^ $iE] ^ $iZ));
+ $iZ = $aV[$iN] = self::int32($aV[$iN] + $iMx);
+ }
+
+ return self::long2str($aV, false);
+ }
+
+ /**
+ * @param string $sEncriptedString
+ * @param string $sKey
+ *
+ * @return string
+ */
+ public static function XxteaDecrypt($sEncriptedString, $sKey)
+ {
+ if (0 === \strlen($sEncriptedString))
+ {
+ return '';
+ }
+
+ $aV = self::str2long($sEncriptedString, false);
+ $aK = self::str2long($sKey, false);
+
+ if (\count($aK) < 4)
+ {
+ for ($iIndex = \count($aK); $iIndex < 4; $iIndex++)
+ {
+ $aK[$iIndex] = 0;
+ }
+ }
+
+ $iN = \count($aV) - 1;
+
+ $iZ = $aV[$iN];
+ $iY = $aV[0];
+ $iDelta = 0x9E3779B9;
+ $iQ = \floor(6 + 52 / ($iN + 1));
+ $iSum = self::int32($iQ * $iDelta);
+ while ($iSum != 0)
+ {
+ $iE = $iSum >> 2 & 3;
+ for ($iPIndex = $iN; $iPIndex > 0; $iPIndex--)
+ {
+ $iZ = $aV[$iPIndex - 1];
+ $iMx = self::int32((($iZ >> 5 & 0x07ffffff) ^ $iY << 2) +
+ (($iY >> 3 & 0x1fffffff) ^ $iZ << 4)) ^ self::int32(($iSum ^ $iY) + ($aK[$iPIndex & 3 ^ $iE] ^ $iZ));
+ $iY = $aV[$iPIndex] = self::int32($aV[$iPIndex] - $iMx);
+ }
+ $iZ = $aV[$iN];
+ $iMx = self::int32((($iZ >> 5 & 0x07ffffff) ^ $iY << 2) +
+ (($iY >> 3 & 0x1fffffff) ^ $iZ << 4)) ^ self::int32(($iSum ^ $iY) + ($aK[$iPIndex & 3 ^ $iE] ^ $iZ));
+ $iY = $aV[0] = self::int32($aV[0] - $iMx);
+ $iSum = self::int32($iSum - $iDelta);
+ }
+
+ return self::long2str($aV, true);
+ }
+
+ /**
+ * @param array $aV
+ * @param array $aW
+ *
+ * @return string
+ */
+ private static function long2str($aV, $aW)
+ {
+ $iLen = \count($aV);
+ $iN = ($iLen - 1) << 2;
+ if ($aW)
+ {
+ $iM = $aV[$iLen - 1];
+ if (($iM < $iN - 3) || ($iM > $iN))
+ {
+ return false;
+ }
+ $iN = $iM;
+ }
+ $aS = array();
+ for ($iIndex = 0; $iIndex < $iLen; $iIndex++)
+ {
+ $aS[$iIndex] = \pack('V', $aV[$iIndex]);
+ }
+ if ($aW)
+ {
+ return \substr(\join('', $aS), 0, $iN);
+ }
+ else
+ {
+ return \join('', $aS);
+ }
+ }
+
+ /**
+ * @param string $sS
+ * @param string $sW
+ *
+ * @return array
+ */
+ private static function str2long($sS, $sW)
+ {
+ $aV = \unpack('V*', $sS . \str_repeat("\0", (4 - \strlen($sS) % 4) & 3));
+ $aV = \array_values($aV);
+ if ($sW)
+ {
+ $aV[\count($aV)] = \strlen($sS);
+ }
+ return $aV;
+ }
+
+ /**
+ * @param int $iN
+ *
+ * @return int
+ */
+ private static function int32($iN)
+ {
+ while ($iN >= 2147483648)
+ {
+ $iN -= 4294967296;
+ }
+ while ($iN <= -2147483649)
+ {
+ $iN += 4294967296;
+ }
+ return (int) $iN;
+ }
+}
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/DateTimeHelper.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/DateTimeHelper.php
new file mode 100644
index 0000000..5ab334e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/DateTimeHelper.php
@@ -0,0 +1,123 @@
+getTimestamp() : 0;
+ }
+
+ /**
+ * Parse date string formated as "10-Jan-2012 01:58:17 -0800"
+ * IMAP INTERNALDATE Format
+ *
+ * @param string $sDateTime
+ *
+ * @return int
+ */
+ public static function ParseInternalDateString($sDateTime)
+ {
+ $sDateTime = \trim($sDateTime);
+ if (empty($sDateTime))
+ {
+ return 0;
+ }
+
+ if (\preg_match('/^[a-z]{2,4}, /i', $sDateTime)) // RFC2822 ~ "Thu, 10 Jun 2010 08:58:33 -0700 (PDT)"
+ {
+ return \MailSo\Base\DateTimeHelper::ParseRFC2822DateString($sDateTime);
+ }
+
+ $oDateTime = \DateTime::createFromFormat('d-M-Y H:i:s O', $sDateTime, \MailSo\Base\DateTimeHelper::GetUtcTimeZoneObject());
+ return $oDateTime ? $oDateTime->getTimestamp() : 0;
+ }
+
+ /**
+ * Parse date string formated as "2011-06-14 23:59:59 +0400"
+ *
+ * @param string $sDateTime
+ *
+ * @return int
+ */
+ public static function ParseDateStringType1($sDateTime)
+ {
+ $sDateTime = \trim($sDateTime);
+ if (empty($sDateTime))
+ {
+ return 0;
+ }
+
+ $oDateTime = \DateTime::createFromFormat('Y-m-d H:i:s O', $sDateTime, \MailSo\Base\DateTimeHelper::GetUtcTimeZoneObject());
+ return $oDateTime ? $oDateTime->getTimestamp() : 0;
+ }
+
+ /**
+ * Parse date string formated as "2015-05-08T14:32:18.483-07:00"
+ *
+ * @param string $sDateTime
+ *
+ * @return int
+ */
+ public static function TryToParseSpecEtagFormat($sDateTime)
+ {
+ $sDateTime = \trim(\preg_replace('/ \([a-zA-Z0-9]+\)$/', '', \trim($sDateTime)));
+ $sDateTime = \trim(\preg_replace('/(:[\d]{2})\.[\d]{3}/', '$1', \trim($sDateTime)));
+ $sDateTime = \trim(\preg_replace('/(-[\d]{2})T([\d]{2}:)/', '$1 $2', \trim($sDateTime)));
+ $sDateTime = \trim(\preg_replace('/([\-+][\d]{2}):([\d]{2})$/', ' $1$2', \trim($sDateTime)));
+
+ return \MailSo\Base\DateTimeHelper::ParseDateStringType1($sDateTime);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/Enumerations/Charset.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/Enumerations/Charset.php
new file mode 100644
index 0000000..85132e6
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/Enumerations/Charset.php
@@ -0,0 +1,38 @@
+getFile()).' ~ '.$this->getLine().')' : $sMessage;
+
+ parent::__construct($sMessage, $iCode, $oPrevious);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/Exceptions/InvalidArgumentException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/Exceptions/InvalidArgumentException.php
new file mode 100644
index 0000000..a366b63
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/Exceptions/InvalidArgumentException.php
@@ -0,0 +1,19 @@
+encoding = 'UTF-8';
+ $oDom->strictErrorChecking = false;
+ $oDom->formatOutput = false;
+
+ @$oDom->loadHTML('<'.'?xml version="1.0" encoding="utf-8"?'.'>'.
+ ' '.$sText.'');
+
+ @$oDom->normalizeDocument();
+
+ if (\MailSo\Base\Utils::FunctionExistsAndEnabled('libxml_use_internal_errors'))
+ {
+ @\libxml_clear_errors();
+ }
+
+ if (\MailSo\Base\Utils::FunctionExistsAndEnabled('libxml_use_internal_errors'))
+ {
+ \libxml_use_internal_errors($bState);
+ }
+
+ return $oDom;
+ }
+
+ /**
+ * @param string $sHtml
+ * @param string $sHtmlAttrs = '
+ * @param string $sBodyAttrs = ''
+ *
+ * @return string
+ */
+ public static function ClearBodyAndHtmlTag($sHtml, &$sHtmlAttrs = '', &$sBodyAttrs = '')
+ {
+ $aMatch = array();
+ if (\preg_match('/]+)>/im', $sHtml, $aMatch) && !empty($aMatch[1]))
+ {
+ $sHtmlAttrs = $aMatch[1];
+ }
+
+ $aMatch = array();
+ if (\preg_match('/]+)>/im', $sHtml, $aMatch) && !empty($aMatch[1]))
+ {
+ $sBodyAttrs = $aMatch[1];
+ }
+
+ $sHtml = \preg_replace('/]*)>/im', '', $sHtml);
+ $sHtml = \preg_replace('/<\/body>/im', '', $sHtml);
+ $sHtml = \preg_replace('/]*)>/im', '', $sHtml);
+ $sHtml = \preg_replace('/<\/html>/im', '', $sHtml);
+
+ $sHtmlAttrs = \preg_replace('/xmlns:[a-z]="[^"]*"/im', '', $sHtmlAttrs);
+ $sHtmlAttrs = \preg_replace('/xmlns="[^"]*"/im', '', $sHtmlAttrs);
+ $sBodyAttrs = \preg_replace('/xmlns:[a-z]="[^"]*"/im', '', $sBodyAttrs);
+
+ return $sHtml;
+ }
+
+ /**
+ * @param string $sHtml
+ * @param bool $bClearEmpty = true
+ *
+ * @return string
+ */
+ public static function FixSchemas($sHtml, $bClearEmpty = true)
+ {
+ if ($bClearEmpty)
+ {
+ $sHtml = \str_replace(' ', '', $sHtml);
+ }
+
+ $sHtml = \str_replace('', '', $sHtml);
+ $sHtml = \str_replace(' ', ' ', $sHtml);
+
+ return $sHtml;
+ }
+
+ /**
+ * @param string $sHtml
+ * @param bool $bClearStyleAndHead = true
+ *
+ * @return string
+ */
+ public static function ClearTags($sHtml, $bClearStyleAndHead = true)
+ {
+ $aRemoveTags = array(
+ 'link', 'base', 'meta', 'title', 'script', 'bgsound', 'keygen', 'source',
+ 'object', 'embed', 'applet', 'mocha', 'iframe', 'frame', 'frameset', 'video', 'audio', 'area', 'map'
+ );
+
+ if ($bClearStyleAndHead)
+ {
+ $aRemoveTags[] = 'head';
+ $aRemoveTags[] = 'style';
+ }
+
+ $aToRemove = array(
+ '/]*><\/p>/i',
+ '/]*>/msi',
+ '/<\?xml [^>]*\?>/msi'
+ );
+
+ foreach ($aRemoveTags as $sTag)
+ {
+ $aToRemove[] = '\'<'.$sTag.'[^>]*>.*?[\s]*'.$sTag.'>\'msi';
+ $aToRemove[] = '\'<'.$sTag.'[^>]*>\'msi';
+ $aToRemove[] = '\'[\s]*'.$sTag.'[^>]*>\'msi';
+ }
+
+ return \preg_replace($aToRemove, '', $sHtml);
+ }
+
+ /**
+ * @param string $sHtml
+ *
+ * @return string
+ */
+ public static function ClearOn($sHtml)
+ {
+ $aToReplace = array(
+ '/on(Blur)/si',
+ '/on(Change)/si',
+ '/on(Click)/si',
+ '/on(DblClick)/si',
+ '/on(Error)/si',
+ '/on(Focus)/si',
+ '/on(FormChange)/si',
+ '/on(KeyDown)/si',
+ '/on(KeyPress)/si',
+ '/on(KeyUp)/si',
+ '/on(Load)/si',
+ '/on(MouseDown)/si',
+ '/on(MouseEnter)/si',
+ '/on(MouseLeave)/si',
+ '/on(MouseMove)/si',
+ '/on(MouseOut)/si',
+ '/on(MouseOver)/si',
+ '/on(MouseUp)/si',
+ '/on(Move)/si',
+ '/on(Resize)/si',
+ '/on(ResizeEnd)/si',
+ '/on(ResizeStart)/si',
+ '/on(Scroll)/si',
+ '/on(Select)/si',
+ '/on(Submit)/si',
+ '/on(Unload)/si'
+ );
+
+ return \preg_replace($aToReplace, 'оn\\1', $sHtml);
+ }
+
+// public static function ClearStyleUrlValueParserHelper($oUrlValue, $oRule, $oRuleSet,
+// $oElem = null,
+// &$bHasExternals = false, &$aFoundCIDs = array(),
+// $aContentLocationUrls = array(), &$aFoundedContentLocationUrls = array(),
+// $bDoNotReplaceExternalUrl = false, $fAdditionalExternalFilter = null
+// )
+// {
+// if ($oUrlValue instanceof \Sabberworm\CSS\Value\URL)
+// {
+// $oNewRule = new \Sabberworm\CSS\Rule\Rule('x-rl-orig-'.$oRule->getRule());
+// $oNewRule->setValue((string) $oRule->getValue());
+// $oNewRule->setIsImportant($oRule->getIsImportant());
+//
+// $oRuleSet->addRule($oNewRule);
+//
+// $oUrl = $oUrlValue->getURL();
+// $sUrl = $oUrl ? $oUrl->getString() : '';
+//
+// if ('cid:' === \strtolower(\substr($sUrl, 0, 4)))
+// {
+// $aFoundCIDs[] = \substr($sUrl, 4);
+//
+// $oRule->setRule('x-rl-mod-'.$oRule->getRule());
+//
+// if ($oElem)
+// {
+// $oElem->setAttribute('data-x-style-mod', '1');
+// }
+// }
+// else
+// {
+// if (\preg_match('/http[s]?:\/\//i', $sUrl) || '//' === \substr($sUrl, 0, 2))
+// {
+// $oRule->setRule('x-rl-mod-'.$oRule->getRule());
+//
+// if (\in_array($sUrl, $aContentLocationUrls))
+// {
+// $aFoundedContentLocationUrls[] = $sUrl;
+// }
+// else
+// {
+// $bHasExternals = true;
+// if (!$bDoNotReplaceExternalUrl)
+// {
+// if ($fAdditionalExternalFilter)
+// {
+// $sAdditionalResult = \call_user_func($fAdditionalExternalFilter, $sUrl);
+// if (0 < \strlen($sAdditionalResult) && $oUrl)
+// {
+// $oUrl->setString($sAdditionalResult);
+// }
+// }
+// }
+// }
+//
+// if ($oElem)
+// {
+// $oElem->setAttribute('data-x-style-mod', '1');
+// }
+// }
+// else if ('data:image/' !== \strtolower(\substr(\trim($sUrl), 0, 11)))
+// {
+// $oRuleSet->removeRule($oRule);
+// }
+// }
+// }
+// else if ($oRule instanceof \Sabberworm\CSS\Rule\Rule)
+// {
+// if ('x-rl-' !== \substr($oRule->getRule(), 0, 5))
+// {
+// $oValue = $oRule->getValue();
+// if ($oValue instanceof \Sabberworm\CSS\Value\URL)
+// {
+// \MailSo\Base\HtmlUtils::ClearStyleUrlValueParserHelper($oValue, $oRule, $oRuleSet, $oElem,
+// $bHasExternals, $aFoundCIDs,
+// $aContentLocationUrls, $aFoundedContentLocationUrls,
+// $bDoNotReplaceExternalUrl, $fAdditionalExternalFilter);
+// }
+// else if ($oValue instanceof \Sabberworm\CSS\Value\RuleValueList)
+// {
+// $aComps = $oValue->getListComponents();
+// foreach ($aComps as $oValue)
+// {
+// if ($oValue instanceof \Sabberworm\CSS\Value\URL)
+// {
+// \MailSo\Base\HtmlUtils::ClearStyleUrlValueParserHelper($oValue, $oRule, $oRuleSet, $oElem,
+// $bHasExternals, $aFoundCIDs,
+// $aContentLocationUrls, $aFoundedContentLocationUrls,
+// $bDoNotReplaceExternalUrl, $fAdditionalExternalFilter);
+// }
+// }
+// }
+// }
+// }
+// }
+//
+// public static function ClearStyleSmart($sStyle, $oElement = null,
+// &$bHasExternals = false, &$aFoundCIDs = array(),
+// $aContentLocationUrls = array(), &$aFoundedContentLocationUrls = array(),
+// $bDoNotReplaceExternalUrl = false, $fAdditionalExternalFilter = null,
+// $sSelectorPrefix = '')
+// {
+// $mResult = false;
+// $oCss = null;
+//
+// if (!\class_exists('Sabberworm\CSS\Parser'))
+// {
+// return $mResult;
+// }
+//
+// $sStyle = \trim($sStyle);
+// if (empty($sStyle))
+// {
+// return '';
+// }
+//
+// $sStyle = \trim(\preg_replace('/[\r\n\t\s]+/', ' ', $sStyle));
+//
+// try
+// {
+// $oSettings = \Sabberworm\CSS\Settings::create();
+// $oSettings->beStrict();
+// $oSettings->withMultibyteSupport(false);
+//
+// $oCssParser = new \Sabberworm\CSS\Parser($sStyle, $oSettings);
+// $oCss = $oCssParser->parse();
+// }
+// catch (\Exception $oEception)
+// {
+// unset($oEception);
+// $mResult = false;
+// }
+//
+// if ($oCss)
+// {
+// foreach ($oCss->getAllDeclarationBlocks() as $oBlock)
+// {
+// foreach($oBlock->getSelectors() as $oSelector)
+// {
+// $sS = ' '.\trim($oSelector->getSelector()).' ';
+// $sS = \preg_replace('/ body([\.# ])/i', ' [data-x-div-type="body"]$1', $sS);
+// $sS = \preg_replace('/ html([\.# ])/i', ' [data-x-div-type="html"]$1', $sS);
+//
+// if (0 < \strlen($sSelectorPrefix))
+// {
+// $sS = \trim($sSelectorPrefix.' '.\trim($sS));
+// }
+//
+// $oSelector->setSelector(\trim($sS));
+// }
+// }
+//
+// $aRulesToRemove = array(
+// 'pointer-events', 'content', 'behavior', 'cursor',
+// );
+//
+// foreach($oCss->getAllRuleSets() as $oRuleSet)
+// {
+// foreach ($aRulesToRemove as $sRuleToRemove)
+// {
+// $oRuleSet->removeRule($sRuleToRemove);
+// }
+//
+// // position: fixed -> position: fixed -> absolute
+// $aRules = $oRuleSet->getRules('position');
+// if (\is_array($aRules))
+// {
+// foreach ($aRules as $oRule)
+// {
+// $mValue = $oRule->getValue();
+// if (\is_string($mValue) && 'fixed' === \trim(\strtolower($mValue)))
+// {
+// $oRule->setValue('absolute');
+// }
+// }
+// }
+// }
+//
+// foreach($oCss->getAllDeclarationBlocks() as $oRuleSet)
+// {
+// if ($oRuleSet instanceof \Sabberworm\CSS\RuleSet\RuleSet)
+// {
+// if ($oRuleSet instanceof \Sabberworm\CSS\RuleSet\DeclarationBlock)
+// {
+// $oRuleSet->expandBackgroundShorthand();
+// $oRuleSet->expandListStyleShorthand();
+// }
+//
+// $aRules = $oRuleSet->getRules();
+// if (\is_array($aRules) && 0 < \count($aRules))
+// {
+// foreach ($aRules as $oRule)
+// {
+// if ($oRule instanceof \Sabberworm\CSS\Rule\Rule)
+// {
+// \MailSo\Base\HtmlUtils::ClearStyleUrlValueParserHelper(null, $oRule, $oRuleSet,
+// $oElement,
+// $bHasExternals, $aFoundCIDs,
+// $aContentLocationUrls, $aFoundedContentLocationUrls,
+// $bDoNotReplaceExternalUrl, $fAdditionalExternalFilter
+// );
+// }
+// }
+// }
+// }
+// }
+//
+// try
+// {
+// $mResult = $oCss->render(\Sabberworm\CSS\OutputFormat::createCompact());
+// }
+// catch (\Exception $oEception)
+// {
+// unset($oEception);
+// $mResult = false;
+// }
+// }
+//
+// return $mResult;
+// }
+
+ /**
+ *
+ * @param string $sStyle
+ * @param \DOMElement $oElement
+ * @param bool $bHasExternals
+ * @param array $aFoundCIDs
+ * @param array $aContentLocationUrls
+ * @param array $aFoundedContentLocationUrls
+ * @param bool $bDoNotReplaceExternalUrl = false
+ * @param callback|null $fAdditionalExternalFilter = null
+ *
+ * @return string
+ */
+ public static function ClearStyle($sStyle, $oElement, &$bHasExternals, &$aFoundCIDs,
+ $aContentLocationUrls, &$aFoundedContentLocationUrls, $bDoNotReplaceExternalUrl = false, $fAdditionalExternalFilter = null)
+ {
+ $sStyle = \trim($sStyle);
+ $aOutStyles = array();
+ $aStyles = \explode(';', $sStyle);
+
+ if ($fAdditionalExternalFilter && !\is_callable($fAdditionalExternalFilter))
+ {
+ $fAdditionalExternalFilter = null;
+ }
+
+ $aMatch = array();
+ foreach ($aStyles as $sStyleItem)
+ {
+ $aStyleValue = \explode(':', $sStyleItem, 2);
+ $sName = \trim(\strtolower($aStyleValue[0]));
+ $sValue = isset($aStyleValue[1]) ? \trim($aStyleValue[1]) : '';
+
+ if ('position' === $sName && 'fixed' === \strtolower($sValue))
+ {
+ $sValue = 'absolute';
+ }
+
+ if (0 === \strlen($sName) || 0 === \strlen($sValue))
+ {
+ continue;
+ }
+
+ $sStyleItem = $sName.': '.$sValue;
+ $aStyleValue = array($sName, $sValue);
+
+ /*if (\in_array($sName, array('position', 'left', 'right', 'top', 'bottom', 'behavior', 'cursor')))
+ {
+ // skip
+ }
+ else */if (\in_array($sName, array('behavior', 'pointer-events')) ||
+ ('cursor' === $sName && !\in_array(\strtolower($sValue), array('none', 'cursor'))) ||
+ ('display' === $sName && 'none' === \strtolower($sValue)) ||
+ \preg_match('/expression/i', $sValue) ||
+ ('text-indent' === $sName && '-' === \substr(trim($sValue), 0, 1))
+ )
+ {
+ // skip
+ }
+ else if (\in_array($sName, array('background-image', 'background', 'list-style', 'list-style-image', 'content'))
+ && \preg_match('/url[\s]?\(([^)]+)\)/im', $sValue, $aMatch) && !empty($aMatch[1]))
+ {
+ $sFullUrl = \trim($aMatch[0], '"\' ');
+ $sUrl = \trim($aMatch[1], '"\' ');
+ $sStyleValue = \trim(\preg_replace('/[\s]+/', ' ', \str_replace($sFullUrl, '', $sValue)));
+ $sStyleItem = empty($sStyleValue) ? '' : $sName.': '.$sStyleValue;
+
+ if ('cid:' === \strtolower(\substr($sUrl, 0, 4)))
+ {
+ if ($oElement)
+ {
+ $oElement->setAttribute('data-x-style-cid-name',
+ 'background' === $sName ? 'background-image' : $sName);
+
+ $oElement->setAttribute('data-x-style-cid', \substr($sUrl, 4));
+
+ $aFoundCIDs[] = \substr($sUrl, 4);
+ }
+ }
+ else
+ {
+ if ($oElement)
+ {
+ if (\preg_match('/http[s]?:\/\//i', $sUrl) || '//' === \substr($sUrl, 0, 2))
+ {
+ $bHasExternals = true;
+ if (!$bDoNotReplaceExternalUrl)
+ {
+ if (\in_array($sName, array('background-image', 'list-style-image', 'content')))
+ {
+ $sStyleItem = '';
+ }
+
+ $sTemp = '';
+ if ($oElement->hasAttribute('data-x-style-url'))
+ {
+ $sTemp = \trim($oElement->getAttribute('data-x-style-url'));
+ }
+
+ $sTemp = empty($sTemp) ? '' : (';' === \substr($sTemp, -1) ? $sTemp.' ' : $sTemp.'; ');
+
+ $oElement->setAttribute('data-x-style-url', \trim($sTemp.
+ ('background' === $sName ? 'background-image' : $sName).': '.$sFullUrl, ' ;'));
+
+ if ($fAdditionalExternalFilter)
+ {
+ $sAdditionalResult = \call_user_func($fAdditionalExternalFilter, $sUrl);
+ if (0 < \strlen($sAdditionalResult))
+ {
+ $oElement->setAttribute('data-x-additional-style-url',
+ ('background' === $sName ? 'background-image' : $sName).': url('.$sAdditionalResult.')');
+ }
+ }
+ }
+ }
+ else if ('data:image/' !== \strtolower(\substr(\trim($sUrl), 0, 11)))
+ {
+ $oElement->setAttribute('data-x-broken-style-src', $sFullUrl);
+ }
+ }
+ }
+
+ if (!empty($sStyleItem))
+ {
+ $aOutStyles[] = $sStyleItem;
+ }
+ }
+ else if ('height' === $sName)
+ {
+// $aOutStyles[] = 'min-'.ltrim($sStyleItem);
+ $aOutStyles[] = $sStyleItem;
+ }
+ else
+ {
+ $aOutStyles[] = $sStyleItem;
+ }
+ }
+
+ return \implode(';', $aOutStyles);
+ }
+
+ /**
+ * @param \DOMDocument $oDom
+ */
+ public static function FindLinksInDOM(&$oDom)
+ {
+ $aNodes = $oDom->getElementsByTagName('*');
+ foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement)
+ {
+ $sTagNameLower = \strtolower($oElement->tagName);
+ $sParentTagNameLower = isset($oElement->parentNode) && isset($oElement->parentNode->tagName) ?
+ \strtolower($oElement->parentNode->tagName) : '';
+
+ if (!\in_array($sTagNameLower, array('html', 'meta', 'head', 'style', 'script', 'img', 'button', 'input', 'textarea', 'a')) &&
+ 'a' !== $sParentTagNameLower && $oElement->childNodes && 0 < $oElement->childNodes->length)
+ {
+ $oSubItem = null;
+ $aTextNodes = array();
+ $iIndex = $oElement->childNodes->length - 1;
+ while ($iIndex > -1)
+ {
+ $oSubItem = $oElement->childNodes->item($iIndex);
+ if ($oSubItem && XML_TEXT_NODE === $oSubItem->nodeType)
+ {
+ $aTextNodes[] = $oSubItem;
+ }
+
+ $iIndex--;
+ }
+
+ unset($oSubItem);
+
+ foreach ($aTextNodes as $oTextNode)
+ {
+ if ($oTextNode && 0 < \strlen($oTextNode->wholeText)/* && \preg_match('/http[s]?:\/\//i', $oTextNode->wholeText)*/)
+ {
+ $sText = \MailSo\Base\LinkFinder::NewInstance()
+ ->Text($oTextNode->wholeText)
+ ->UseDefaultWrappers(true)
+ ->CompileText()
+ ;
+
+ $oSubDom = \MailSo\Base\HtmlUtils::GetDomFromText('
'.$sText.'');
+ if ($oSubDom)
+ {
+ $oBodyNodes = $oSubDom->getElementsByTagName('body');
+ if ($oBodyNodes && 0 < $oBodyNodes->length)
+ {
+ $oBodyChildNodes = $oBodyNodes->item(0)->childNodes;
+ if ($oBodyChildNodes && $oBodyChildNodes->length)
+ {
+ for ($iIndex = 0, $iLen = $oBodyChildNodes->length; $iIndex < $iLen; $iIndex++)
+ {
+ $oSubItem = $oBodyChildNodes->item($iIndex);
+ if ($oSubItem)
+ {
+ if (XML_ELEMENT_NODE === $oSubItem->nodeType &&
+ 'a' === \strtolower($oSubItem->tagName))
+ {
+ $oLink = $oDom->createElement('a',
+ \str_replace(':', \MailSo\Base\HtmlUtils::$KOS, \htmlspecialchars($oSubItem->nodeValue)));
+
+ $sHref = $oSubItem->getAttribute('href');
+ if ($sHref)
+ {
+ $oLink->setAttribute('href', $sHref);
+ }
+
+ $oElement->insertBefore($oLink, $oTextNode);
+ }
+ else
+ {
+ $oElement->insertBefore($oDom->importNode($oSubItem), $oTextNode);
+ }
+ }
+ }
+
+ $oElement->removeChild($oTextNode);
+ }
+ }
+
+ unset($oBodyNodes);
+ }
+
+ unset($oSubDom, $sText);
+ }
+ }
+ }
+ }
+
+ unset($aNodes);
+ }
+
+ /**
+ * @param string $sHtml
+ * @param bool $bDoNotReplaceExternalUrl = false
+ * @param bool $bFindLinksInHtml = false
+ *
+ * @return string
+ */
+ public static function ClearHtmlSimple($sHtml, $bDoNotReplaceExternalUrl = false, $bFindLinksInHtml = false)
+ {
+ $bHasExternals = false;
+ $aFoundCIDs = array();
+ $aContentLocationUrls = array();
+ $aFoundedContentLocationUrls = array();
+
+ return \MailSo\Base\HtmlUtils::ClearHtml($sHtml, $bHasExternals, $aFoundCIDs,
+ $aContentLocationUrls, $aFoundedContentLocationUrls, $bDoNotReplaceExternalUrl, $bFindLinksInHtml);
+ }
+
+ /**
+ * @param string $sHtml
+ * @param bool $bHasExternals = false
+ * @param array $aFoundCIDs = array()
+ * @param array $aContentLocationUrls = array()
+ * @param array $aFoundedContentLocationUrls = array()
+ * @param bool $bDoNotReplaceExternalUrl = false
+ * @param bool $bFindLinksInHtml = false
+ * @param callback|null $fAdditionalExternalFilter = null
+ * @param callback|null $fAdditionalDomReader = null
+ *
+ * @return string
+ */
+ public static function ClearHtml($sHtml, &$bHasExternals = false, &$aFoundCIDs = array(),
+ $aContentLocationUrls = array(), &$aFoundedContentLocationUrls = array(),
+ $bDoNotReplaceExternalUrl = false, $bFindLinksInHtml = false,
+ $fAdditionalExternalFilter = null, $fAdditionalDomReader = false,
+ $bTryToDetectHiddenImages = false)
+ {
+ $sResult = '';
+
+ $sHtml = null === $sHtml ? '' : (string) $sHtml;
+ $sHtml = \trim($sHtml);
+ if (0 === \strlen($sHtml))
+ {
+ return '';
+ }
+
+ if ($fAdditionalExternalFilter && !\is_callable($fAdditionalExternalFilter))
+ {
+ $fAdditionalExternalFilter = null;
+ }
+
+ if ($fAdditionalDomReader && !\is_callable($fAdditionalDomReader))
+ {
+ $fAdditionalDomReader = null;
+ }
+
+ $bHasExternals = false;
+
+ $sHtml = \MailSo\Base\HtmlUtils::FixSchemas($sHtml);
+
+ $sHtml = \MailSo\Base\HtmlUtils::ClearTags($sHtml, false);
+ $sHtml = \MailSo\Base\HtmlUtils::ClearOn($sHtml);
+
+ $sHtmlAttrs = $sBodyAttrs = '';
+ $sHtml = \MailSo\Base\HtmlUtils::ClearBodyAndHtmlTag($sHtml, $sHtmlAttrs, $sBodyAttrs);
+
+ // Dom Part
+ $oDom = \MailSo\Base\HtmlUtils::GetDomFromText($sHtml, $sHtmlAttrs, $sBodyAttrs);
+ unset($sHtml);
+
+ if ($oDom)
+ {
+ if ($fAdditionalDomReader)
+ {
+ $oResDom = \call_user_func($fAdditionalDomReader, $oDom);
+ if ($oResDom)
+ {
+ $oDom = $oResDom;
+ }
+
+ unset($oResDom);
+ }
+
+ if ($bFindLinksInHtml)
+ {
+ \MailSo\Base\HtmlUtils::FindLinksInDOM($oDom);
+ }
+
+ $oXpath = new \DOMXpath($oDom);
+ $oComments = $oXpath->query('//comment()');
+ if ($oComments)
+ {
+ foreach ($oComments as $oComment)
+ {
+ if (isset($oComment->parentNode))
+ {
+ @$oComment->parentNode->removeChild($oComment);
+ }
+ }
+ }
+
+ unset($oXpath, $oComments);
+
+ $aNodes = $oDom->getElementsByTagName('*');
+ foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement)
+ {
+ if ($oElement)
+ {
+ $sTagNameLower = \strtolower($oElement->tagName);
+
+ if ('' !== $sTagNameLower && \in_array($sTagNameLower, array('svg', 'head', 'link',
+ 'base', 'meta', 'title', 'style', 'x-script', 'script', 'bgsound', 'keygen', 'source',
+ 'object', 'embed', 'applet', 'mocha', 'iframe', 'frame', 'frameset',
+ 'video', 'audio', 'area', 'map')))
+ {
+ if (isset($oElement->parentNode))
+ {
+ @$oElement->parentNode->removeChild($oElement);
+ }
+ }
+ }
+ }
+
+ $sLinkColor = '';
+ $aNodes = $oDom->getElementsByTagName('*');
+ foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement)
+ {
+ $sTagNameLower = \strtolower($oElement->tagName);
+
+ // convert body attributes to styles
+ if ('body' === $sTagNameLower)
+ {
+ $aAttrs = array(
+ 'link' => '',
+ 'text' => '',
+ 'topmargin' => '',
+ 'leftmargin' => '',
+ 'bottommargin' => '',
+ 'rightmargin' => ''
+ );
+
+ if (isset($oElement->attributes))
+ {
+ foreach ($oElement->attributes as $sAttributeName => /* @var $oAttributeNode \DOMNode */ $oAttributeNode)
+ {
+ if ($oAttributeNode && isset($oAttributeNode->nodeValue))
+ {
+ $sAttributeNameLower = \strtolower($sAttributeName);
+ if (isset($aAttrs[$sAttributeNameLower]) && '' === $aAttrs[$sAttributeNameLower])
+ {
+ $aAttrs[$sAttributeNameLower] = array($sAttributeName, \trim($oAttributeNode->nodeValue));
+ }
+ }
+ }
+ }
+
+ $aStyles = array();
+ foreach ($aAttrs as $sIndex => $aItem)
+ {
+ if (\is_array($aItem))
+ {
+ $oElement->removeAttribute($aItem[0]);
+
+ switch ($sIndex)
+ {
+ case 'link':
+ $sLinkColor = \trim($aItem[1]);
+ if (!\preg_match('/^#[abcdef0-9]{3,6}$/i', $sLinkColor))
+ {
+ $sLinkColor = '';
+ }
+ break;
+ case 'text':
+ $aStyles[] = 'color: '.$aItem[1];
+ break;
+ case 'topmargin':
+ $aStyles[] = 'margin-top: '.((int) $aItem[1]).'px';
+ break;
+ case 'leftmargin':
+ $aStyles[] = 'margin-left: '.((int) $aItem[1]).'px';
+ break;
+ case 'bottommargin':
+ $aStyles[] = 'margin-bottom: '.((int) $aItem[1]).'px';
+ break;
+ case 'rightmargin':
+ $aStyles[] = 'margin-right: '.((int) $aItem[1]).'px';
+ break;
+ }
+ }
+ }
+
+ if (0 < \count($aStyles))
+ {
+ $sStyles = $oElement->hasAttribute('style') ? \trim(\trim(\trim($oElement->getAttribute('style')), ';')) : '';
+ $oElement->setAttribute('style', (empty($sStyles) ? '' : $sStyles.'; ').\implode('; ', $aStyles));
+ }
+ }
+
+ if ('iframe' === $sTagNameLower || 'frame' === $sTagNameLower)
+ {
+ $oElement->setAttribute('src', 'javascript:false');
+ }
+
+ if ('a' === $sTagNameLower && !empty($sLinkColor))
+ {
+ $sStyles = $oElement->hasAttribute('style')
+ ? \trim(\trim(\trim($oElement->getAttribute('style')), ';')) : '';
+
+ $oElement->setAttribute('style',
+ 'color: '.$sLinkColor.\trim((empty($sStyles) ? '' : '; '.$sStyles)));
+ }
+
+ if (\in_array($sTagNameLower, array('a', 'form', 'area')))
+ {
+ $oElement->setAttribute('target', '_blank');
+ }
+
+ if (\in_array($sTagNameLower, array('a', 'form', 'area', 'input', 'button', 'textarea')))
+ {
+ $oElement->setAttribute('tabindex', '-1');
+ }
+
+ if ($oElement->hasAttributes() && isset($oElement->attributes) && $oElement->attributes)
+ {
+ foreach ($oElement->attributes as $oAttr)
+ {
+ if ($oAttr && !empty($oAttr->nodeName))
+ {
+ $sAttrName = \trim(\strtolower($oAttr->nodeName));
+ if ('on' === \substr($sAttrName, 0, 2) || in_array($sAttrName, array(
+ 'id', 'class', 'contenteditable', 'designmode', 'formaction',
+ 'data-bind', 'data-reactid', 'xmlns', 'srcset', 'data-x-skip-style',
+ 'fscommand', 'seeksegmenttime'
+ )))
+ {
+ @$oElement->removeAttribute($oAttr->nodeName);
+ }
+ }
+ }
+ }
+
+ if ($oElement->hasAttribute('href'))
+ {
+ $sHref = \trim($oElement->getAttribute('href'));
+ if (!\preg_match('/^(http[s]?|ftp|skype|mailto):/i', $sHref) && '//' !== \substr($sHref, 0, 2))
+ {
+ $oElement->setAttribute('data-x-broken-href', $sHref);
+ $oElement->setAttribute('href', 'javascript:false');
+ }
+
+ if ('a' === $sTagNameLower)
+ {
+ $oElement->setAttribute('rel', 'external nofollow');
+ }
+ }
+
+ if ($bTryToDetectHiddenImages && 'img' === $sTagNameLower)
+ {
+ $sAlt = $oElement->hasAttribute('alt')
+ ? \trim($oElement->getAttribute('alt')) : '';
+
+ if ($oElement->hasAttribute('src') && '' === $sAlt)
+ {
+ $aH = array(
+ 'email.microsoftemail.com/open',
+ 'github.com/notifications/beacon/',
+ 'mandrillapp.com/track/open',
+ 'list-manage.com/track/open'
+ );
+
+ $sH = $oElement->hasAttribute('height')
+ ? \trim($oElement->getAttribute('height')) : '';
+
+// $sW = $oElement->hasAttribute('width')
+// ? \trim($oElement->getAttribute('width')) : '';
+
+ $sStyles = $oElement->hasAttribute('style')
+ ? \preg_replace('/[\s]+/', '', \trim(\trim(\trim($oElement->getAttribute('style')), ';'))) : '';
+
+ $sSrc = \trim($oElement->getAttribute('src'));
+
+ $bC = \in_array($sH, array('1', '0', '1px', '0px')) ||
+ \preg_match('/(display:none|visibility:hidden|height:0|height:[01][a-z][a-z])/i', $sStyles);
+
+ if (!$bC)
+ {
+ $sSrcLower = \strtolower($sSrc);
+ foreach ($aH as $sLine)
+ {
+ if (false !== \strpos($sSrcLower, $sLine))
+ {
+ $bC = true;
+ break;
+ }
+ }
+ }
+
+ if ($bC)
+ {
+ $oElement->setAttribute('style', 'display:none');
+ $oElement->setAttribute('data-x-skip-style', 'true');
+ $oElement->setAttribute('data-x-hidden-src', $sSrc);
+
+ $oElement->removeAttribute('src');
+ }
+ }
+ }
+
+ if ($oElement->hasAttribute('src'))
+ {
+ $sSrc = \trim($oElement->getAttribute('src'));
+ $oElement->removeAttribute('src');
+
+ if (\in_array($sSrc, $aContentLocationUrls))
+ {
+ $oElement->setAttribute('data-x-src-location', $sSrc);
+ $aFoundedContentLocationUrls[] = $sSrc;
+ }
+ else if ('cid:' === \strtolower(\substr($sSrc, 0, 4)))
+ {
+ $oElement->setAttribute('data-x-src-cid', \substr($sSrc, 4));
+ $aFoundCIDs[] = \substr($sSrc, 4);
+ }
+ else
+ {
+ if (\preg_match('/^http[s]?:\/\//i', $sSrc) || '//' === \substr($sSrc, 0, 2))
+ {
+ if ($bDoNotReplaceExternalUrl)
+ {
+ $oElement->setAttribute('src', $sSrc);
+ }
+ else
+ {
+ $oElement->setAttribute('data-x-src', $sSrc);
+ if ($fAdditionalExternalFilter)
+ {
+ $sCallResult = \call_user_func($fAdditionalExternalFilter, $sSrc);
+ if (0 < \strlen($sCallResult))
+ {
+ $oElement->setAttribute('data-x-additional-src', $sCallResult);
+ }
+ }
+ }
+
+ $bHasExternals = true;
+ }
+ else if ('data:image/' === \strtolower(\substr($sSrc, 0, 11)))
+ {
+ $oElement->setAttribute('src', $sSrc);
+ }
+ else
+ {
+ $oElement->setAttribute('data-x-broken-src', $sSrc);
+ }
+ }
+ }
+
+ $sBackground = $oElement->hasAttribute('background')
+ ? \trim($oElement->getAttribute('background')) : '';
+ $sBackgroundColor = $oElement->hasAttribute('bgcolor')
+ ? \trim($oElement->getAttribute('bgcolor')) : '';
+
+ if (!empty($sBackground) || !empty($sBackgroundColor))
+ {
+ $aStyles = array();
+ $sStyles = $oElement->hasAttribute('style')
+ ? \trim(\trim(\trim($oElement->getAttribute('style')), ';')) : '';
+
+ if (!empty($sBackground))
+ {
+ $aStyles[] = 'background-image: url(\''.$sBackground.'\')';
+ $oElement->removeAttribute('background');
+ }
+
+ if (!empty($sBackgroundColor))
+ {
+ $aStyles[] = 'background-color: '.$sBackgroundColor;
+ $oElement->removeAttribute('bgcolor');
+ }
+
+ $oElement->setAttribute('style', (empty($sStyles) ? '' : $sStyles.'; ').\implode('; ', $aStyles));
+ }
+
+ if ($oElement->hasAttribute('style') && !$oElement->hasAttribute('data-x-skip-style'))
+ {
+ $oElement->setAttribute('style',
+ \MailSo\Base\HtmlUtils::ClearStyle($oElement->getAttribute('style'), $oElement, $bHasExternals,
+ $aFoundCIDs, $aContentLocationUrls, $aFoundedContentLocationUrls, $bDoNotReplaceExternalUrl, $fAdditionalExternalFilter));
+ }
+
+ $oElement->removeAttribute('data-x-skip-style');
+ }
+
+ $sResult = $oDom->saveHTML();
+ }
+
+ unset($oDom);
+
+ $sResult = \MailSo\Base\HtmlUtils::ClearTags($sResult);
+
+ $sHtmlAttrs = $sBodyAttrs = '';
+ $sResult = \MailSo\Base\HtmlUtils::ClearBodyAndHtmlTag($sResult, $sHtmlAttrs, $sBodyAttrs);
+ $sResult = ''.$sResult.'
';
+ $sResult = ''.$sResult.'
';
+
+ $sResult = \str_replace(\MailSo\Base\HtmlUtils::$KOS, ':', $sResult);
+ $sResult = \MailSo\Base\Utils::StripSpaces($sResult);
+
+ return \trim($sResult);
+ }
+
+ /**
+ * @param string $sHtml
+ * @param array $aFoundCids = array()
+ * @param array|null $mFoundDataURL = null
+ * @param array $aFoundedContentLocationUrls = array()
+ *
+ * @return string
+ */
+ public static function BuildHtml($sHtml, &$aFoundCids = array(), &$mFoundDataURL = null, &$aFoundedContentLocationUrls = array())
+ {
+ $oDom = \MailSo\Base\HtmlUtils::GetDomFromText($sHtml);
+ unset($sHtml);
+
+ $aNodes = $oDom->getElementsByTagName('*');
+ foreach ($aNodes as /* @var $oElement \DOMElement */ $oElement)
+ {
+ $sTagNameLower = \strtolower($oElement->tagName);
+
+ if ($oElement->hasAttribute('data-x-src-cid'))
+ {
+ $sCid = $oElement->getAttribute('data-x-src-cid');
+ $oElement->removeAttribute('data-x-src-cid');
+
+ if (!empty($sCid))
+ {
+ $aFoundCids[] = $sCid;
+
+ @$oElement->removeAttribute('src');
+ $oElement->setAttribute('src', 'cid:'.$sCid);
+ }
+ }
+
+ if ($oElement->hasAttribute('data-x-src-location'))
+ {
+ $sSrc = $oElement->getAttribute('data-x-src-location');
+ $oElement->removeAttribute('data-x-src-location');
+
+ if (!empty($sSrc))
+ {
+ $aFoundedContentLocationUrls[] = $sSrc;
+
+ @$oElement->removeAttribute('src');
+ $oElement->setAttribute('src', $sSrc);
+ }
+ }
+
+ if ($oElement->hasAttribute('data-x-broken-src'))
+ {
+ $oElement->setAttribute('src', $oElement->getAttribute('data-x-broken-src'));
+ $oElement->removeAttribute('data-x-broken-src');
+ }
+
+ if ($oElement->hasAttribute('data-x-src'))
+ {
+ $oElement->setAttribute('src', $oElement->getAttribute('data-x-src'));
+ $oElement->removeAttribute('data-x-src');
+ }
+
+ if ($oElement->hasAttribute('data-x-href'))
+ {
+ $oElement->setAttribute('href', $oElement->getAttribute('data-x-href'));
+ $oElement->removeAttribute('data-x-href');
+ }
+
+ if ($oElement->hasAttribute('data-x-additional-src'))
+ {
+ $oElement->removeAttribute('data-x-additional-src');
+ }
+
+ if ($oElement->hasAttribute('data-x-additional-style-url'))
+ {
+ $oElement->removeAttribute('data-x-additional-style-url');
+ }
+
+ if ($oElement->hasAttribute('data-x-style-cid-name') && $oElement->hasAttribute('data-x-style-cid'))
+ {
+ $sCidName = $oElement->getAttribute('data-x-style-cid-name');
+ $sCid = $oElement->getAttribute('data-x-style-cid');
+
+ $oElement->removeAttribute('data-x-style-cid-name');
+ $oElement->removeAttribute('data-x-style-cid');
+ if (!empty($sCidName) && !empty($sCid) && \in_array($sCidName,
+ array('background-image', 'background', 'list-style-image', 'content')))
+ {
+ $sStyles = '';
+ if ($oElement->hasAttribute('style'))
+ {
+ $sStyles = \trim(\trim($oElement->getAttribute('style')), ';');
+ }
+
+ $sBack = $sCidName.': url(cid:'.$sCid.')';
+ $sStyles = \preg_replace('/'.\preg_quote($sCidName, '/').':\s?[^;]+/i', $sBack, $sStyles);
+ if (false === \strpos($sStyles, $sBack))
+ {
+ $sStyles .= empty($sStyles) ? '': '; ';
+ $sStyles .= $sBack;
+ }
+
+ $oElement->setAttribute('style', $sStyles);
+ $aFoundCids[] = $sCid;
+ }
+ }
+
+ if ($oElement->hasAttribute('data-original'))
+ {
+ $oElement->removeAttribute('data-original');
+ }
+
+ if ($oElement->hasAttribute('data-x-div-type'))
+ {
+ $oElement->removeAttribute('data-x-div-type');
+ }
+
+ if ($oElement->hasAttribute('data-x-style-url'))
+ {
+ $sAddStyles = $oElement->getAttribute('data-x-style-url');
+ $oElement->removeAttribute('data-x-style-url');
+
+ if (!empty($sAddStyles))
+ {
+ $sStyles = '';
+ if ($oElement->hasAttribute('style'))
+ {
+ $sStyles = \trim(\trim($oElement->getAttribute('style')), ';');
+ }
+
+ $oElement->setAttribute('style', (empty($sStyles) ? '' : $sStyles.'; ').$sAddStyles);
+ }
+ }
+
+ if ('img' === $sTagNameLower && \is_array($mFoundDataURL))
+ {
+ $sSrc = $oElement->getAttribute('src');
+ if ('data:image/' === \strtolower(\substr($sSrc, 0, 11)))
+ {
+ $sHash = \md5($sSrc);
+ $mFoundDataURL[$sHash] = $sSrc;
+
+ $oElement->setAttribute('src', 'cid:'.$sHash);
+ }
+ }
+ }
+
+ $sResult = $oDom->saveHTML();
+ unset($oDom);
+
+ $sResult = \MailSo\Base\HtmlUtils::ClearTags($sResult);
+ $sResult = \MailSo\Base\HtmlUtils::ClearBodyAndHtmlTag($sResult);
+
+ return ' '.
+ ''.\trim($sResult).'';
+ }
+
+ /**
+ * @param string $sText
+ * @param bool $bLinksWithTargetBlank = true
+ *
+ * @return string
+ */
+ public static function ConvertPlainToHtml($sText, $bLinksWithTargetBlank = true)
+ {
+ $sText = \trim($sText);
+ if (0 === \strlen($sText))
+ {
+ return '';
+ }
+
+ $sText = \MailSo\Base\LinkFinder::NewInstance()
+ ->Text($sText)
+ ->UseDefaultWrappers($bLinksWithTargetBlank)
+ ->CompileText();
+
+ $sText = \str_replace("\r", '', $sText);
+
+ $aText = \explode("\n", $sText);
+ unset($sText);
+
+ $bIn = false;
+ $bDo = true;
+ do
+ {
+ $bDo = false;
+ $aNextText = array();
+ foreach ($aText as $sTextLine)
+ {
+ $bStart = 0 === \strpos(\ltrim($sTextLine), '>');
+ if ($bStart && !$bIn)
+ {
+ $bDo = true;
+ $bIn = true;
+ $aNextText[] = '';
+ $aNextText[] = \substr(\ltrim($sTextLine), 4);
+ }
+ else if (!$bStart && $bIn)
+ {
+ $bIn = false;
+ $aNextText[] = ' ';
+ $aNextText[] = $sTextLine;
+ }
+ else if ($bStart && $bIn)
+ {
+ $aNextText[] = \substr(\ltrim($sTextLine), 4);
+ }
+ else
+ {
+ $aNextText[] = $sTextLine;
+ }
+ }
+
+ if ($bIn)
+ {
+ $bIn = false;
+ $aNextText[] = '';
+ }
+
+ $aText = $aNextText;
+ }
+ while ($bDo);
+
+ $sText = \join("\n", $aText);
+ unset($aText);
+
+ $sText = \preg_replace('/[\n][ ]+/', "\n", $sText);
+// $sText = \preg_replace('/[\s]+([\s])/', '\\1', $sText);
+
+ $sText = \preg_replace('/[\s]+/i', '', $sText);
+ $sText = \preg_replace('/[\s]+<\/blockquote>/i', ' ', $sText);
+
+ $sText = \preg_replace('/<\/blockquote>([\n]{0,2})/i', '\\1', $sText);
+ $sText = \preg_replace('/[\n]{3,}/', "\n\n", $sText);
+
+ $sText = \strtr($sText, array(
+ "\n" => " ",
+ "\t" => ' ',
+ ' ' => ' '
+ ));
+
+ return $sText;
+ }
+
+ /**
+ * @param string $sText
+ *
+ * @return string
+ */
+ public static function ConvertHtmlToPlain($sText)
+ {
+ $sText = \trim(\stripslashes($sText));
+ $sText = \MailSo\Base\Utils::StripSpaces($sText);
+
+ $sText = \preg_replace(array(
+ "/\r/",
+ "/[\n\t]+/",
+ '/', '<\/script>',
+ \str_replace($aJsonReplaces[0], $aJsonReplaces[1], $sText));
+ }
+
+ /**
+ * @param array $aInput
+ */
+ public static function ClearArrayUtf8Values(&$aInput)
+ {
+ if (\is_array($aInput))
+ {
+ foreach ($aInput as $mKey => $mItem)
+ {
+ if (\is_string($mItem))
+ {
+ $aInput[$mKey] = \MailSo\Base\Utils::Utf8Clear($mItem);
+ }
+ else if (\is_array($mItem))
+ {
+ \MailSo\Base\Utils::ClearArrayUtf8Values($mItem);
+ $aInput[$mKey] = $mItem;
+ }
+ }
+ }
+ }
+
+ /**
+ * @param mixed $mInput
+ * @param \MailSo\Log\Logger|null $oLogger = null
+ *
+ * @return string
+ */
+ public static function Php2js($mInput, $oLogger = null)
+ {
+ static $iOpt = null;
+ if (null === $iOpt)
+ {
+ $iOpt = \defined('JSON_UNESCAPED_UNICODE') ? JSON_UNESCAPED_UNICODE : 0;
+ }
+
+ $sResult = @\json_encode($mInput, $iOpt);
+ if (!\is_string($sResult) || '' === $sResult)
+ {
+ if (!$oLogger && \MailSo\Log\Logger::IsSystemEnabled())
+ {
+ $oLogger = \MailSo\Config::$SystemLogger;
+ }
+
+ if (!($oLogger instanceof \MailSo\Log\Logger))
+ {
+ $oLogger = null;
+ }
+
+ if ($oLogger)
+ {
+ $oLogger->Write('json_encode: '.\trim(
+ (\MailSo\Base\Utils::FunctionExistsAndEnabled('json_last_error') ? ' [Error Code: '.\json_last_error().']' : '').
+ (\MailSo\Base\Utils::FunctionExistsAndEnabled('json_last_error_msg') ? ' [Error Message: '.\json_last_error_msg().']' : '')
+ ), \MailSo\Log\Enumerations\Type::WARNING, 'JSON'
+ );
+ }
+
+ if (\is_array($mInput))
+ {
+ if ($oLogger)
+ {
+ $oLogger->WriteDump($mInput, \MailSo\Log\Enumerations\Type::INFO, 'JSON');
+ $oLogger->Write('Trying to clear Utf8 before json_encode', \MailSo\Log\Enumerations\Type::INFO, 'JSON');
+ }
+
+ \MailSo\Base\Utils::ClearArrayUtf8Values($mInput);
+ $sResult = @\json_encode($mInput, $iOpt);
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sFileName
+ *
+ * @return string
+ */
+ public static function ClearFileName($sFileName)
+ {
+ return \MailSo\Base\Utils::Trim(\MailSo\Base\Utils::ClearNullBite(
+ \MailSo\Base\Utils::StripSpaces(
+ \str_replace(array('"', '/', '\\', '*', '?', '<', '>', '|', ':'), ' ', $sFileName))));
+ }
+
+ /**
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function ClearXss($sValue)
+ {
+ return \MailSo\Base\Utils::Trim(\MailSo\Base\Utils::ClearNullBite(
+ \str_replace(array('"', '/', '\\', '*', '?', '<', '>', '|', ':'), ' ', $sValue)));
+ }
+
+ /**
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function Trim($sValue)
+ {
+ return \trim(\preg_replace('/^[\x00-\x1F]+/u', '',
+ \preg_replace('/[\x00-\x1F]+$/u', '', \trim($sValue))));
+ }
+
+ /**
+ * @param string $sDir
+ *
+ * @return bool
+ */
+ public static function RecRmDir($sDir)
+ {
+ if (@\is_dir($sDir))
+ {
+ $aObjects = \scandir($sDir);
+ foreach ($aObjects as $sObject)
+ {
+ if ('.' !== $sObject && '..' !== $sObject)
+ {
+// if ('dir' === \filetype($sDir.'/'.$sObject))
+ if (\is_dir($sDir.'/'.$sObject))
+ {
+ self::RecRmDir($sDir.'/'.$sObject);
+ }
+ else
+ {
+ @\unlink($sDir.'/'.$sObject);
+ }
+ }
+ }
+
+ return @\rmdir($sDir);
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $sSource
+ * @param string $sDestination
+ */
+ public static function CopyDir($sSource, $sDestination)
+ {
+ if (\is_dir($sSource))
+ {
+ if (!\is_dir($sDestination))
+ {
+ \mkdir($sDestination);
+ }
+
+ $oDirectory = \dir($sSource);
+ if ($oDirectory)
+ {
+ while (false !== ($sRead = $oDirectory->read()))
+ {
+ if ('.' === $sRead || '..' === $sRead)
+ {
+ continue;
+ }
+
+ $sPathDir = $sSource.'/'.$sRead;
+ if (\is_dir($sPathDir))
+ {
+ \MailSo\Base\Utils::CopyDir($sPathDir, $sDestination.'/'.$sRead);
+ continue;
+ }
+
+ \copy($sPathDir, $sDestination.'/'.$sRead);
+ }
+
+ $oDirectory->close();
+ }
+ }
+ }
+
+ /**
+ * @param string $sTempPath
+ * @param int $iTime2Kill
+ * @param int $iNow
+ *
+ * @return bool
+ */
+ public static function RecTimeDirRemove($sTempPath, $iTime2Kill, $iNow)
+ {
+ $iFileCount = 0;
+
+ $sTempPath = rtrim($sTempPath, '\\/');
+ if (@\is_dir($sTempPath))
+ {
+ $rDirH = @\opendir($sTempPath);
+ if ($rDirH)
+ {
+ $bRemoveAllDirs = true;
+ while (($sFile = @\readdir($rDirH)) !== false)
+ {
+ if ('.' !== $sFile && '..' !== $sFile)
+ {
+ if (@\is_dir($sTempPath.'/'.$sFile))
+ {
+ if (!\MailSo\Base\Utils::RecTimeDirRemove($sTempPath.'/'.$sFile, $iTime2Kill, $iNow))
+ {
+ $bRemoveAllDirs = false;
+ }
+ }
+ else
+ {
+ $iFileCount++;
+ }
+ }
+ }
+
+ @\closedir($rDirH);
+ }
+
+ if ($iFileCount > 0)
+ {
+ if (\MailSo\Base\Utils::TimeFilesRemove($sTempPath, $iTime2Kill, $iNow))
+ {
+ return @\rmdir($sTempPath);
+ }
+ }
+ else
+ {
+ return $bRemoveAllDirs ? @\rmdir($sTempPath) : false;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @param string $sTempPath
+ * @param int $iTime2Kill
+ * @param int $iNow
+ */
+ public static function TimeFilesRemove($sTempPath, $iTime2Kill, $iNow)
+ {
+ $bResult = true;
+
+ $sTempPath = rtrim($sTempPath, '\\/');
+ if (@\is_dir($sTempPath))
+ {
+ $rDirH = @\opendir($sTempPath);
+ if ($rDirH)
+ {
+ while (($sFile = @\readdir($rDirH)) !== false)
+ {
+ if ($sFile !== '.' && $sFile !== '..')
+ {
+ if ($iNow - \filemtime($sTempPath.'/'.$sFile) > $iTime2Kill)
+ {
+ @\unlink($sTempPath.'/'.$sFile);
+ }
+ else
+ {
+ $bResult = false;
+ }
+ }
+ }
+
+ @\closedir($rDirH);
+ }
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @param string $sUtfString
+ * @param int $iLength
+ *
+ * @return string
+ */
+ public static function Utf8Truncate($sUtfString, $iLength)
+ {
+ if (\strlen($sUtfString) <= $iLength)
+ {
+ return $sUtfString;
+ }
+
+ while ($iLength >= 0)
+ {
+ if ((\ord($sUtfString[$iLength]) < 0x80) || (\ord($sUtfString[$iLength]) >= 0xC0))
+ {
+ return \substr($sUtfString, 0, $iLength);
+ }
+
+ $iLength--;
+ }
+
+ return '';
+ }
+
+ /**
+ * @param string $sUtfString
+ * @param string $sReplaceOn = ''
+ *
+ * @return string
+ */
+ public static function Utf8Clear($sUtfString, $sReplaceOn = '')
+ {
+ if ('' === $sUtfString)
+ {
+ return $sUtfString;
+ }
+
+ $sUtfString = \preg_replace(\MailSo\Base\Utils::$sValidUtf8Regexp, '$1', $sUtfString);
+
+ $sUtfString = \preg_replace(
+ '/\xE0[\x80-\x9F][\x80-\xBF]'.
+ '|\xEF\xBF\xBF'.
+ '|\xED[\xA0-\xBF][\x80-\xBF]/S', $sReplaceOn, $sUtfString);
+
+ $sUtfString = \preg_replace('/\xEF\xBF\xBD/', '?', $sUtfString);
+
+ $sNewUtfString = false;
+ if (false === $sNewUtfString && \MailSo\Base\Utils::IsMbStringSupported())
+ {
+ $sNewUtfString = \MailSo\Base\Utils::MbConvertEncoding($sUtfString, 'UTF-8', 'UTF-8');
+ }
+
+ if (false === $sNewUtfString && \MailSo\Base\Utils::IsIconvSupported())
+ {
+ $sNewUtfString = \MailSo\Base\Utils::IconvConvertEncoding($sUtfString, 'UTF-8', 'UTF-8');
+ }
+
+ if (false !== $sNewUtfString)
+ {
+ $sUtfString = $sNewUtfString;
+ }
+
+ return $sUtfString;
+ }
+
+ /**
+ * @param string $sUtfString
+ *
+ * @return bool
+ */
+ public static function IsRTL($sUtfString)
+ {
+ // \x{0591}-\x{05F4} - Hebrew
+ // \x{0600}-\x{068F} - Arabic
+ // \x{0750}-\x{077F} - Arabic
+ // \x{08A0}-\x{08FF} - Arabic
+ // \x{103A0}-\x{103DF} - Old Persian
+ return 0 < (int) preg_match('/[\x{0591}-\x{05F4}\x{0600}-\x{068F}\x{0750}-\x{077F}\x{08A0}-\x{08FF}\x{103A0}-\x{103DF}]/u', $sUtfString);
+ }
+
+ /**
+ * @param string $sString
+ *
+ * @return string
+ */
+ public static function Base64Decode($sString)
+ {
+ $sResultString = \base64_decode($sString, true);
+ if (false === $sResultString)
+ {
+ $sString = \str_replace(array(' ', "\r", "\n", "\t"), '', $sString);
+ $sString = \preg_replace('/[^a-zA-Z0-9=+\/](.*)$/', '', $sString);
+
+ if (false !== \strpos(\trim(\trim($sString), '='), '='))
+ {
+ $sString = \preg_replace('/=([^=])/', '= $1', $sString);
+ $aStrings = \explode(' ', $sString);
+ foreach ($aStrings as $iIndex => $sParts)
+ {
+ $aStrings[$iIndex] = \base64_decode($sParts);
+ }
+
+ $sResultString = \implode('', $aStrings);
+ }
+ else
+ {
+ $sResultString = \base64_decode($sString);
+ }
+ }
+
+ return $sResultString;
+ }
+
+ /**
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function UrlSafeBase64Encode($sValue)
+ {
+ return \str_replace(array('+', '/', '='), array('-', '_', '.'), \base64_encode($sValue));
+ }
+
+ /**
+ * @param string $sValue
+ *
+ * @return string
+ */
+ public static function UrlSafeBase64Decode($sValue)
+ {
+ $sData = \str_replace(array('-', '_', '.'), array('+', '/', '='), $sValue);
+ $sMode = \strlen($sData) % 4;
+ if ($sMode)
+ {
+ $sData .= \substr('====', $sMode);
+ }
+
+ return \MailSo\Base\Utils::Base64Decode($sData);
+ }
+
+ /**
+ * @param string $sSequence
+ *
+ * @return array
+ */
+ public static function ParseFetchSequence($sSequence)
+ {
+ $aResult = array();
+ $sSequence = \trim($sSequence);
+ if (0 < \strlen($sSequence))
+ {
+ $aSequence = \explode(',', $sSequence);
+ foreach ($aSequence as $sItem)
+ {
+ if (false === \strpos($sItem, ':'))
+ {
+ $aResult[] = (int) $sItem;
+ }
+ else
+ {
+ $aItems = \explode(':', $sItem);
+ $iMax = \max($aItems[0], $aItems[1]);
+
+ for ($iIndex = $aItems[0]; $iIndex <= $iMax; $iIndex++)
+ {
+ $aResult[] = (int) $iIndex;
+ }
+ }
+ }
+ }
+
+ return $aResult;
+ }
+ /**
+ * @param array $aSequence
+ *
+ * @return string
+ */
+ public static function PrepearFetchSequence($aSequence)
+ {
+ $aResult = array();
+ if (\is_array($aSequence) && 0 < \count($aSequence))
+ {
+ $iStart = null;
+ $iPrev = null;
+
+ foreach ($aSequence as $sItem)
+ {
+ // simple protection
+ if (false !== \strpos($sItem, ':'))
+ {
+ $aResult[] = $sItem;
+ continue;
+ }
+
+ $iItem = (int) $sItem;
+ if (null === $iStart || null === $iPrev)
+ {
+ $iStart = $iItem;
+ $iPrev = $iItem;
+ continue;
+ }
+
+ if ($iPrev === $iItem - 1)
+ {
+ $iPrev = $iItem;
+ }
+ else
+ {
+ $aResult[] = $iStart === $iPrev ? $iStart : $iStart.':'.$iPrev;
+ $iStart = $iItem;
+ $iPrev = $iItem;
+ }
+ }
+
+ if (null !== $iStart && null !== $iPrev)
+ {
+ $aResult[] = $iStart === $iPrev ? $iStart : $iStart.':'.$iPrev;
+ }
+ }
+
+ return \implode(',', $aResult);
+ }
+
+ /**
+ *
+ * @param resource $fResource
+ * @param int $iBufferLen = 8192
+ *
+ * @return bool
+ */
+ public static function FpassthruWithTimeLimitReset($fResource, $iBufferLen = 8192)
+ {
+ $bResult = false;
+ if (\is_resource($fResource))
+ {
+ while (!\feof($fResource))
+ {
+ $sBuffer = @\fread($fResource, $iBufferLen);
+ if (false !== $sBuffer)
+ {
+ echo $sBuffer;
+ \MailSo\Base\Utils::ResetTimeLimit();
+ continue;
+ }
+
+ break;
+ }
+
+ $bResult = true;
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @param resource $rRead
+ * @param array $aWrite
+ * @param int $iBufferLen = 8192
+ * @param bool $bResetTimeLimit = true
+ * @param bool $bFixCrLf = false
+ * @param bool $bRewindOnComplete = false
+ *
+ * @return int|bool
+ */
+ public static function MultipleStreamWriter($rRead, $aWrite, $iBufferLen = 8192, $bResetTimeLimit = true, $bFixCrLf = false, $bRewindOnComplete = false)
+ {
+ $mResult = false;
+ if ($rRead && \is_array($aWrite) && 0 < \count($aWrite))
+ {
+ $mResult = 0;
+ while (!\feof($rRead))
+ {
+ $sBuffer = \fread($rRead, $iBufferLen);
+ if (false === $sBuffer)
+ {
+ $mResult = false;
+ break;
+ }
+
+ if (0 === $iBufferLen || '' === $sBuffer)
+ {
+ break;
+ }
+
+ if ($bFixCrLf)
+ {
+ $sBuffer = \str_replace("\n", "\r\n", \str_replace("\r", '', $sBuffer));
+ }
+
+ $mResult += \strlen($sBuffer);
+
+ foreach ($aWrite as $rWriteStream)
+ {
+ $mWriteResult = \fwrite($rWriteStream, $sBuffer);
+ if (false === $mWriteResult)
+ {
+ $mResult = false;
+ break 2;
+ }
+ }
+
+ if ($bResetTimeLimit)
+ {
+ \MailSo\Base\Utils::ResetTimeLimit();
+ }
+ }
+ }
+
+ if ($mResult && $bRewindOnComplete)
+ {
+ foreach ($aWrite as $rWriteStream)
+ {
+ if (\is_resource($rWriteStream))
+ {
+ @\rewind($rWriteStream);
+ }
+ }
+ }
+
+ return $mResult;
+ }
+
+ /**
+ * @param string $sUtfModifiedString
+ *
+ * @return string
+ */
+ public static function ModifiedToPlainUtf7($sUtfModifiedString)
+ {
+ $sUtf = '';
+ $bBase = false;
+
+ for ($iIndex = 0, $iLen = \strlen($sUtfModifiedString); $iIndex < $iLen; $iIndex++)
+ {
+ if ('&' === $sUtfModifiedString[$iIndex])
+ {
+ if (isset($sUtfModifiedString[$iIndex+1]) && '-' === $sUtfModifiedString[$iIndex + 1])
+ {
+ $sUtf .= '&';
+ $iIndex++;
+ }
+ else
+ {
+ $sUtf .= '+';
+ $bBase = true;
+ }
+ }
+ else if ($sUtfModifiedString[$iIndex] == '-' && $bBase)
+ {
+ $bBase = false;
+ }
+ else
+ {
+ if ($bBase && ',' === $sUtfModifiedString[$iIndex])
+ {
+ $sUtf .= '/';
+ }
+ else if (!$bBase && '+' === $sUtfModifiedString[$iIndex])
+ {
+ $sUtf .= '+-';
+ }
+ else
+ {
+ $sUtf .= $sUtfModifiedString[$iIndex];
+ }
+ }
+ }
+
+ return $sUtf;
+ }
+
+ /**
+ * @param string $sStr
+ *
+ * @return string|bool
+ */
+ public static function Utf7ModifiedToUtf8($sStr)
+ {
+ $aArray = array(-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,62, 63,-1,-1,-1,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,
+ 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
+ 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1);
+
+ $sResult = '';
+ $bError = false;
+ $iLen = \strlen($sStr);
+
+ for ($iIndex = 0; $iLen > 0; $iIndex++, $iLen--)
+ {
+ $sChar = $sStr{$iIndex};
+ if ($sChar == '&')
+ {
+ $iIndex++;
+ $iLen--;
+
+ $sChar = isset($sStr{$iIndex}) ? $sStr{$iIndex} : null;
+ if ($sChar === null)
+ {
+ break;
+ }
+
+ if ($iLen && $sChar == '-')
+ {
+ $sResult .= '&';
+ continue;
+ }
+
+ $iCh = 0;
+ $iK = 10;
+ for (; $iLen > 0; $iIndex++, $iLen--)
+ {
+ $sChar = $sStr{$iIndex};
+
+ $iB = $aArray[\ord($sChar)];
+ if ((\ord($sChar) & 0x80) || $iB == -1)
+ {
+ break;
+ }
+
+ if ($iK > 0)
+ {
+ $iCh |= $iB << $iK;
+ $iK -= 6;
+ }
+ else
+ {
+ $iCh |= $iB >> (-$iK);
+ if ($iCh < 0x80)
+ {
+ if (0x20 <= $iCh && $iCh < 0x7f)
+ {
+ return $bError;
+ }
+
+ $sResult .= \chr($iCh);
+ }
+ else if ($iCh < 0x800)
+ {
+ $sResult .= \chr(0xc0 | ($iCh >> 6));
+ $sResult .= \chr(0x80 | ($iCh & 0x3f));
+ }
+ else
+ {
+ $sResult .= \chr(0xe0 | ($iCh >> 12));
+ $sResult .= \chr(0x80 | (($iCh >> 6) & 0x3f));
+ $sResult .= \chr(0x80 | ($iCh & 0x3f));
+ }
+
+ $iCh = ($iB << (16 + $iK)) & 0xffff;
+ $iK += 10;
+ }
+ }
+
+ if (($iCh || $iK < 6) ||
+ (!$iLen || $sChar != '-') ||
+ ($iLen > 2 && '&' === $sStr{$iIndex+1} && '-' !== $sStr{$iIndex+2}))
+ {
+ return $bError;
+ }
+ }
+ else if (\ord($sChar) < 0x20 || \ord($sChar) >= 0x7f)
+ {
+ return $bError;
+ }
+ else
+ {
+ $sResult .= $sChar;
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sStr
+ *
+ * @return string|bool
+ */
+ public static function Utf8ToUtf7Modified($sStr)
+ {
+ $sArray = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S',
+ 'T','U','V','W','X','Y','Z', 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
+ 'p','q','r','s','t','u','v','w','x','y','z', '0','1','2','3','4','5','6','7','8','9','+',',');
+
+ $sLen = \strlen($sStr);
+ $bIsB = false;
+ $iIndex = $iN = 0;
+ $sReturn = '';
+ $bError = false;
+ $iCh = $iB = $iK = 0;
+
+ while ($sLen)
+ {
+ $iC = \ord($sStr{$iIndex});
+ if ($iC < 0x80)
+ {
+ $iCh = $iC;
+ $iN = 0;
+ }
+ else if ($iC < 0xc2)
+ {
+ return $bError;
+ }
+ else if ($iC < 0xe0)
+ {
+ $iCh = $iC & 0x1f;
+ $iN = 1;
+ }
+ else if ($iC < 0xf0)
+ {
+ $iCh = $iC & 0x0f;
+ $iN = 2;
+ }
+ else if ($iC < 0xf8)
+ {
+ $iCh = $iC & 0x07;
+ $iN = 3;
+ }
+ else if ($iC < 0xfc)
+ {
+ $iCh = $iC & 0x03;
+ $iN = 4;
+ }
+ else if ($iC < 0xfe)
+ {
+ $iCh = $iC & 0x01;
+ $iN = 5;
+ }
+ else
+ {
+ return $bError;
+ }
+
+ $iIndex++;
+ $sLen--;
+
+ if ($iN > $sLen)
+ {
+ return $bError;
+ }
+
+ for ($iJ = 0; $iJ < $iN; $iJ++)
+ {
+ $iO = \ord($sStr{$iIndex+$iJ});
+ if (($iO & 0xc0) != 0x80)
+ {
+ return $bError;
+ }
+
+ $iCh = ($iCh << 6) | ($iO & 0x3f);
+ }
+
+ if ($iN > 1 && !($iCh >> ($iN * 5 + 1)))
+ {
+ return $bError;
+ }
+
+ $iIndex += $iN;
+ $sLen -= $iN;
+
+ if ($iCh < 0x20 || $iCh >= 0x7f)
+ {
+ if (!$bIsB)
+ {
+ $sReturn .= '&';
+ $bIsB = true;
+ $iB = 0;
+ $iK = 10;
+ }
+
+ if ($iCh & ~0xffff)
+ {
+ $iCh = 0xfffe;
+ }
+
+ $sReturn .= $sArray[($iB | $iCh >> $iK)];
+ $iK -= 6;
+ for (; $iK >= 0; $iK -= 6)
+ {
+ $sReturn .= $sArray[(($iCh >> $iK) & 0x3f)];
+ }
+
+ $iB = ($iCh << (-$iK)) & 0x3f;
+ $iK += 16;
+ }
+ else
+ {
+ if ($bIsB)
+ {
+ if ($iK > 10)
+ {
+ $sReturn .= $sArray[$iB];
+ }
+ $sReturn .= '-';
+ $bIsB = false;
+ }
+
+ $sReturn .= \chr($iCh);
+ if ('&' === \chr($iCh))
+ {
+ $sReturn .= '-';
+ }
+ }
+ }
+
+ if ($bIsB)
+ {
+ if ($iK > 10)
+ {
+ $sReturn .= $sArray[$iB];
+ }
+
+ $sReturn .= '-';
+ }
+
+ return $sReturn;
+ }
+
+ /**
+ * @param string|array $mFunctionNameOrNames
+ *
+ * @return bool
+ */
+ public static function FunctionExistsAndEnabled($mFunctionNameOrNames)
+ {
+ static $aCache = null;
+
+ if (\is_array($mFunctionNameOrNames))
+ {
+ foreach ($mFunctionNameOrNames as $sFunctionName)
+ {
+ if (!\MailSo\Base\Utils::FunctionExistsAndEnabled($sFunctionName))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ if (empty($mFunctionNameOrNames) || !\function_exists($mFunctionNameOrNames) || !\is_callable($mFunctionNameOrNames))
+ {
+ return false;
+ }
+
+ if (null === $aCache)
+ {
+ $sDisableFunctions = @\ini_get('disable_functions');
+ $sDisableFunctions = \is_string($sDisableFunctions) && 0 < \strlen($sDisableFunctions) ? $sDisableFunctions : '';
+
+ $aCache = \explode(',', $sDisableFunctions);
+ $aCache = \is_array($aCache) && 0 < \count($aCache) ? $aCache : array();
+
+ if (\extension_loaded('suhosin'))
+ {
+ $sSuhosin = @\ini_get('suhosin.executor.func.blacklist');
+ $sSuhosin = \is_string($sSuhosin) && 0 < \strlen($sSuhosin) ? $sSuhosin : '';
+
+ $aSuhosinCache = \explode(',', $sSuhosin);
+ $aSuhosinCache = \is_array($aSuhosinCache) && 0 < \count($aSuhosinCache) ? $aSuhosinCache : array();
+
+ if (0 < \count($aSuhosinCache))
+ {
+ $aCache = \array_merge($aCache, $aSuhosinCache);
+ $aCache = \array_unique($aCache);
+ }
+ }
+ }
+
+ return !\in_array($mFunctionNameOrNames, $aCache);
+ }
+
+ /**
+ * @param string $mValue
+ *
+ * @return string
+ */
+ public static function ClearNullBite($mValue)
+ {
+ return \str_replace('%00', '', $mValue);
+ }
+
+ /**
+ * @param mixed $mValue
+ * @param bool $bClearNullBite = false
+ *
+ * @return mixed
+ */
+ public static function StripSlashesValue($mValue, $bClearNullBite = false)
+ {
+ static $bIsMagicQuotesOn = null;
+ if (null === $bIsMagicQuotesOn)
+ {
+ $bIsMagicQuotesOn = (bool) @\ini_get('magic_quotes_gpc');
+ }
+
+ if (!$bIsMagicQuotesOn)
+ {
+ return $bClearNullBite && \is_string($mValue) ? \MailSo\Base\Utils::ClearNullBite($mValue) : $mValue;
+ }
+
+ $sType = \gettype($mValue);
+ if ('string' === $sType)
+ {
+ return \stripslashes($bClearNullBite ? \MailSo\Base\Utils::ClearNullBite($mValue) : $mValue);
+ }
+ else if ('array' === $sType)
+ {
+ $aReturnValue = array();
+ $mValueKeys = \array_keys($mValue);
+ foreach ($mValueKeys as $sKey)
+ {
+ $aReturnValue[$sKey] = \MailSo\Base\Utils::StripSlashesValue($mValue[$sKey], $bClearNullBite);
+ }
+
+ return $aReturnValue;
+ }
+
+ return $mValue;
+ }
+
+ /**
+ * @param string $sStr
+ *
+ * @return string
+ */
+ public static function CharsetDetect($sStr)
+ {
+ $mResult = '';
+ if (!\MailSo\Base\Utils::IsAscii($sStr))
+ {
+ $mResult = \MailSo\Base\Utils::IsMbStringSupported() &&
+ \MailSo\Base\Utils::FunctionExistsAndEnabled('mb_detect_encoding') ?
+ @\mb_detect_encoding($sStr, 'auto', true) : false;
+
+ if (false === $mResult && \MailSo\Base\Utils::IsIconvSupported())
+ {
+ $mResult = \md5(@\iconv('utf-8', 'utf-8//IGNORE', $sStr)) === \md5($sStr) ? 'utf-8' : '';
+ }
+ }
+
+ return \is_string($mResult) && 0 < \strlen($mResult) ? $mResult : '';
+ }
+
+ /**
+ * @param string $sAdditionalSalt = ''
+ *
+ * @return string
+ */
+ public static function Md5Rand($sAdditionalSalt = '')
+ {
+ return \md5(\microtime(true).\rand(10000, 99999).
+ \md5($sAdditionalSalt).\rand(10000, 99999).\microtime(true));
+ }
+
+ /**
+ * @param string $sAdditionalSalt = ''
+ *
+ * @return string
+ */
+ public static function Sha1Rand($sAdditionalSalt = '')
+ {
+ return \sha1(\microtime(true).\rand(10000, 99999).
+ \sha1($sAdditionalSalt).\rand(10000, 99999).\microtime(true));
+ }
+
+ /**
+ * @param string $sData
+ * @param string $sKey
+ *
+ * @return string
+ */
+ public static function Hmac($sData, $sKey)
+ {
+ if (\function_exists('hash_hmac'))
+ {
+ return \hash_hmac('md5', $sData, $sKey);
+ }
+
+ $iLen = 64;
+ if ($iLen < \strlen($sKey))
+ {
+ $sKey = \pack('H*', \md5($sKey));
+ }
+
+ $sKey = \str_pad($sKey, $iLen, \chr(0x00));
+ $sIpad = \str_pad('', $iLen, \chr(0x36));
+ $sOpad = \str_pad('', $iLen, \chr(0x5c));
+
+ return \md5(($sKey ^ $sOpad).\pack('H*', \md5(($sKey ^ $sIpad).$sData)));
+ }
+
+ /**
+ * @param string $sDomain
+ *
+ * @return bool
+ */
+ public static function ValidateDomain($sDomain)
+ {
+ $aMatch = array();
+ return \preg_match('/.+(\.[a-zA-Z]+)$/', $sDomain, $aMatch) && !empty($aMatch[1]) && \in_array($aMatch[1], \explode(' ',
+ '.academy .actor .agency .audio .bar .beer .bike .blue .boutique .cab .camera .camp .capital .cards .careers .cash .catering .center .cheap .city .cleaning .clinic .clothing .club .coffee .community .company .computer .construction .consulting .contractors .cool .credit .dance .dating .democrat .dental .diamonds .digital .direct .directory .discount .domains .education .email .energy .equipment .estate .events .expert .exposed .fail .farm .fish .fitness .florist .fund .futbol .gallery .gift .glass .graphics .guru .help .holdings .holiday .host .hosting .house .institute .international .kitchen .land .life .lighting .limo .link .management .market .marketing .media .menu .moda .partners .parts .photo .photography .photos .pics .pink .press .productions .pub .red .rentals .repair .report .rest .sexy .shoes .social .solar .solutions .space .support .systems .tattoo .tax .technology .tips .today .tools .town .toys .trade .training .university .uno .vacations .vision .vodka .voyage .watch .webcam .wiki .work .works .wtf .zone .aero .asia .biz .cat .com .coop .edu .gov .info .int .jobs .mil .mobi .museum .name .net .org .pro .tel .travel .xxx '.
+ '.ac .ad .ae .af .ag .ai .al .am .an .ao .aq .ar .as .at .au .aw .ax .az .ba .bb .bd .be .bf .bg .bh .bi .bj .bm .bn .bo .br .bs .bt .bv .bw .by .bz .ca .cc .cd .cf .cg .ch .ci .ck .cl .cm .cn .co .cr .cs .cu .cv .cx .cy .cz .dd .de .dj .dk .dm .do .dz .ec .ee .eg .er .es .et .eu .fi .fj .fk .fm .fo .fr .ga .gb .gd .ge .gf .gg .gh .gi .gl .gm .gn .gp .gq .gr .gs .gt .gu .gw .gy .hk .hm .hn .hr .ht .hu .id .ie .il .im .in .io .iq .ir .is .it .je .jm .jo .jp .ke .kg .kh .ki .km .kn .kp .kr .kw .ky .kz .la .lb .lc .li .lk .lr .ls .lt .lu .lv .ly .ma .mc .md .me .mg .mh .mk .ml .mm .mn .mo .mp .mq .mr .ms .mt .mu .mv .mw .mx .my .mz .na .nc .ne .nf .ng .ni .nl .no .np .nr .nu .nz .om .pa .pe .pf .pg .ph .pk .pl .pm .pn .pr .ps .pt .pw .py .qa .re .ro .rs .ru . .rw .sa .sb .sc .sd .se .sg .sh .si .sj .sk .sl .sm .sn .so .sr .st .su .sv .sy .sz .tc .td .tf .tg .th .tj .tk .tl .tm .tn .to .tp .tr .tt .tv .tw .tz .ua .ug .uk .us .uy .uz .va .vc .ve .vg .vi .vn .vu .wf .ws .ye .yt .za .zm .zw'
+ ));
+ }
+
+ /**
+ * @param string $sIp
+ *
+ * @return bool
+ */
+ public static function ValidateIP($sIp)
+ {
+ return !empty($sIp) && $sIp === @\filter_var($sIp, FILTER_VALIDATE_IP);
+ }
+
+ /**
+ * @return \Net_IDNA2
+ */
+ private static function idn()
+ {
+ static $oIdn = null;
+ if (null === $oIdn)
+ {
+ include_once MAILSO_LIBRARY_ROOT_PATH.'Vendors/Net/IDNA2.php';
+ $oIdn = new \Net_IDNA2();
+ }
+
+ return $oIdn;
+ }
+
+ /**
+ * @param string $sStr
+ * @param bool $bLowerIfAscii = false
+ *
+ * @return string
+ */
+ public static function IdnToUtf8($sStr, $bLowerIfAscii = false)
+ {
+ if (0 < \strlen($sStr) && \preg_match('/(^|\.)xn--/i', $sStr))
+ {
+ try
+ {
+ $sStr = self::idn()->decode($sStr);
+ }
+ catch (\Exception $oException) {}
+ }
+
+ return $bLowerIfAscii ? \MailSo\Base\Utils::StrMailDomainToLowerIfAscii($sStr) : $sStr;
+ }
+
+ /**
+ * @param string $sStr
+ * @param bool $bLowerIfAscii = false
+ *
+ * @return string
+ */
+ public static function IdnToAscii($sStr, $bLowerIfAscii = false)
+ {
+ $sStr = $bLowerIfAscii ? \MailSo\Base\Utils::StrMailDomainToLowerIfAscii($sStr) : $sStr;
+
+ $sUser = '';
+ $sDomain = $sStr;
+ if (false !== \strpos($sStr, '@'))
+ {
+ $sUser = \MailSo\Base\Utils::GetAccountNameFromEmail($sStr);
+ $sDomain = \MailSo\Base\Utils::GetDomainFromEmail($sStr);
+ }
+
+ if (0 < \strlen($sDomain) && \preg_match('/[^\x20-\x7E]/', $sDomain))
+ {
+ try
+ {
+ $sDomain = self::idn()->encode($sDomain);
+ }
+ catch (\Exception $oException) {}
+ }
+
+ return ('' === $sUser ? '' : $sUser.'@').$sDomain;
+ }
+
+ /**
+ * @param string $sHash
+ * @param string $sSalt
+ *
+ * @return int
+ */
+ public static function HashToId($sHash, $sSalt = '')
+ {
+ $sData = $sHash ? @\MailSo\Base\Crypt::XxteaDecrypt(\hex2bin($sHash), \md5($sSalt)) : null;
+
+ $aMatch = array();
+ if ($sData && preg_match('/^id:(\d+)$/', $sData, $aMatch) && isset($aMatch[1]))
+ {
+ return is_numeric($aMatch[1]) ? (int) $aMatch[1] : null;
+ }
+
+ return null;
+ }
+
+ /**
+ * @param int $iID
+ * @param string $sSalt
+ *
+ * @return string
+ */
+ public static function IdToHash($iID, $sSalt = '')
+ {
+ return is_int($iID) ?
+ \bin2hex(\MailSo\Base\Crypt::XxteaEncrypt('id:'.$iID, \md5($sSalt))) : null
+ ;
+ }
+
+ /**
+ * @param string $sPassword
+ *
+ * @return bool
+ */
+ public static function PasswordWeaknessCheck($sPassword)
+ {
+ $sPassword = \trim($sPassword);
+ if (6 > \strlen($sPassword))
+ {
+ return false;
+ }
+
+ $sLine = 'password 123.456 12345678 abc123 qwerty monkey letmein dragon 111.111 baseball iloveyou trustno1 1234567 sunshine master 123.123 welcome shadow ashley football jesus michael ninja mustang password1 123456 123456789 qwerty 111111 1234567 666666 12345678 7777777 123321 654321 1234567890 123123 555555 vkontakte gfhjkm 159753 777777 temppassword qazwsx 1q2w3e 1234 112233 121212 qwertyuiop qq18ww899 987654321 12345 zxcvbn zxcvbnm 999999 samsung ghbdtn 1q2w3e4r 1111111 123654 159357 131313 qazwsxedc 123qwe 222222 asdfgh 333333 9379992 asdfghjkl 4815162342 12344321 88888888 11111111 knopka 789456 qwertyu 1q2w3e4r5t iloveyou vfhbyf marina password qweasdzxc 10203 987654 yfnfif cjkysirj nikita 888888 vfrcbv k.,jdm qwertyuiop[] qwe123 qweasd natasha 123123123 fylhtq q1w2e3 stalker 1111111111 q1w2e3r4 nastya 147258369 147258 fyfcnfcbz 1234554321 1qaz2wsx andrey 111222 147852 genius sergey 7654321 232323 123789 fktrcfylh spartak admin test 123 azerty abc123 lol123 easytocrack1 hello saravn holysh!t test123 tundra_cool2 456 dragon thomas killer root 1111 pass master aaaaaa a monkey daniel asdasd e10adc3949ba59abbe56e057f20f883e changeme computer jessica letmein mirage loulou lol superman shadow admin123 secret administrator sophie kikugalanetroot doudou liverpool hallo sunshine charlie parola 100827092 michael andrew password1 fuckyou matrix cjmasterinf internet hallo123 eminem demo gewinner pokemon abcd1234 guest ngockhoa martin sandra asdf hejsan george qweqwe lollipop lovers q1q1q1 tecktonik naruto 12 password12 password123 password1234 password12345 password123456 password1234567 password12345678 password123456789 000000 maximius 123abc baseball1 football1 soccer princess slipknot 11111 nokia super star 666999 12341234 1234321 135790 159951 212121 zzzzzz 121314 134679 142536 19921992 753951 7007 1111114 124578 19951995 258456 qwaszx zaqwsx 55555 77777 54321 qwert 22222 33333 99999 88888 66666';
+ return false === \strpos($sLine, \strtolower($sPassword));
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/Validator.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/Validator.php
new file mode 100644
index 0000000..dbaf2ff
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Base/Validator.php
@@ -0,0 +1,100 @@
+= $iMin || null === $iMin) &&
+ (null !== $iMax && $iNumber <= $iMax || null === $iMax);
+ }
+
+ /**
+ * @param int $iPort
+ *
+ * @return bool
+ */
+ public static function PortInt($iPort)
+ {
+ return \MailSo\Base\Validator::RangeInt($iPort, 0, 65535);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Cache/CacheClient.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Cache/CacheClient.php
new file mode 100644
index 0000000..e72f56e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Cache/CacheClient.php
@@ -0,0 +1,215 @@
+oDriver = null;
+ $this->sCacheIndex = '';
+ }
+
+ /**
+ * @return \MailSo\Cache\CacheClient
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @param string $sKey
+ * @param string $sValue
+ *
+ * @return bool
+ */
+ public function Set($sKey, $sValue)
+ {
+ return $this->oDriver ? $this->oDriver->Set($sKey.$this->sCacheIndex, $sValue) : false;
+ }
+
+ /**
+ * @param string $sKey
+ *
+ * @return bool
+ */
+ public function SetTimer($sKey)
+ {
+ return $this->Set($sKey.'/TIMER', time());
+ }
+
+ /**
+ * @param string $sKey
+ *
+ * @return bool
+ */
+ public function SetLock($sKey)
+ {
+ return $this->Set($sKey.'/LOCK', '1');
+ }
+
+ /**
+ * @param string $sKey
+ *
+ * @return bool
+ */
+ public function RemoveLock($sKey)
+ {
+ return $this->Set($sKey.'/LOCK', '0');
+ }
+
+ /**
+ * @param string $sKey
+ *
+ * @return bool
+ */
+ public function GetLock($sKey)
+ {
+ return '1' === $this->Get($sKey.'/LOCK');
+ }
+
+ /**
+ * @param string $sKey
+ * @param string $bClearAfterGet = false
+ *
+ * @return string
+ */
+ public function Get($sKey, $bClearAfterGet = false)
+ {
+ $sValue = '';
+
+ if ($this->oDriver)
+ {
+ $sValue = $this->oDriver->Get($sKey.$this->sCacheIndex);
+ }
+
+ if ($bClearAfterGet)
+ {
+ $this->Delete($sKey);
+ }
+
+ return $sValue;
+ }
+
+ /**
+ * @param string $sKey
+ *
+ * @return int
+ */
+ public function GetTimer($sKey)
+ {
+ $iTimer = 0;
+ $sValue = $this->Get($sKey.'/TIMER');
+ if (0 < strlen($sValue) && is_numeric($sValue))
+ {
+ $iTimer = (int) $sValue;
+ }
+
+ return $iTimer;
+ }
+
+ /**
+ * @param string $sKey
+ *
+ * @return \MailSo\Cache\CacheClient
+ */
+ public function Delete($sKey)
+ {
+ if ($this->oDriver)
+ {
+ $this->oDriver->Delete($sKey.$this->sCacheIndex);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param \MailSo\Cache\DriverInterface $oDriver
+ *
+ * @return \MailSo\Cache\CacheClient
+ */
+ public function SetDriver(\MailSo\Cache\DriverInterface $oDriver)
+ {
+ $this->oDriver = $oDriver;
+
+ return $this;
+ }
+
+ /**
+ * @param int $iTimeToClearInHours = 24
+ *
+ * @return bool
+ */
+ public function GC($iTimeToClearInHours = 24)
+ {
+ return $this->oDriver ? $this->oDriver->GC($iTimeToClearInHours) : false;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsInited()
+ {
+ return $this->oDriver instanceof \MailSo\Cache\DriverInterface;
+ }
+
+ /**
+ * @param string $sCacheIndex
+ *
+ * @return \MailSo\Cache\CacheClient
+ */
+ public function SetCacheIndex($sCacheIndex)
+ {
+ $this->sCacheIndex = 0 < \strlen($sCacheIndex) ? "\x0".$sCacheIndex : '';
+
+ return $this;
+ }
+
+ /**
+ * @param bool $bCache = false
+ *
+ * @return bool
+ */
+ public function Verify($bCache = false)
+ {
+ if ($this->oDriver)
+ {
+ $sCacheData = \gmdate('Y-m-d-H');
+ if ($bCache && $sCacheData === $this->Get('__verify_key__'))
+ {
+ return true;
+ }
+
+ return $this->Set('__verify_key__', $sCacheData);
+ }
+
+ return false;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Cache/DriverInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Cache/DriverInterface.php
new file mode 100644
index 0000000..8751ba1
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Cache/DriverInterface.php
@@ -0,0 +1,48 @@
+sKeyPrefix = $sKeyPrefix;
+ if (!empty($this->sKeyPrefix))
+ {
+ $this->sKeyPrefix =
+ \preg_replace('/[^a-zA-Z0-9_]/', '_', rtrim(trim($this->sKeyPrefix), '\\/')).'/';
+ }
+ }
+
+ /**
+ * @param string $sKeyPrefix = ''
+ *
+ * @return \MailSo\Cache\Drivers\APC
+ */
+ public static function NewInstance($sKeyPrefix = '')
+ {
+ return new self($sKeyPrefix);
+ }
+
+ /**
+ * @param string $sKey
+ * @param string $sValue
+ *
+ * @return bool
+ */
+ public function Set($sKey, $sValue)
+ {
+ return \apc_store($this->generateCachedKey($sKey), (string) $sValue);
+ }
+
+ /**
+ * @param string $sKey
+ *
+ * @return string
+ */
+ public function Get($sKey)
+ {
+ $sValue = \apc_fetch($this->generateCachedKey($sKey));
+ return \is_string($sValue) ? $sValue : '';
+ }
+
+ /**
+ * @param string $sKey
+ *
+ * @return void
+ */
+ public function Delete($sKey)
+ {
+ \apc_delete($this->generateCachedKey($sKey));
+ }
+
+ /**
+ * @param int $iTimeToClearInHours = 24
+ *
+ * @return bool
+ */
+ public function GC($iTimeToClearInHours = 24)
+ {
+ if (0 === $iTimeToClearInHours)
+ {
+ return \apc_clear_cache('user');
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $sKey
+ *
+ * @return string
+ */
+ private function generateCachedKey($sKey)
+ {
+ return $this->sKeyPrefix.\sha1($sKey);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Cache/Drivers/File.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Cache/Drivers/File.php
new file mode 100644
index 0000000..bee1c51
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Cache/Drivers/File.php
@@ -0,0 +1,153 @@
+sCacheFolder = $sCacheFolder;
+ $this->sCacheFolder = rtrim(trim($this->sCacheFolder), '\\/').'/';
+
+ $this->sKeyPrefix = $sKeyPrefix;
+ if (!empty($this->sKeyPrefix))
+ {
+ $this->sKeyPrefix = \str_pad(\preg_replace('/[^a-zA-Z0-9_]/', '_',
+ rtrim(trim($this->sKeyPrefix), '\\/')), 5, '_');
+
+ $this->sKeyPrefix = '__/'.
+ \substr($this->sKeyPrefix, 0, 2).'/'.\substr($this->sKeyPrefix, 2, 2).'/'.
+ $this->sKeyPrefix.'/';
+ }
+ }
+
+ /**
+ * @param string $sCacheFolder
+ * @param string $sKeyPrefix = ''
+ *
+ * @return \MailSo\Cache\Drivers\File
+ */
+ public static function NewInstance($sCacheFolder, $sKeyPrefix = '')
+ {
+ return new self($sCacheFolder, $sKeyPrefix);
+ }
+
+ /**
+ * @param string $sKey
+ * @param string $sValue
+ *
+ * @return bool
+ */
+ public function Set($sKey, $sValue)
+ {
+ $sPath = $this->generateCachedFileName($sKey, true);
+ return '' === $sPath ? false : false !== \file_put_contents($sPath, $sValue);
+ }
+
+ /**
+ * @param string $sKey
+ *
+ * @return string
+ */
+ public function Get($sKey)
+ {
+ $sValue = '';
+ $sPath = $this->generateCachedFileName($sKey);
+ if ('' !== $sPath && \file_exists($sPath))
+ {
+ $sValue = \file_get_contents($sPath);
+ }
+
+ return \is_string($sValue) ? $sValue : '';
+ }
+
+ /**
+ * @param string $sKey
+ *
+ * @return void
+ */
+ public function Delete($sKey)
+ {
+ $sPath = $this->generateCachedFileName($sKey);
+ if ('' !== $sPath && \file_exists($sPath))
+ {
+ \unlink($sPath);
+ }
+ }
+
+ /**
+ * @param int $iTimeToClearInHours = 24
+ *
+ * @return bool
+ */
+ public function GC($iTimeToClearInHours = 24)
+ {
+ if (0 < $iTimeToClearInHours)
+ {
+ \MailSo\Base\Utils::RecTimeDirRemove($this->sCacheFolder, 60 * 60 * $iTimeToClearInHours, \time());
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $sKey
+ * @param bool $bMkDir = false
+ *
+ * @return string
+ */
+ private function generateCachedFileName($sKey, $bMkDir = false)
+ {
+ $sFilePath = '';
+ if (3 < \strlen($sKey))
+ {
+ $sKeyPath = \sha1($sKey);
+ $sKeyPath = \substr($sKeyPath, 0, 2).'/'.\substr($sKeyPath, 2, 2).'/'.$sKeyPath;
+
+ $sFilePath = $this->sCacheFolder.$this->sKeyPrefix.$sKeyPath;
+ if ($bMkDir && !\is_dir(\dirname($sFilePath)))
+ {
+ if (!@\mkdir(\dirname($sFilePath), 0755, true))
+ {
+ if (!@\mkdir(\dirname($sFilePath), 0755, true))
+ {
+ $sFilePath = '';
+ }
+ }
+ }
+ }
+
+ return $sFilePath;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Cache/Drivers/Memcache.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Cache/Drivers/Memcache.php
new file mode 100644
index 0000000..35094b4
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Cache/Drivers/Memcache.php
@@ -0,0 +1,144 @@
+sHost = $sHost;
+ $this->iPost = $iPost;
+ $this->iExpire = 0 < $iExpire ? $iExpire : 43200;
+
+ $this->oMem = new \Memcache();
+ if (!$this->oMem->connect($this->sHost, $this->iPost))
+ {
+ $this->oMem = null;
+ }
+
+ $this->sKeyPrefix = $sKeyPrefix;
+ if (!empty($this->sKeyPrefix))
+ {
+ $this->sKeyPrefix =
+ \preg_replace('/[^a-zA-Z0-9_]/', '_', rtrim(trim($this->sKeyPrefix), '\\/')).'/';
+ }
+ }
+
+ /**
+ * @param string $sHost = '127.0.0.1'
+ * @param int $iPost = 11211
+ * @param int $iExpire = 43200
+ * @param string $sKeyPrefix = ''
+ *
+ * @return \MailSo\Cache\Drivers\APC
+ */
+ public static function NewInstance($sHost = '127.0.0.1', $iPost = 11211, $iExpire = 43200, $sKeyPrefix = '')
+ {
+ return new self($sHost, $iPost, $iExpire, $sKeyPrefix);
+ }
+
+ /**
+ * @param string $sKey
+ * @param string $sValue
+ *
+ * @return bool
+ */
+ public function Set($sKey, $sValue)
+ {
+ return $this->oMem ? $this->oMem->set($this->generateCachedKey($sKey), $sValue, 0, $this->iExpire) : false;
+ }
+
+ /**
+ * @param string $sKey
+ *
+ * @return string
+ */
+ public function Get($sKey)
+ {
+ $sValue = $this->oMem ? $this->oMem->get($this->generateCachedKey($sKey)) : '';
+ return \is_string($sValue) ? $sValue : '';
+ }
+
+ /**
+ * @param string $sKey
+ *
+ * @return void
+ */
+ public function Delete($sKey)
+ {
+ if ($this->oMem)
+ {
+ $this->oMem->delete($this->generateCachedKey($sKey));
+ }
+ }
+
+ /**
+ * @param int $iTimeToClearInHours = 24
+ *
+ * @return bool
+ */
+ public function GC($iTimeToClearInHours = 24)
+ {
+ if (0 === $iTimeToClearInHours && $this->oMem)
+ {
+ return $this->oMem->flush();
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $sKey
+ *
+ * @return string
+ */
+ private function generateCachedKey($sKey)
+ {
+ return $this->sKeyPrefix.\sha1($sKey);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Config.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Config.php
new file mode 100644
index 0000000..f5b84ab
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Config.php
@@ -0,0 +1,93 @@
+sContentType = $sContentType;
+ $this->sCharset = $sCharset;
+ $this->aBodyParams = $aBodyParams;
+ $this->sContentID = $sContentID;
+ $this->sDescription = $sDescription;
+ $this->sMailEncodingName = $sMailEncodingName;
+ $this->sDisposition = $sDisposition;
+ $this->aDispositionParams = $aDispositionParams;
+ $this->sFileName = $sFileName;
+ $this->sLanguage = $sLanguage;
+ $this->sLocation = $sLocation;
+ $this->iSize = $iSize;
+ $this->iTextLineCount = $iTextLineCount;
+ $this->sPartID = $sPartID;
+ $this->aSubParts = $aSubParts;
+ }
+
+ /**
+ * return string
+ */
+ public function MailEncodingName()
+ {
+ return $this->sMailEncodingName;
+ }
+
+ /**
+ * return string
+ */
+ public function PartID()
+ {
+ return (string) $this->sPartID;
+ }
+
+ /**
+ * return string
+ */
+ public function FileName()
+ {
+ return $this->sFileName;
+ }
+
+ /**
+ * return string
+ */
+ public function ContentType()
+ {
+ return $this->sContentType;
+ }
+
+ /**
+ * return int
+ */
+ public function Size()
+ {
+ return (int) $this->iSize;
+ }
+
+ /**
+ * return int
+ */
+ public function EstimatedSize()
+ {
+ $fCoefficient = 1;
+ switch (\strtolower($this->MailEncodingName()))
+ {
+ case 'base64':
+ $fCoefficient = 0.75;
+ break;
+ case 'quoted-printable':
+ $fCoefficient = 0.44;
+ break;
+ }
+
+ return (int) ($this->Size() * $fCoefficient);
+ }
+
+ /**
+ * return string
+ */
+ public function Charset()
+ {
+ return $this->sCharset;
+ }
+
+
+ /**
+ * return string
+ */
+ public function ContentID()
+ {
+ return (null === $this->sContentID) ? '' : $this->sContentID;
+ }
+
+ /**
+ * return string
+ */
+ public function ContentLocation()
+ {
+ return (null === $this->sLocation) ? '' : $this->sLocation;
+ }
+
+ /**
+ * return bool
+ */
+ public function IsInline()
+ {
+ return (null === $this->sDisposition) ?
+ (0 < \strlen($this->ContentID())) : ('inline' === strtolower($this->sDisposition));
+ }
+
+ /**
+ * return bool
+ */
+ public function IsImage()
+ {
+ return 'image' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
+ }
+
+ /**
+ * return bool
+ */
+ public function IsArchive()
+ {
+ return 'archive' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsPdf()
+ {
+ return 'pdf' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsDoc()
+ {
+ return 'doc' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsPgpSignature()
+ {
+ return \in_array(\strtolower($this->ContentType()),
+ array('application/pgp-signature', 'application/pkcs7-signature'));
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsAttachBodyPart()
+ {
+ $bResult = (
+ (null !== $this->sDisposition && 'attachment' === \strtolower($this->sDisposition))
+ );
+
+ if (!$bResult && null !== $this->sContentType)
+ {
+ $sContentType = \strtolower($this->sContentType);
+ $bResult = false === \strpos($sContentType, 'multipart/') &&
+ 'text/html' !== $sContentType && 'text/plain' !== $sContentType;
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsFlowedFormat()
+ {
+ $bResult = !empty($this->aBodyParams['format']) &&
+ 'flowed' === \strtolower(\trim($this->aBodyParams['format']));
+
+ if ($bResult && \in_array(\strtolower($this->MailEncodingName()), array('base64', 'quoted-printable')))
+ {
+ $bResult = false;
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @return array|null
+ */
+ public function SearchPlainParts()
+ {
+ $aReturn = array();
+ $aParts = $this->SearchByContentType('text/plain');
+ foreach ($aParts as $oPart)
+ {
+ if (!$oPart->IsAttachBodyPart())
+ {
+ $aReturn[] = $oPart;
+ }
+ }
+ return $aReturn;
+ }
+
+ /**
+ * @return array|null
+ */
+ public function SearchHtmlParts()
+ {
+ $aReturn = array();
+ $aParts = $this->SearchByContentType('text/html');
+
+ foreach ($aParts as $oPart)
+ {
+ if (!$oPart->IsAttachBodyPart())
+ {
+ $aReturn[] = $oPart;
+ }
+ }
+
+ return $aReturn;
+ }
+
+ /**
+ * @return \MailSo\Imap\BodyStructure|null
+ */
+ public function SearchInlineEncryptedPart()
+ {
+ if ('multipart/encrypted' === \strtolower($this->ContentType()))
+ {
+ $aSearchParts = $this->SearchByCallback(function ($oItem) {
+ return $oItem->IsInline();
+ });
+
+ if (is_array($aSearchParts) && 1 === \count($aSearchParts) && isset($aSearchParts[0]))
+ {
+ return $aSearchParts[0];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @return array|null
+ */
+ public function SearchHtmlOrPlainParts()
+ {
+ $mResult = $this->SearchHtmlParts();
+ if (null === $mResult || (\is_array($mResult) && 0 === count($mResult)))
+ {
+ $mResult = $this->SearchPlainParts();
+ }
+
+ if (null === $mResult || (\is_array($mResult) && 0 === count($mResult)))
+ {
+ $oPart = $this->SearchInlineEncryptedPart();
+ if ($oPart instanceof \MailSo\Imap\BodyStructure)
+ {
+ $mResult = array($oPart);
+ }
+ }
+
+ return $mResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function SearchCharset()
+ {
+ $sResult = '';
+ $mParts = array();
+
+ $mHtmlParts = $this->SearchHtmlParts();
+ $mPlainParts = $this->SearchPlainParts();
+
+ if (\is_array($mHtmlParts) && 0 < \count($mHtmlParts))
+ {
+ $mParts = \array_merge($mParts, $mHtmlParts);
+ }
+
+ if (\is_array($mPlainParts) && 0 < \count($mPlainParts))
+ {
+ $mParts = \array_merge($mParts, $mPlainParts);
+ }
+
+ foreach ($mParts as $oPart)
+ {
+ $sResult = $oPart ? $oPart->Charset() : '';
+ if (!empty($sResult))
+ {
+ break;
+ }
+ }
+
+ if (0 === strlen($sResult))
+ {
+ $aParts = $this->SearchAttachmentsParts();
+ foreach ($aParts as $oPart)
+ {
+ if (0 === \strlen($sResult))
+ {
+ $sResult = $oPart ? $oPart->Charset() : '';
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param mixed $fCallback
+ *
+ * @return array
+ */
+ public function SearchByCallback($fCallback)
+ {
+ $aReturn = array();
+ if (\call_user_func($fCallback, $this))
+ {
+ $aReturn[] = $this;
+ }
+
+ if (\is_array($this->aSubParts) && 0 < \count($this->aSubParts))
+ {
+ foreach ($this->aSubParts as /* @var $oSubPart \MailSo\Imap\BodyStructure */ &$oSubPart)
+ {
+ $aReturn = \array_merge($aReturn, $oSubPart->SearchByCallback($fCallback));
+ }
+ }
+
+ return $aReturn;
+ }
+
+ /**
+ * @return array
+ */
+ public function SearchAttachmentsParts()
+ {
+ return $this->SearchByCallback(function ($oItem) {
+ return $oItem->IsAttachBodyPart();
+ });
+ }
+
+ /**
+ * @param string $sContentType
+ *
+ * @return array
+ */
+ public function SearchByContentType($sContentType)
+ {
+ $sContentType = \strtolower($sContentType);
+ return $this->SearchByCallback(function ($oItem) use ($sContentType) {
+ return $sContentType === $oItem->ContentType();
+ });
+ }
+
+ /**
+ * @param string $sMimeIndex
+ *
+ * @return \MailSo\Imap\BodyStructure
+ */
+ public function GetPartByMimeIndex($sMimeIndex)
+ {
+ $oPart = null;
+ if (0 < \strlen($sMimeIndex))
+ {
+ if ($sMimeIndex === $this->sPartID)
+ {
+ $oPart = $this;
+ }
+
+ if (null === $oPart && is_array($this->aSubParts) && 0 < count($this->aSubParts))
+ {
+ foreach ($this->aSubParts as /* @var $oSubPart \MailSo\Imap\BodyStructure */ &$oSubPart)
+ {
+ $oPart = $oSubPart->GetPartByMimeIndex($sMimeIndex);
+ if (null !== $oPart)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ return $oPart;
+ }
+
+ /**
+ * @param array $aParams
+ * @param string $sParamName
+ * @param string $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8
+ *
+ * @return string
+ */
+ private static function decodeAttrParamenter($aParams, $sParamName, $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8)
+ {
+ $sResult = '';
+ if (isset($aParams[$sParamName]))
+ {
+ $sResult = \MailSo\Base\Utils::DecodeHeaderValue($aParams[$sParamName], $sCharset);
+ }
+ else if (isset($aParams[$sParamName.'*']))
+ {
+ $aValueParts = \explode("''", $aParams[$sParamName.'*'], 2);
+ if (\is_array($aValueParts) && 2 === \count($aValueParts))
+ {
+ $sCharset = isset($aValueParts[0]) ? $aValueParts[0] : \MailSo\Base\Enumerations\Charset::UTF_8;
+
+ $sResult = \MailSo\Base\Utils::ConvertEncoding(
+ \urldecode($aValueParts[1]), $sCharset, \MailSo\Base\Enumerations\Charset::UTF_8);
+ }
+ else
+ {
+ $sResult = \urldecode($aParams[$sParamName.'*']);
+ }
+ }
+ else
+ {
+ $sCharset = '';
+ $sCharsetIndex = -1;
+
+ $aFileNames = array();
+ foreach ($aParams as $sName => $sValue)
+ {
+ $aMatches = array();
+ if (\preg_match('/^'.\preg_quote($sParamName, '/').'\*([0-9]+)\*$/i', $sName, $aMatches))
+ {
+ $iIndex = (int) $aMatches[1];
+ if ($sCharsetIndex < $iIndex && false !== \strpos($sValue, "''"))
+ {
+ $aValueParts = \explode("''", $sValue, 2);
+ if (\is_array($aValueParts) && 2 === \count($aValueParts) && 0 < \strlen($aValueParts[0]))
+ {
+ $sCharsetIndex = $iIndex;
+ $sCharset = $aValueParts[0];
+ $sValue = $aValueParts[1];
+ }
+ }
+
+ $aFileNames[$iIndex] = $sValue;
+ }
+ }
+
+ if (0 < \count($aFileNames))
+ {
+ \ksort($aFileNames, SORT_NUMERIC);
+ $sResult = \implode(\array_values($aFileNames));
+ $sResult = \urldecode($sResult);
+
+ if (0 < \strlen($sCharset))
+ {
+ $sResult = \MailSo\Base\Utils::ConvertEncoding($sResult,
+ $sCharset, \MailSo\Base\Enumerations\Charset::UTF_8);
+ }
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param array $aBodyStructure
+ * @param string $sPartID = ''
+ *
+ * @return \MailSo\Imap\BodyStructure
+ */
+ public static function NewInstance(array $aBodyStructure, $sPartID = '')
+ {
+ if (!\is_array($aBodyStructure) || 2 > \count($aBodyStructure))
+ {
+ return null;
+ }
+ else
+ {
+ $sBodyMainType = null;
+ if (\is_string($aBodyStructure[0]) && 'NIL' !== $aBodyStructure[0])
+ {
+ $sBodyMainType = $aBodyStructure[0];
+ }
+
+ $sBodySubType = null;
+ $sContentType = '';
+ $aSubParts = null;
+ $aBodyParams = array();
+ $sName = null;
+ $sCharset = null;
+ $sContentID = null;
+ $sDescription = null;
+ $sMailEncodingName = null;
+ $iSize = 0;
+ $iTextLineCount = 0; // valid for rfc822/message and text parts
+ $iExtraItemPos = 0; // list index of items which have no well-established position (such as 0, 1, 5, etc).
+
+ if (null === $sBodyMainType)
+ {
+ // Process multipart body structure
+ if (!\is_array($aBodyStructure[0]))
+ {
+ return null;
+ }
+ else
+ {
+ $sBodyMainType = 'multipart';
+ $sSubPartIDPrefix = '';
+ if (0 === \strlen($sPartID) || '.' === $sPartID[\strlen($sPartID) - 1])
+ {
+ // This multi-part is root part of message.
+ $sSubPartIDPrefix = $sPartID;
+ $sPartID .= 'TEXT';
+ }
+ else if (0 < \strlen($sPartID))
+ {
+ // This multi-part is a part of another multi-part.
+ $sSubPartIDPrefix = $sPartID.'.';
+ }
+
+ $aSubParts = array();
+ $iIndex = 1;
+
+ while ($iExtraItemPos < \count($aBodyStructure) && \is_array($aBodyStructure[$iExtraItemPos]))
+ {
+ $oPart = self::NewInstance($aBodyStructure[$iExtraItemPos], $sSubPartIDPrefix.$iIndex);
+ if (null === $oPart)
+ {
+ return null;
+ }
+ else
+ {
+ // For multipart, we have no charset info in the part itself. Thus,
+ // obtain charset from nested parts.
+ if ($sCharset == null)
+ {
+ $sCharset = $oPart->Charset();
+ }
+
+ $aSubParts[] = $oPart;
+ $iExtraItemPos++;
+ $iIndex++;
+ }
+ }
+ }
+
+ if ($iExtraItemPos < \count($aBodyStructure))
+ {
+ if (!\is_string($aBodyStructure[$iExtraItemPos]) || 'NIL' === $aBodyStructure[$iExtraItemPos])
+ {
+ return null;
+ }
+
+ $sBodySubType = \strtolower($aBodyStructure[$iExtraItemPos]);
+ $iExtraItemPos++;
+ }
+
+ if ($iExtraItemPos < \count($aBodyStructure))
+ {
+ $sBodyParamList = $aBodyStructure[$iExtraItemPos];
+ if (\is_array($sBodyParamList))
+ {
+ $aBodyParams = self::getKeyValueListFromArrayList($sBodyParamList);
+ }
+ }
+
+ $iExtraItemPos++;
+ }
+ else
+ {
+ // Process simple (singlepart) body structure
+ if (7 > \count($aBodyStructure))
+ {
+ return null;
+ }
+
+ $sBodyMainType = \strtolower($sBodyMainType);
+ if (!\is_string($aBodyStructure[1]) || 'NIL' === $aBodyStructure[1])
+ {
+ return null;
+ }
+
+ $sBodySubType = \strtolower($aBodyStructure[1]);
+
+ $aBodyParamList = $aBodyStructure[2];
+ if (\is_array($aBodyParamList))
+ {
+ $aBodyParams = self::getKeyValueListFromArrayList($aBodyParamList);
+ if (isset($aBodyParams['charset']))
+ {
+ $sCharset = $aBodyParams['charset'];
+ }
+
+ if (\is_array($aBodyParams))
+ {
+ $sName = self::decodeAttrParamenter($aBodyParams, 'name', $sContentType);
+ }
+ }
+
+ if (null !== $aBodyStructure[3] && 'NIL' !== $aBodyStructure[3])
+ {
+ if (!\is_string($aBodyStructure[3]))
+ {
+ return null;
+ }
+
+ $sContentID = $aBodyStructure[3];
+ }
+
+ if (null !== $aBodyStructure[4] && 'NIL' !== $aBodyStructure[4])
+ {
+ if (!\is_string($aBodyStructure[4]))
+ {
+ return null;
+ }
+
+ $sDescription = $aBodyStructure[4];
+ }
+
+ if (null !== $aBodyStructure[5] && 'NIL' !== $aBodyStructure[5])
+ {
+ if (!\is_string($aBodyStructure[5]))
+ {
+ return null;
+ }
+ $sMailEncodingName = $aBodyStructure[5];
+ }
+
+ if (\is_numeric($aBodyStructure[6]))
+ {
+ $iSize = (int) $aBodyStructure[6];
+ }
+ else
+ {
+ $iSize = -1;
+ }
+
+ if (0 === \strlen($sPartID) || '.' === $sPartID[\strlen($sPartID) - 1])
+ {
+ // This is the only sub-part of the message (otherwise, it would be
+ // one of sub-parts of a multi-part, and partID would already be fully set up).
+ $sPartID .= '1';
+ }
+
+ $iExtraItemPos = 7;
+ if ('text' === $sBodyMainType)
+ {
+ if ($iExtraItemPos < \count($aBodyStructure))
+ {
+ if (\is_numeric($aBodyStructure[$iExtraItemPos]))
+ {
+ $iTextLineCount = (int) $aBodyStructure[$iExtraItemPos];
+ }
+ else
+ {
+ $iTextLineCount = -1;
+ }
+ }
+ else
+ {
+ $iTextLineCount = -1;
+ }
+
+ $iExtraItemPos++;
+ }
+ else if ('message' === $sBodyMainType && 'rfc822' === $sBodySubType)
+ {
+ if ($iExtraItemPos + 2 < \count($aBodyStructure))
+ {
+ if (\is_numeric($aBodyStructure[$iExtraItemPos + 2]))
+ {
+ $iTextLineCount = (int) $aBodyStructure[$iExtraItemPos + 2];
+ }
+ else
+ {
+ $iTextLineCount = -1;
+ }
+ }
+ else
+ {
+ $iTextLineCount = -1;
+ }
+
+ $iExtraItemPos += 3;
+ }
+
+ $iExtraItemPos++; // skip MD5 digest of the body because most mail servers leave it NIL anyway
+ }
+
+ $sContentType = $sBodyMainType.'/'.$sBodySubType;
+
+ $sDisposition = null;
+ $aDispositionParams = null;
+ $sFileName = null;
+
+ if ($iExtraItemPos < \count($aBodyStructure))
+ {
+ $aDispList = $aBodyStructure[$iExtraItemPos];
+ if (\is_array($aDispList) && 1 < \count($aDispList))
+ {
+ if (null !== $aDispList[0])
+ {
+ if (\is_string($aDispList[0]) && 'NIL' !== $aDispList[0])
+ {
+ $sDisposition = $aDispList[0];
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+
+ $aDispParamList = $aDispList[1];
+ if (\is_array($aDispParamList))
+ {
+ $aDispositionParams = self::getKeyValueListFromArrayList($aDispParamList);
+ if (\is_array($aDispositionParams))
+ {
+ $sFileName = self::decodeAttrParamenter($aDispositionParams, 'filename', $sCharset);
+ }
+ }
+ }
+
+ $iExtraItemPos++;
+
+ $sLanguage = null;
+ if ($iExtraItemPos < count($aBodyStructure))
+ {
+ if (null !== $aBodyStructure[$iExtraItemPos] && 'NIL' !== $aBodyStructure[$iExtraItemPos])
+ {
+ if (\is_array($aBodyStructure[$iExtraItemPos]))
+ {
+ $sLanguage = \implode(',', $aBodyStructure[$iExtraItemPos]);
+ }
+ else if (\is_string($aBodyStructure[$iExtraItemPos]))
+ {
+ $sLanguage = $aBodyStructure[$iExtraItemPos];
+ }
+ }
+ $iExtraItemPos++;
+ }
+
+ $sLocation = null;
+ if ($iExtraItemPos < \count($aBodyStructure))
+ {
+ if (null !== $aBodyStructure[$iExtraItemPos] && 'NIL' !== $aBodyStructure[$iExtraItemPos])
+ {
+ if (\is_string($aBodyStructure[$iExtraItemPos]))
+ {
+ $sLocation = $aBodyStructure[$iExtraItemPos];
+ }
+ }
+ $iExtraItemPos++;
+ }
+
+ return new self(
+ $sContentType,
+ $sCharset,
+ $aBodyParams,
+ $sContentID,
+ $sDescription,
+ $sMailEncodingName,
+ $sDisposition,
+ $aDispositionParams,
+ \MailSo\Base\Utils::Utf8Clear((null === $sFileName || 0 === \strlen($sFileName)) ? $sName : $sFileName),
+ $sLanguage,
+ $sLocation,
+ $iSize,
+ $iTextLineCount,
+ $sPartID,
+ $aSubParts
+ );
+ }
+ }
+
+ /**
+ * @param array $aBodyStructure
+ * @param string $sSubPartID
+ *
+ * @return \MailSo\Imap\BodyStructure|null
+ */
+ public static function NewInstanceFromRfc822SubPart(array $aBodyStructure, $sSubPartID)
+ {
+ $oBody = null;
+ $aBodySubStructure = self::findPartByIndexInArray($aBodyStructure, $sSubPartID);
+ if ($aBodySubStructure && \is_array($aBodySubStructure) && isset($aBodySubStructure[8]))
+ {
+ $oBody = self::NewInstance($aBodySubStructure[8], $sSubPartID);
+ }
+
+ return $oBody;
+ }
+
+ /**
+ * @param array $aList
+ * @param string $sPartID
+ *
+ * @return array|null
+ */
+ private static function findPartByIndexInArray(array $aList, $sPartID)
+ {
+ $bFind = false;
+ $aPath = \explode('.', ''.$sPartID);
+ $aCurrentPart = $aList;
+
+ foreach ($aPath as $iPos => $iNum)
+ {
+ $iIndex = \intval($iNum) - 1;
+ if (0 <= $iIndex && 0 < $iPos ? isset($aCurrentPart[8][$iIndex]) : isset($aCurrentPart[$iIndex]))
+ {
+ $aCurrentPart = 0 < $iPos ? $aCurrentPart[8][$iIndex] : $aCurrentPart[$iIndex];
+ $bFind = true;
+ }
+ }
+
+ return $bFind ? $aCurrentPart : null;
+ }
+
+ /**
+ * Returns dict with key="charset" and value="US-ASCII" for array ("CHARSET" "US-ASCII").
+ * Keys are lowercased (StringDictionary itself does this), values are not altered.
+ *
+ * @param array $aList
+ *
+ * @return array
+ */
+ private static function getKeyValueListFromArrayList(array $aList)
+ {
+ $aDict = null;
+ if (0 === \count($aList) % 2)
+ {
+ $aDict = array();
+ for ($iIndex = 0, $iLen = \count($aList); $iIndex < $iLen; $iIndex += 2)
+ {
+ if (\is_string($aList[$iIndex]) && isset($aList[$iIndex + 1]) && \is_string($aList[$iIndex + 1]))
+ {
+ $aDict[\strtolower($aList[$iIndex])] = $aList[$iIndex + 1];
+ }
+ }
+ }
+
+ return $aDict;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/Enumerations/FetchType.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/Enumerations/FetchType.php
new file mode 100644
index 0000000..fe6a36e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/Enumerations/FetchType.php
@@ -0,0 +1,127 @@
+GetLastResponse();
+ if ($oResponse && $oResponse->IsStatusResponse && !empty($oResponse->HumanReadable) &&
+ isset($oResponse->OptionalResponse[0]) && 'ALERT' === $oResponse->OptionalResponse[0])
+ {
+ $sResult = $oResponse->HumanReadable;
+ }
+
+ return $sResult;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/Exceptions/ResponseException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/Exceptions/ResponseException.php
new file mode 100644
index 0000000..24f0d8c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/Exceptions/ResponseException.php
@@ -0,0 +1,57 @@
+aResponses = $aResponses;
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function GetResponses()
+ {
+ return $this->aResponses;
+ }
+
+ /**
+ * @return \MailSo\Imap\Response|null
+ */
+ public function GetLastResponse()
+ {
+ return 0 < count($this->aResponses) ? $this->aResponses[count($this->aResponses) - 1] : null;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/Exceptions/ResponseNotFoundException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/Exceptions/ResponseNotFoundException.php
new file mode 100644
index 0000000..2d4d029
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/Exceptions/ResponseNotFoundException.php
@@ -0,0 +1,19 @@
+oImapResponse = $oImapResponse;
+ $this->aEnvelopeCache = null;
+ }
+
+ /**
+ * @param \MailSo\Imap\Response $oImapResponse
+ * @return \MailSo\Imap\FetchResponse
+ */
+ public static function NewInstance($oImapResponse)
+ {
+ return new self($oImapResponse);
+ }
+
+ /**
+ * @param bool $bForce = false
+ *
+ * @return array|null
+ */
+ public function GetEnvelope($bForce = false)
+ {
+ if (null === $this->aEnvelopeCache || $bForce)
+ {
+ $this->aEnvelopeCache = $this->GetFetchValue(Enumerations\FetchType::ENVELOPE);
+ }
+ return $this->aEnvelopeCache;
+ }
+
+ /**
+ * @param int $iIndex
+ * @param mixed $mNullResult = null
+ *
+ * @return mixed
+ */
+ public function GetFetchEnvelopeValue($iIndex, $mNullResult)
+ {
+ return self::findEnvelopeIndex($this->GetEnvelope(), $iIndex, $mNullResult);
+ }
+
+ /**
+ * @param int $iIndex
+ * @param string $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1
+ *
+ * @return \MailSo\Mime\EmailCollection|null
+ */
+ public function GetFetchEnvelopeEmailCollection($iIndex, $sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1)
+ {
+ $oResult = null;
+ $aEmails = $this->GetFetchEnvelopeValue($iIndex, null);
+ if (is_array($aEmails) && 0 < count($aEmails))
+ {
+ $oResult = \MailSo\Mime\EmailCollection::NewInstance();
+ foreach ($aEmails as $aEmailItem)
+ {
+ if (is_array($aEmailItem) && 4 === count($aEmailItem))
+ {
+ $sDisplayName = \MailSo\Base\Utils::DecodeHeaderValue(
+ self::findEnvelopeIndex($aEmailItem, 0, ''), $sParentCharset);
+
+ $sRemark = \MailSo\Base\Utils::DecodeHeaderValue(
+ self::findEnvelopeIndex($aEmailItem, 1, ''), $sParentCharset);
+
+ $sLocalPart = self::findEnvelopeIndex($aEmailItem, 2, '');
+ $sDomainPart = self::findEnvelopeIndex($aEmailItem, 3, '');
+
+ if (0 < strlen($sLocalPart) && 0 < strlen($sDomainPart))
+ {
+ $oResult->Add(
+ \MailSo\Mime\Email::NewInstance(
+ $sLocalPart.'@'.$sDomainPart, $sDisplayName, $sRemark)
+ );
+ }
+ }
+ }
+ }
+
+ return $oResult;
+ }
+
+ /**
+ * @param string $sRfc822SubMimeIndex = ''
+ *
+ * @return \MailSo\Imap\BodyStructure|null
+ */
+ public function GetFetchBodyStructure($sRfc822SubMimeIndex = '')
+ {
+ $oBodyStructure = null;
+ $aBodyStructureArray = $this->GetFetchValue(Enumerations\FetchType::BODYSTRUCTURE);
+
+ if (is_array($aBodyStructureArray))
+ {
+ if (0 < strlen($sRfc822SubMimeIndex))
+ {
+ $oBodyStructure = BodyStructure::NewInstanceFromRfc822SubPart($aBodyStructureArray, $sRfc822SubMimeIndex);
+ }
+ else
+ {
+ $oBodyStructure = BodyStructure::NewInstance($aBodyStructureArray);
+ }
+ }
+
+ return $oBodyStructure;
+ }
+
+ /**
+ * @param string $sFetchItemName
+ *
+ * @return mixed
+ */
+ public function GetFetchValue($sFetchItemName)
+ {
+ $mReturn = null;
+ $bNextIsValue = false;
+
+ if (Enumerations\FetchType::INDEX === $sFetchItemName)
+ {
+ $mReturn = $this->oImapResponse->ResponseList[1];
+ }
+ else if (isset($this->oImapResponse->ResponseList[3]) && \is_array($this->oImapResponse->ResponseList[3]))
+ {
+ foreach ($this->oImapResponse->ResponseList[3] as $mItem)
+ {
+ if ($bNextIsValue)
+ {
+ $mReturn = $mItem;
+ break;
+ }
+
+ if ($sFetchItemName === $mItem)
+ {
+ $bNextIsValue = true;
+ }
+ }
+ }
+
+ return $mReturn;
+ }
+
+ /**
+ * @param string $sRfc822SubMimeIndex = ''
+ *
+ * @return string
+ */
+ public function GetHeaderFieldsValue($sRfc822SubMimeIndex = '')
+ {
+ $sReturn = '';
+ $bNextIsValue = false;
+
+ $sRfc822SubMimeIndex = 0 < \strlen($sRfc822SubMimeIndex) ? ''.$sRfc822SubMimeIndex.'.' : '';
+
+ if (isset($this->oImapResponse->ResponseList[3]) && \is_array($this->oImapResponse->ResponseList[3]))
+ {
+ foreach ($this->oImapResponse->ResponseList[3] as $mItem)
+ {
+ if ($bNextIsValue)
+ {
+ $sReturn = (string) $mItem;
+ break;
+ }
+
+ if (\is_string($mItem) && (
+ $mItem === 'BODY['.$sRfc822SubMimeIndex.'HEADER]' ||
+ 0 === \strpos($mItem, 'BODY['.$sRfc822SubMimeIndex.'HEADER.FIELDS') ||
+ $mItem === 'BODY['.$sRfc822SubMimeIndex.'MIME]'))
+ {
+ $bNextIsValue = true;
+ }
+ }
+ }
+
+ return $sReturn;
+ }
+
+ private static function findFetchUidAndSize($aList)
+ {
+ $bUid = false;
+ $bSize = false;
+ if (is_array($aList))
+ {
+ foreach ($aList as $mItem)
+ {
+ if (\MailSo\Imap\Enumerations\FetchType::UID === $mItem)
+ {
+ $bUid = true;
+ }
+ else if (\MailSo\Imap\Enumerations\FetchType::RFC822_SIZE === $mItem)
+ {
+ $bSize = true;
+ }
+ }
+ }
+
+ return $bUid && $bSize;
+ }
+
+ /**
+ * @param \MailSo\Imap\Response $oImapResponse
+ *
+ * @return bool
+ */
+ public static function IsValidFetchImapResponse($oImapResponse)
+ {
+ return (
+ $oImapResponse
+ && true !== $oImapResponse->IsStatusResponse
+ && \MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
+ && 3 < count($oImapResponse->ResponseList) && 'FETCH' === $oImapResponse->ResponseList[2]
+ && is_array($oImapResponse->ResponseList[3])
+ );
+ }
+
+ /**
+ * @param \MailSo\Imap\Response $oImapResponse
+ *
+ * @return bool
+ */
+ public static function IsNotEmptyFetchImapResponse($oImapResponse)
+ {
+ return (
+ $oImapResponse
+ && self::IsValidFetchImapResponse($oImapResponse)
+ && isset($oImapResponse->ResponseList[3])
+ && self::findFetchUidAndSize($oImapResponse->ResponseList[3])
+ );
+ }
+
+ /**
+ * @param array $aEnvelope
+ * @param int $iIndex
+ * @param mixed $mNullResult = null
+ *
+ * @return mixed
+ */
+ private static function findEnvelopeIndex($aEnvelope, $iIndex, $mNullResult)
+ {
+ return (isset($aEnvelope[$iIndex]) && 'NIL' !== $aEnvelope[$iIndex] && '' !== $aEnvelope[$iIndex])
+ ? $aEnvelope[$iIndex] : $mNullResult;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/Folder.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/Folder.php
new file mode 100644
index 0000000..50fd423
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/Folder.php
@@ -0,0 +1,193 @@
+sNameRaw = '';
+ $this->sFullNameRaw = '';
+ $this->sDelimiter = '';
+ $this->aFlags = array();
+ $this->aExtended = array();
+
+ $sDelimiter = 'NIL' === \strtoupper($sDelimiter) ? '' : $sDelimiter;
+ if (empty($sDelimiter))
+ {
+ $sDelimiter = '.'; // default delimiter
+ }
+
+ if (!\is_array($aFlags) ||
+ !\is_string($sDelimiter) || 1 < \strlen($sDelimiter) ||
+ !\is_string($sFullNameRaw) || 0 === \strlen($sFullNameRaw))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->sFullNameRaw = $sFullNameRaw;
+ $this->sDelimiter = $sDelimiter;
+ $this->aFlags = $aFlags;
+ $this->aFlagsLowerCase = \array_map('strtolower', $this->aFlags);
+
+ $this->sFullNameRaw = 'INBOX'.$this->sDelimiter === \substr(\strtoupper($this->sFullNameRaw), 0, 5 + \strlen($this->sDelimiter)) ?
+ 'INBOX'.\substr($this->sFullNameRaw, 5) : $this->sFullNameRaw;
+
+ if ($this->IsInbox())
+ {
+ $this->sFullNameRaw = 'INBOX';
+ }
+
+ $this->sNameRaw = $this->sFullNameRaw;
+ if (0 < \strlen($this->sDelimiter))
+ {
+ $aNames = \explode($this->sDelimiter, $this->sFullNameRaw);
+ if (false !== \array_search('', $aNames))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->sNameRaw = \end($aNames);
+ }
+ }
+
+ /**
+ * @param string $sFullNameRaw
+ * @param string $sDelimiter = '.'
+ * @param array $aFlags = array()
+ *
+ * @return \MailSo\Imap\Folder
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public static function NewInstance($sFullNameRaw, $sDelimiter = '.', $aFlags = array())
+ {
+ return new self($sFullNameRaw, $sDelimiter, $aFlags);
+ }
+
+ /**
+ * @return string
+ */
+ public function NameRaw()
+ {
+ return $this->sNameRaw;
+ }
+
+ /**
+ * @return string
+ */
+ public function FullNameRaw()
+ {
+ return $this->sFullNameRaw;
+ }
+
+ /**
+ * @return string | null
+ */
+ public function Delimiter()
+ {
+ return $this->sDelimiter;
+ }
+
+ /**
+ * @return array
+ */
+ public function Flags()
+ {
+ return $this->aFlags;
+ }
+
+ /**
+ * @return array
+ */
+ public function FlagsLowerCase()
+ {
+ return $this->aFlagsLowerCase;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsSelectable()
+ {
+ return !\in_array('\noselect', $this->aFlagsLowerCase);
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsInbox()
+ {
+ return 'INBOX' === \strtoupper($this->sFullNameRaw) || \in_array('\inbox', $this->aFlagsLowerCase);
+ }
+
+ /**
+ * @param string $sName
+ * @param mixed $mData
+ */
+ public function SetExtended($sName, $mData)
+ {
+ $this->aExtended[$sName] = $mData;
+ }
+
+ /**
+ * @param string $sName
+ * @return mixed
+ */
+ public function GetExtended($sName)
+ {
+ return isset($this->aExtended[$sName]) ? $this->aExtended[$sName] : null;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/FolderInformation.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/FolderInformation.php
new file mode 100644
index 0000000..f6ac83e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/FolderInformation.php
@@ -0,0 +1,110 @@
+FolderName = $sFolderName;
+ $this->IsWritable = $bIsWritable;
+ $this->Exists = null;
+ $this->Recent = null;
+ $this->Flags = array();
+ $this->PermanentFlags = array();
+
+ $this->Unread = null;
+ $this->Uidnext = null;
+ $this->HighestModSeq = null;
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param bool $bIsWritable
+ *
+ * @return \MailSo\Imap\FolderInformation
+ */
+ public static function NewInstance($sFolderName, $bIsWritable)
+ {
+ return new self($sFolderName, $bIsWritable);
+ }
+
+ /**
+ * @param string $sFlag
+ *
+ * @return bool
+ */
+ public function IsFlagSupported($sFlag)
+ {
+ return \in_array('\\*', $this->PermanentFlags) || \in_array($sFlag, $this->PermanentFlags);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/ImapClient.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/ImapClient.php
new file mode 100644
index 0000000..449b51f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/ImapClient.php
@@ -0,0 +1,2662 @@
+iTagCount = 0;
+ $this->aCapabilityItems = null;
+ $this->oCurrentFolderInfo = null;
+ $this->aFetchCallbacks = null;
+ $this->iResponseBufParsedPos = 0;
+
+ $this->aLastResponse = array();
+ $this->bNeedNext = true;
+ $this->aPartialResponses = array();
+
+ $this->aTagTimeouts = array();
+
+ $this->bIsLoggined = false;
+ $this->bIsSelected = false;
+ $this->sLogginedUser = '';
+
+ $this->__FORCE_SELECT_ON_EXAMINE__ = false;
+
+ @\ini_set('xdebug.max_nesting_level', 500);
+ }
+
+ /**
+ * @return \MailSo\Imap\ImapClient
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @return string
+ */
+ public function GetLogginedUser()
+ {
+ return $this->sLogginedUser;
+ }
+
+ /**
+ * @param string $sServerName
+ * @param int $iPort = 143
+ * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
+ * @param bool $bVerifySsl = false
+ * @param bool $bAllowSelfSigned = true
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Connect($sServerName, $iPort = 143,
+ $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT,
+ $bVerifySsl = false, $bAllowSelfSigned = true)
+ {
+ $this->aTagTimeouts['*'] = \microtime(true);
+
+ parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned);
+
+ $this->parseResponseWithValidation('*', true);
+
+ if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS(
+ $this->IsSupported('STARTTLS'), $this->iSecurityType))
+ {
+ $this->SendRequestWithCheck('STARTTLS');
+ $this->EnableCrypto();
+
+ $this->aCapabilityItems = null;
+ }
+ else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType)
+ {
+ $this->writeLogException(
+ new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ return $this;
+ }
+
+ protected function _xor($string, $string2)
+ {
+ $result = '';
+ $size = strlen($string);
+ for ($i=0; $i<$size; $i++) {
+ $result .= chr(ord($string[$i]) ^ ord($string2[$i]));
+ }
+ return $result;
+ }
+
+ /**
+ * @param string $sLogin
+ * @param string $sPassword
+ * @param string $sProxyAuthUser = ''
+ * @param bool $bUseAuthPlainIfSupported = false
+ * @param bool $bUseAuthCramMd5IfSupported = false
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Login($sLogin, $sPassword, $sProxyAuthUser = '',
+ $bUseAuthPlainIfSupported = false, $bUseAuthCramMd5IfSupported = false)
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sLogin, true) ||
+ !\MailSo\Base\Validator::NotEmptyString($sPassword, true))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $sLogin = \MailSo\Base\Utils::IdnToAscii(\MailSo\Base\Utils::Trim($sLogin));
+
+ $sPassword = $sPassword;
+
+ $this->sLogginedUser = $sLogin;
+
+ try
+ {
+ if ($bUseAuthCramMd5IfSupported && $this->IsSupported('AUTH=CRAM-MD5'))
+ {
+ $this->SendRequest('AUTHENTICATE', array('CRAM-MD5'));
+
+ $aResponse = $this->parseResponseWithValidation();
+ if ($aResponse && \is_array($aResponse) && 0 < \count($aResponse) &&
+ \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $aResponse[\count($aResponse) - 1]->ResponseType)
+ {
+ $oContinuationResponse = null;
+ foreach ($aResponse as $oResponse)
+ {
+ if ($oResponse && \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oResponse->ResponseType)
+ {
+ $oContinuationResponse = $oResponse;
+ }
+ }
+
+ if ($oContinuationResponse && !empty($oContinuationResponse->ResponseList[1]))
+ {
+ $sTiken = @\base64_decode($oContinuationResponse->ResponseList[1]);
+ $this->oLogger->Write('tiket: '.$sTiken);
+
+ $sToken = \base64_encode($sLogin.' '.\MailSo\Base\Utils::Hmac($sPassword, $sTiken));
+
+ if ($this->oLogger)
+ {
+ $this->oLogger->AddSecret($sToken);
+ }
+
+ $this->sendRaw($sToken, true, '*******');
+ $this->parseResponseWithValidation();
+ }
+ else
+ {
+ $this->writeLogException(
+ new \MailSo\Imap\Exceptions\LoginException(),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+ }
+ else
+ {
+ $this->writeLogException(
+ new \MailSo\Imap\Exceptions\LoginException(),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+ }
+ else if ($bUseAuthPlainIfSupported && $this->IsSupported('AUTH=PLAIN'))
+ {
+ $sToken = \base64_encode("\0".$sLogin."\0".$sPassword);
+ if ($this->oLogger)
+ {
+ $this->oLogger->AddSecret($sToken);
+ }
+
+ if ($this->IsSupported('AUTH=SASL-IR') && false)
+ {
+ $this->SendRequestWithCheck('AUTHENTICATE', array('PLAIN', $sToken));
+ }
+ else
+ {
+ $this->SendRequest('AUTHENTICATE', array('PLAIN'));
+ $this->parseResponseWithValidation();
+
+ $this->sendRaw($sToken, true, '*******');
+ $this->parseResponseWithValidation();
+ }
+ }
+ else
+ {
+ if ($this->oLogger)
+ {
+ $this->oLogger->AddSecret($this->EscapeString($sPassword));
+ }
+
+ $this->SendRequestWithCheck('LOGIN',
+ array(
+ $this->EscapeString($sLogin),
+ $this->EscapeString($sPassword)
+ ));
+ }
+// else
+// {
+// $this->writeLogException(
+// new \MailSo\Imap\Exceptions\LoginBadMethodException(),
+// \MailSo\Log\Enumerations\Type::NOTICE, true);
+// }
+
+ if (0 < \strlen($sProxyAuthUser))
+ {
+ $this->SendRequestWithCheck('PROXYAUTH', array($this->EscapeString($sProxyAuthUser)));
+ }
+ }
+ catch (\MailSo\Imap\Exceptions\NegativeResponseException $oException)
+ {
+ $this->writeLogException(
+ new \MailSo\Imap\Exceptions\LoginBadCredentialsException(
+ $oException->GetResponses(), '', 0, $oException),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+
+ $this->bIsLoggined = true;
+ $this->aCapabilityItems = null;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sXOAuth2Token
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function LoginWithXOauth2($sXOAuth2Token)
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sXOAuth2Token, true))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ if (!$this->IsSupported('AUTH=XOAUTH2'))
+ {
+ $this->writeLogException(
+ new \MailSo\Imap\Exceptions\LoginBadMethodException(),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+
+ try
+ {
+ $this->SendRequest('AUTHENTICATE', array('XOAUTH2', \trim($sXOAuth2Token)));
+ $aR = $this->parseResponseWithValidation();
+
+ if (\is_array($aR) && 0 < \count($aR) && isset($aR[\count($aR) - 1]))
+ {
+ $oR = $aR[\count($aR) - 1];
+ if (\MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oR->ResponseType)
+ {
+ if (!empty($oR->ResponseList[1]) && preg_match('/^[a-zA-Z0-9=+\/]+$/', $oR->ResponseList[1]))
+ {
+ $this->Logger()->Write(\base64_decode($oR->ResponseList[1]),
+ \MailSo\Log\Enumerations\Type::WARNING);
+ }
+
+ $this->sendRaw('');
+ $this->parseResponseWithValidation();
+ }
+ }
+ }
+ catch (\MailSo\Imap\Exceptions\NegativeResponseException $oException)
+ {
+ $this->writeLogException(
+ new \MailSo\Imap\Exceptions\LoginBadCredentialsException(
+ $oException->GetResponses(), '', 0, $oException),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+
+ $this->bIsLoggined = true;
+ $this->aCapabilityItems = null;
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ public function Logout()
+ {
+ if ($this->bIsLoggined)
+ {
+ $this->bIsLoggined = false;
+ $this->SendRequestWithCheck('LOGOUT', array());
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Imap\ImapClient
+ */
+ public function ForceCloseConnection()
+ {
+ $this->Disconnect();
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsLoggined()
+ {
+ return $this->IsConnected() && $this->bIsLoggined;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsSelected()
+ {
+ return $this->IsLoggined() && $this->bIsSelected;
+ }
+
+ /**
+ * @return array|null
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Capability()
+ {
+ $this->SendRequestWithCheck('CAPABILITY', array(), true);
+ return $this->aCapabilityItems;
+ }
+
+ /**
+ * @param string $sExtentionName
+ * @return bool
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function IsSupported($sExtentionName)
+ {
+ $bResult = \MailSo\Base\Validator::NotEmptyString($sExtentionName, true);
+ if ($bResult && null === $this->aCapabilityItems)
+ {
+ $this->aCapabilityItems = $this->Capability();
+ }
+
+ return $bResult && \is_array($this->aCapabilityItems) &&
+ \in_array(\strtoupper($sExtentionName), $this->aCapabilityItems);
+ }
+
+ /**
+ * @return \MailSo\Imap\NamespaceResult|null
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function GetNamespace()
+ {
+ if (!$this->IsSupported('NAMESPACE'))
+ {
+ return null;
+ }
+
+ $oReturn = false;
+
+ $this->SendRequest('NAMESPACE');
+ $aResult = $this->parseResponseWithValidation();
+
+ $oImapResponse = null;
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType &&
+ 'NAMESPACE' === $oImapResponse->StatusOrIndex)
+ {
+ $oReturn = NamespaceResult::NewInstance();
+ $oReturn->InitByImapResponse($oImapResponse);
+ break;
+ }
+ }
+
+ if (false === $oReturn)
+ {
+ $this->writeLogException(
+ new \MailSo\Imap\Exceptions\ResponseException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ return $oReturn;
+ }
+
+ /**
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Noop()
+ {
+ return $this->SendRequestWithCheck('NOOP');
+ }
+
+ /**
+ * @param string $sFolderName
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderCreate($sFolderName)
+ {
+ return $this->SendRequestWithCheck('CREATE',
+ array($this->EscapeString($sFolderName)));
+ }
+
+ /**
+ * @param string $sFolderName
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderDelete($sFolderName)
+ {
+ return $this->SendRequestWithCheck('DELETE',
+ array($this->EscapeString($sFolderName)));
+ }
+
+ /**
+ * @param string $sFolderName
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderSubscribe($sFolderName)
+ {
+ return $this->SendRequestWithCheck('SUBSCRIBE',
+ array($this->EscapeString($sFolderName)));
+ }
+
+ /**
+ * @param string $sFolderName
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderUnSubscribe($sFolderName)
+ {
+ return $this->SendRequestWithCheck('UNSUBSCRIBE',
+ array($this->EscapeString($sFolderName)));
+ }
+
+ /**
+ * @param string $sOldFolderName
+ * @param string $sNewFolderName
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderRename($sOldFolderName, $sNewFolderName)
+ {
+ return $this->SendRequestWithCheck('RENAME', array(
+ $this->EscapeString($sOldFolderName),
+ $this->EscapeString($sNewFolderName)));
+ }
+
+ /**
+ * @param array $aResult
+ *
+ * @return array
+ */
+ protected function getStatusFolderInformation($aResult)
+ {
+ $aReturn = array();
+
+ if (\is_array($aResult))
+ {
+ $oImapResponse = null;
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType &&
+ 'STATUS' === $oImapResponse->StatusOrIndex && isset($oImapResponse->ResponseList[3]) &&
+ \is_array($oImapResponse->ResponseList[3]))
+ {
+ $sName = null;
+ foreach ($oImapResponse->ResponseList[3] as $sArrayItem)
+ {
+ if (null === $sName)
+ {
+ $sName = $sArrayItem;
+ }
+ else
+ {
+ $aReturn[$sName] = $sArrayItem;
+ $sName = null;
+ }
+ }
+ }
+ }
+ }
+
+ return $aReturn;
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param array $aStatusItems
+ *
+ * @return array|bool
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderStatus($sFolderName, array $aStatusItems)
+ {
+ $aResult = false;
+ if (\count($aStatusItems) > 0)
+ {
+ $this->SendRequest('STATUS',
+ array($this->EscapeString($sFolderName), $aStatusItems));
+
+ $aResult = $this->getStatusFolderInformation(
+ $this->parseResponseWithValidation());
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param array $aResult
+ * @param string $sStatus
+ * @param bool $bUseListStatus = false
+ *
+ * @return array
+ */
+ private function getFoldersFromResult(array $aResult, $sStatus, $bUseListStatus = false)
+ {
+ $aReturn = array();
+
+ $sDelimiter = '';
+ $bInbox = false;
+
+ $oImapResponse = null;
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType &&
+ $sStatus === $oImapResponse->StatusOrIndex && 5 === count($oImapResponse->ResponseList))
+ {
+ try
+ {
+ $oFolder = Folder::NewInstance($oImapResponse->ResponseList[4],
+ $oImapResponse->ResponseList[3], $oImapResponse->ResponseList[2]);
+
+ if ($oFolder->IsInbox())
+ {
+ $bInbox = true;
+ }
+
+ if (empty($sDelimiter))
+ {
+ $sDelimiter = $oFolder->Delimiter();
+ }
+
+ $aReturn[] = $oFolder;
+ }
+ catch (\MailSo\Base\Exceptions\InvalidArgumentException $oException)
+ {
+ $this->writeLogException($oException, \MailSo\Log\Enumerations\Type::WARNING, false);
+ }
+ }
+ }
+
+ if (!$bInbox && !empty($sDelimiter))
+ {
+ $aReturn[] = Folder::NewInstance('INBOX', $sDelimiter);
+ }
+
+ if ($bUseListStatus)
+ {
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType &&
+ 'STATUS' === $oImapResponse->StatusOrIndex &&
+ isset($oImapResponse->ResponseList[2]) &&
+ isset($oImapResponse->ResponseList[3]) &&
+ \is_array($oImapResponse->ResponseList[3]))
+ {
+ $sFolderNameRaw = $oImapResponse->ResponseList[2];
+
+ $oCurrentFolder = null;
+ foreach ($aReturn as &$oFolder)
+ {
+ if ($oFolder && $sFolderNameRaw === $oFolder->FullNameRaw())
+ {
+ $oCurrentFolder =& $oFolder;
+ break;
+ }
+ }
+
+ if (null !== $oCurrentFolder)
+ {
+ $sName = null;
+ $aStatus = array();
+
+ foreach ($oImapResponse->ResponseList[3] as $sArrayItem)
+ {
+ if (null === $sName)
+ {
+ $sName = $sArrayItem;
+ }
+ else
+ {
+ $aStatus[$sName] = $sArrayItem;
+ $sName = null;
+ }
+ }
+
+ if (0 < count($aStatus))
+ {
+ $oCurrentFolder->SetExtended('STATUS', $aStatus);
+ }
+ }
+
+ unset($oCurrentFolder);
+ }
+ }
+ }
+
+ return $aReturn;
+ }
+
+ /**
+ * @param bool $bIsSubscribeList
+ * @param string $sParentFolderName = ''
+ * @param string $sListPattern = '*'
+ * @param bool $bUseListStatus = false
+ *
+ * @return array
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ private function specificFolderList($bIsSubscribeList, $sParentFolderName = '', $sListPattern = '*', $bUseListStatus = false)
+ {
+ $sCmd = 'LSUB';
+ if (!$bIsSubscribeList)
+ {
+ $sCmd = 'LIST';
+ }
+
+ $sListPattern = 0 === strlen(trim($sListPattern)) ? '*' : $sListPattern;
+
+ $aParameters = array(
+ $this->EscapeString($sParentFolderName),
+ $this->EscapeString($sListPattern)
+ );
+
+ if ($bUseListStatus && !$bIsSubscribeList && $this->IsSupported('LIST-STATUS'))
+ {
+ $aL = array(
+ \MailSo\Imap\Enumerations\FolderStatus::MESSAGES,
+ \MailSo\Imap\Enumerations\FolderStatus::UNSEEN,
+ \MailSo\Imap\Enumerations\FolderStatus::UIDNEXT
+ );
+
+// if ($this->IsSupported('CONDSTORE'))
+// {
+// $aL[] = \MailSo\Imap\Enumerations\FolderStatus::HIGHESTMODSEQ;
+// }
+
+ $aParameters[] = 'RETURN';
+ $aParameters[] = array('STATUS', $aL);
+ }
+ else
+ {
+ $bUseListStatus = false;
+ }
+
+ $this->SendRequest($sCmd, $aParameters);
+
+ return $this->getFoldersFromResult(
+ $this->parseResponseWithValidation(), $sCmd, $bUseListStatus);
+ }
+
+ /**
+ * @param string $sParentFolderName = ''
+ * @param string $sListPattern = '*'
+ *
+ * @return array
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderList($sParentFolderName = '', $sListPattern = '*')
+ {
+ return $this->specificFolderList(false, $sParentFolderName, $sListPattern);
+ }
+
+ /**
+ * @param string $sParentFolderName = ''
+ * @param string $sListPattern = '*'
+ *
+ * @return array
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderSubscribeList($sParentFolderName = '', $sListPattern = '*')
+ {
+ return $this->specificFolderList(true, $sParentFolderName, $sListPattern);
+ }
+
+ /**
+ * @param string $sParentFolderName = ''
+ * @param string $sListPattern = '*'
+ *
+ * @return array
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderStatusList($sParentFolderName = '', $sListPattern = '*')
+ {
+ return $this->specificFolderList(false, $sParentFolderName, $sListPattern, true);
+ }
+
+ /**
+ * @param array $aResult
+ * @param string $sFolderName
+ * @param bool $bIsWritable
+ *
+ * @return void
+ */
+ protected function initCurrentFolderInformation($aResult, $sFolderName, $bIsWritable)
+ {
+ if (\is_array($aResult))
+ {
+ $oImapResponse = null;
+ $oResult = FolderInformation::NewInstance($sFolderName, $bIsWritable);
+
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType)
+ {
+ if (\count($oImapResponse->ResponseList) > 2 &&
+ 'FLAGS' === $oImapResponse->ResponseList[1] && \is_array($oImapResponse->ResponseList[2]))
+ {
+ $oResult->Flags = $oImapResponse->ResponseList[2];
+ }
+
+ if (is_array($oImapResponse->OptionalResponse) && \count($oImapResponse->OptionalResponse) > 1)
+ {
+ if ('PERMANENTFLAGS' === $oImapResponse->OptionalResponse[0] &&
+ is_array($oImapResponse->OptionalResponse[1]))
+ {
+ $oResult->PermanentFlags = $oImapResponse->OptionalResponse[1];
+ }
+ else if ('UIDVALIDITY' === $oImapResponse->OptionalResponse[0] &&
+ isset($oImapResponse->OptionalResponse[1]))
+ {
+ $oResult->Uidvalidity = $oImapResponse->OptionalResponse[1];
+ }
+ else if ('UNSEEN' === $oImapResponse->OptionalResponse[0] &&
+ isset($oImapResponse->OptionalResponse[1]) &&
+ is_numeric($oImapResponse->OptionalResponse[1]))
+ {
+ $oResult->Unread = (int) $oImapResponse->OptionalResponse[1];
+ }
+ else if ('UIDNEXT' === $oImapResponse->OptionalResponse[0] &&
+ isset($oImapResponse->OptionalResponse[1]))
+ {
+ $oResult->Uidnext = $oImapResponse->OptionalResponse[1];
+ }
+ else if ('HIGHESTMODSEQ' === $oImapResponse->OptionalResponse[0] &&
+ isset($oImapResponse->OptionalResponse[1]) &&
+ \is_numeric($oImapResponse->OptionalResponse[1]))
+ {
+ $oResult->HighestModSeq = \trim($oImapResponse->OptionalResponse[1]);
+ }
+ }
+
+ if (\count($oImapResponse->ResponseList) > 2 &&
+ \is_string($oImapResponse->ResponseList[2]) &&
+ \is_numeric($oImapResponse->ResponseList[1]))
+ {
+ switch($oImapResponse->ResponseList[2])
+ {
+ case 'EXISTS':
+ $oResult->Exists = (int) $oImapResponse->ResponseList[1];
+ break;
+ case 'RECENT':
+ $oResult->Recent = (int) $oImapResponse->ResponseList[1];
+ break;
+ }
+ }
+ }
+ }
+
+ $this->oCurrentFolderInfo = $oResult;
+ }
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param bool $bIsWritable
+ * @param bool $bReSelectSameFolders
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ protected function selectOrExamineFolder($sFolderName, $bIsWritable, $bReSelectSameFolders)
+ {
+ if (!$bReSelectSameFolders)
+ {
+ if ($this->oCurrentFolderInfo &&
+ $sFolderName === $this->oCurrentFolderInfo->FolderName &&
+ $bIsWritable === $this->oCurrentFolderInfo->IsWritable)
+ {
+ return $this;
+ }
+ }
+
+ if (!\MailSo\Base\Validator::NotEmptyString($sFolderName, true))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->SendRequest(($bIsWritable) ? 'SELECT' : 'EXAMINE',
+ array($this->EscapeString($sFolderName)));
+
+ $this->initCurrentFolderInformation(
+ $this->parseResponseWithValidation(), $sFolderName, $bIsWritable);
+
+ $this->bIsSelected = true;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param bool $bReSelectSameFolders = false
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderSelect($sFolderName, $bReSelectSameFolders = false)
+ {
+ return $this->selectOrExamineFolder($sFolderName, true, $bReSelectSameFolders);
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param bool $bReSelectSameFolders = false
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderExamine($sFolderName, $bReSelectSameFolders = false)
+ {
+ return $this->selectOrExamineFolder($sFolderName, $this->__FORCE_SELECT_ON_EXAMINE__, $bReSelectSameFolders);
+ }
+
+ /**
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderUnSelect()
+ {
+ return $this->IsSelected() && $this->IsSupported('UNSELECT') ?
+ $this->SendRequestWithCheck('UNSELECT') : $this;
+ }
+
+ /**
+ * @param array $aInputFetchItems
+ * @param string $sIndexRange
+ * @param bool $bIndexIsUid
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Fetch(array $aInputFetchItems, $sIndexRange, $bIndexIsUid)
+ {
+ $sIndexRange = (string) $sIndexRange;
+ if (!\MailSo\Base\Validator::NotEmptyString($sIndexRange, true))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $aFetchItems = \MailSo\Imap\Enumerations\FetchType::ChangeFetchItemsBefourRequest($aInputFetchItems);
+ foreach ($aFetchItems as $sName => $mItem)
+ {
+ if (0 < \strlen($sName) && '' !== $mItem)
+ {
+ if (null === $this->aFetchCallbacks)
+ {
+ $this->aFetchCallbacks = array();
+ }
+
+ $this->aFetchCallbacks[$sName] = $mItem;
+ }
+ }
+
+ $this->SendRequest((($bIndexIsUid) ? 'UID ' : '').'FETCH', array($sIndexRange, \array_keys($aFetchItems)));
+ $aResult = $this->validateResponse($this->parseResponse());
+ $this->aFetchCallbacks = null;
+
+ $aReturn = array();
+ $oImapResponse = null;
+ foreach ($aResult as $oImapResponse)
+ {
+ if (FetchResponse::IsValidFetchImapResponse($oImapResponse))
+ {
+ if (FetchResponse::IsNotEmptyFetchImapResponse($oImapResponse))
+ {
+ $aReturn[] = FetchResponse::NewInstance($oImapResponse);
+ }
+ else
+ {
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('Skipped Imap Response! ['.$oImapResponse->ToLine().']', \MailSo\Log\Enumerations\Type::NOTICE);
+ }
+ }
+ }
+ }
+
+ return $aReturn;
+ }
+
+
+ /**
+ * @return array|false
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Quota()
+ {
+ $aReturn = false;
+ if ($this->IsSupported('QUOTA'))
+ {
+ $this->SendRequest('GETQUOTAROOT "INBOX"');
+ $aResult = $this->parseResponseWithValidation();
+
+ $aReturn = array(0, 0);
+ $oImapResponse = null;
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
+ && 'QUOTA' === $oImapResponse->StatusOrIndex
+ && \is_array($oImapResponse->ResponseList)
+ && isset($oImapResponse->ResponseList[3])
+ && \is_array($oImapResponse->ResponseList[3])
+ && 2 < \count($oImapResponse->ResponseList[3])
+ && 'STORAGE' === \strtoupper($oImapResponse->ResponseList[3][0])
+ && \is_numeric($oImapResponse->ResponseList[3][1])
+ && \is_numeric($oImapResponse->ResponseList[3][2])
+ )
+ {
+ $aReturn = array(
+ (int) $oImapResponse->ResponseList[3][1],
+ (int) $oImapResponse->ResponseList[3][2],
+ 0,
+ 0
+ );
+
+ if (5 < \count($oImapResponse->ResponseList[3])
+ && 'MESSAGE' === \strtoupper($oImapResponse->ResponseList[3][3])
+ && \is_numeric($oImapResponse->ResponseList[3][4])
+ && \is_numeric($oImapResponse->ResponseList[3][5])
+ )
+ {
+ $aReturn[2] = (int) $oImapResponse->ResponseList[3][4];
+ $aReturn[3] = (int) $oImapResponse->ResponseList[3][5];
+ }
+ }
+ }
+ }
+
+ return $aReturn;
+ }
+
+ /**
+ * @param array $aSortTypes
+ * @param string $sSearchCriterias
+ * @param bool $bReturnUid
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSimpleSort($aSortTypes, $sSearchCriterias = 'ALL', $bReturnUid = true)
+ {
+ $sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
+ $sSearchCriterias = !\MailSo\Base\Validator::NotEmptyString($sSearchCriterias, true) || '*' === $sSearchCriterias
+ ? 'ALL' : $sSearchCriterias;
+
+ if (!\is_array($aSortTypes) || 0 === \count($aSortTypes))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+ else if (!$this->IsSupported('SORT'))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $aRequest = array();
+ $aRequest[] = $aSortTypes;
+ $aRequest[] = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8';
+ $aRequest[] = $sSearchCriterias;
+
+ $sCmd = 'SORT';
+
+ $this->SendRequest($sCommandPrefix.$sCmd, $aRequest);
+ $aResult = $this->parseResponseWithValidation();
+
+ $aReturn = array();
+ $oImapResponse = null;
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
+ && ($sCmd === $oImapResponse->StatusOrIndex ||
+ ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex) && !empty($oImapResponse->ResponseList[2]) &&
+ $sCmd === $oImapResponse->ResponseList[2])
+ && \is_array($oImapResponse->ResponseList)
+ && 2 < \count($oImapResponse->ResponseList))
+ {
+ $iStart = 2;
+ if ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex &&
+ !empty($oImapResponse->ResponseList[2]) &&
+ $sCmd === $oImapResponse->ResponseList[2])
+ {
+ $iStart = 3;
+ }
+
+ for ($iIndex = $iStart, $iLen = \count($oImapResponse->ResponseList); $iIndex < $iLen; $iIndex++)
+ {
+ $aReturn[] = (int) $oImapResponse->ResponseList[$iIndex];
+ }
+ }
+ }
+
+ return $aReturn;
+ }
+
+ /**
+ * @param bool $bSort = false
+ * @param string $sSearchCriterias = 'ALL'
+ * @param array $aSearchOrSortReturn = null
+ * @param bool $bReturnUid = true
+ * @param string $sLimit = ''
+ * @param string $sCharset = ''
+ * @param array $aSortTypes = null
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ private function simpleESearchOrESortHelper($bSort = false, $sSearchCriterias = 'ALL', $aSearchOrSortReturn = null, $bReturnUid = true, $sLimit = '', $sCharset = '', $aSortTypes = null)
+ {
+ $sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
+ $sSearchCriterias = 0 === \strlen($sSearchCriterias) || '*' === $sSearchCriterias
+ ? 'ALL' : $sSearchCriterias;
+
+ $sCmd = $bSort ? 'SORT': 'SEARCH';
+ if ($bSort && (!\is_array($aSortTypes) || 0 === \count($aSortTypes) || !$this->IsSupported('SORT')))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ if (!$this->IsSupported($bSort ? 'ESORT' : 'ESEARCH'))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ if (!\is_array($aSearchOrSortReturn) || 0 === \count($aSearchOrSortReturn))
+ {
+ $aSearchOrSortReturn = array('ALL');
+ }
+
+ $aRequest = array();
+ if ($bSort)
+ {
+ $aRequest[] = 'RETURN';
+ $aRequest[] = $aSearchOrSortReturn;
+
+ $aRequest[] = $aSortTypes;
+ $aRequest[] = \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? 'US-ASCII' : 'UTF-8';
+ }
+ else
+ {
+ if (0 < \strlen($sCharset))
+ {
+ $aRequest[] = 'CHARSET';
+ $aRequest[] = \strtoupper($sCharset);
+ }
+
+ $aRequest[] = 'RETURN';
+ $aRequest[] = $aSearchOrSortReturn;
+ }
+
+ $aRequest[] = $sSearchCriterias;
+
+ if (0 < \strlen($sLimit))
+ {
+ $aRequest[] = $sLimit;
+ }
+
+ $this->SendRequest($sCommandPrefix.$sCmd, $aRequest);
+ $sRequestTag = $this->getCurrentTag();
+
+ $aResult = array();
+ $aResponse = $this->parseResponseWithValidation();
+
+ if (\is_array($aResponse))
+ {
+ $oImapResponse = null;
+ foreach ($aResponse as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
+ && ('ESEARCH' === $oImapResponse->StatusOrIndex || 'ESORT' === $oImapResponse->StatusOrIndex)
+ && \is_array($oImapResponse->ResponseList)
+ && isset($oImapResponse->ResponseList[2], $oImapResponse->ResponseList[2][0], $oImapResponse->ResponseList[2][1])
+ && 'TAG' === $oImapResponse->ResponseList[2][0] && $sRequestTag === $oImapResponse->ResponseList[2][1]
+ && (!$bReturnUid || ($bReturnUid && !empty($oImapResponse->ResponseList[3]) && 'UID' === $oImapResponse->ResponseList[3]))
+ )
+ {
+ $iStart = 3;
+ foreach ($oImapResponse->ResponseList as $iIndex => $mItem)
+ {
+ if ($iIndex >= $iStart)
+ {
+ switch ($mItem)
+ {
+ case 'ALL':
+ case 'MAX':
+ case 'MIN':
+ case 'COUNT':
+ if (isset($oImapResponse->ResponseList[$iIndex + 1]))
+ {
+ $aResult[$mItem] = $oImapResponse->ResponseList[$iIndex + 1];
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sSearchCriterias = 'ALL'
+ * @param array $aSearchReturn = null
+ * @param bool $bReturnUid = true
+ * @param string $sLimit = ''
+ * @param string $sCharset = ''
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSimpleESearch($sSearchCriterias = 'ALL', $aSearchReturn = null, $bReturnUid = true, $sLimit = '', $sCharset = '')
+ {
+ return $this->simpleESearchOrESortHelper(false, $sSearchCriterias, $aSearchReturn, $bReturnUid, $sLimit, $sCharset);
+ }
+
+ /**
+ * @param array $aSortTypes
+ * @param string $sSearchCriterias = 'ALL'
+ * @param array $aSearchReturn = null
+ * @param bool $bReturnUid = true
+ * @param string $sLimit = ''
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSimpleESort($aSortTypes, $sSearchCriterias = 'ALL', $aSearchReturn = null, $bReturnUid = true, $sLimit = '')
+ {
+ return $this->simpleESearchOrESortHelper(true, $sSearchCriterias, $aSearchReturn, $bReturnUid, $sLimit, '', $aSortTypes);
+ }
+
+ /**
+ * @param array $aResult
+ * @return \MailSo\Imap\Response
+ */
+ private function findLastResponse($aResult)
+ {
+ $oResult = null;
+ if (\is_array($aResult) && 0 < \count($aResult))
+ {
+ $oResult = $aResult[\count($aResult) - 1];
+ if (!($oResult instanceof \MailSo\Imap\Response))
+ {
+ $oResult = null;
+ }
+ }
+
+ return $oResult;
+ }
+
+ /**
+ * @param string $sSearchCriterias
+ * @param bool $bReturnUid = true
+ * @param string $sCharset = ''
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSimpleSearch($sSearchCriterias = 'ALL', $bReturnUid = true, $sCharset = '')
+ {
+ $sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
+ $sSearchCriterias = 0 === \strlen($sSearchCriterias) || '*' === $sSearchCriterias
+ ? 'ALL' : $sSearchCriterias;
+
+ $aRequest = array();
+ if (0 < \strlen($sCharset))
+ {
+ $aRequest[] = 'CHARSET';
+ $aRequest[] = \strtoupper($sCharset);
+ }
+
+ $aRequest[] = $sSearchCriterias;
+
+ $sCmd = 'SEARCH';
+
+ $sCont = $this->SendRequest($sCommandPrefix.$sCmd, $aRequest, true);
+ if ('' !== $sCont)
+ {
+ $aResult = $this->parseResponseWithValidation();
+ $oItem = $this->findLastResponse($aResult);
+
+ if ($oItem && \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oItem->ResponseType)
+ {
+ $aParts = explode("\r\n", $sCont);
+ foreach ($aParts as $sLine)
+ {
+ $this->sendRaw($sLine);
+
+ $aResult = $this->parseResponseWithValidation();
+ $oItem = $this->findLastResponse($aResult);
+ if ($oItem && \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oItem->ResponseType)
+ {
+ continue;
+ }
+ }
+ }
+ }
+ else
+ {
+ $aResult = $this->parseResponseWithValidation();
+ }
+
+ $aReturn = array();
+ $oImapResponse = null;
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
+ && ($sCmd === $oImapResponse->StatusOrIndex ||
+ ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex) && !empty($oImapResponse->ResponseList[2]) &&
+ $sCmd === $oImapResponse->ResponseList[2])
+ && \is_array($oImapResponse->ResponseList)
+ && 2 < count($oImapResponse->ResponseList))
+ {
+ $iStart = 2;
+ if ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex &&
+ !empty($oImapResponse->ResponseList[2]) &&
+ $sCmd === $oImapResponse->ResponseList[2])
+ {
+ $iStart = 3;
+ }
+
+ for ($iIndex = $iStart, $iLen = \count($oImapResponse->ResponseList); $iIndex < $iLen; $iIndex++)
+ {
+ $aReturn[] = (int) $oImapResponse->ResponseList[$iIndex];
+ }
+ }
+ }
+
+ $aReturn = \array_reverse($aReturn);
+ return $aReturn;
+ }
+
+ /**
+ * @param mixed $aValue
+ *
+ * @return mixed
+ */
+ private function validateThreadItem($aValue)
+ {
+ $mResult = false;
+ if (\is_numeric($aValue))
+ {
+ $mResult = (int) $aValue;
+ if (0 >= $mResult)
+ {
+ $mResult = false;
+ }
+ }
+ else if (\is_array($aValue))
+ {
+ if (1 === \count($aValue) && \is_numeric($aValue[0]))
+ {
+ $mResult = (int) $aValue[0];
+ if (0 >= $mResult)
+ {
+ $mResult = false;
+ }
+ }
+ else
+ {
+ $mResult = array();
+ foreach ($aValue as $aValueItem)
+ {
+ $mTemp = $this->validateThreadItem($aValueItem);
+ if (false !== $mTemp)
+ {
+ $mResult[] = $mTemp;
+ }
+ }
+ }
+ }
+
+ return $mResult;
+ }
+
+ /**
+ * @param string $sSearchCriterias = 'ALL'
+ * @param bool $bReturnUid = true
+ * @param string $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSimpleThread($sSearchCriterias = 'ALL', $bReturnUid = true, $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8)
+ {
+ $sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
+ $sSearchCriterias = !\MailSo\Base\Validator::NotEmptyString($sSearchCriterias, true) || '*' === $sSearchCriterias
+ ? 'ALL' : $sSearchCriterias;
+
+ $sThreadType = '';
+ switch (true)
+ {
+ case $this->IsSupported('THREAD=REFS'):
+ $sThreadType = 'REFS';
+ break;
+ case $this->IsSupported('THREAD=REFERENCES'):
+ $sThreadType = 'REFERENCES';
+ break;
+ case $this->IsSupported('THREAD=ORDEREDSUBJECT'):
+ $sThreadType = 'ORDEREDSUBJECT';
+ break;
+ default:
+ $this->writeLogException(
+ new Exceptions\RuntimeException('Thread is not supported'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ break;
+ }
+
+ $aRequest = array();
+ $aRequest[] = $sThreadType;
+ $aRequest[] = \strtoupper($sCharset);
+ $aRequest[] = $sSearchCriterias;
+
+ $sCmd = 'THREAD';
+
+ $this->SendRequest($sCommandPrefix.$sCmd, $aRequest);
+ $aResult = $this->parseResponseWithValidation();
+
+ $aReturn = array();
+ $oImapResponse = null;
+
+ foreach ($aResult as /* @var $oImapResponse \MailSo\Imap\Response */ $oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
+ && ($sCmd === $oImapResponse->StatusOrIndex ||
+ ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex) && !empty($oImapResponse->ResponseList[2]) &&
+ $sCmd === $oImapResponse->ResponseList[2])
+ && \is_array($oImapResponse->ResponseList)
+ && 2 < \count($oImapResponse->ResponseList))
+ {
+ $iStart = 2;
+ if ($bReturnUid && 'UID' === $oImapResponse->StatusOrIndex &&
+ !empty($oImapResponse->ResponseList[2]) &&
+ $sCmd === $oImapResponse->ResponseList[2])
+ {
+ $iStart = 3;
+ }
+
+ for ($iIndex = $iStart, $iLen = \count($oImapResponse->ResponseList); $iIndex < $iLen; $iIndex++)
+ {
+ $aNewValue = $this->validateThreadItem($oImapResponse->ResponseList[$iIndex]);
+ if (false !== $aNewValue)
+ {
+ $aReturn[] = $aNewValue;
+ }
+ }
+ }
+ }
+
+ return $aReturn;
+ }
+
+ /**
+ * @param string $sToFolder
+ * @param string $sIndexRange
+ * @param bool $bIndexIsUid
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageCopy($sToFolder, $sIndexRange, $bIndexIsUid)
+ {
+ if (0 === \strlen($sIndexRange))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $sCommandPrefix = ($bIndexIsUid) ? 'UID ' : '';
+ return $this->SendRequestWithCheck($sCommandPrefix.'COPY',
+ array($sIndexRange, $this->EscapeString($sToFolder)));
+ }
+
+ /**
+ * @param string $sToFolder
+ * @param string $sIndexRange
+ * @param bool $bIndexIsUid
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageMove($sToFolder, $sIndexRange, $bIndexIsUid)
+ {
+ if (0 === \strlen($sIndexRange))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ if (!$this->IsSupported('MOVE'))
+ {
+ $this->writeLogException(
+ new Exceptions\RuntimeException('Move is not supported'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $sCommandPrefix = ($bIndexIsUid) ? 'UID ' : '';
+ return $this->SendRequestWithCheck($sCommandPrefix.'MOVE',
+ array($sIndexRange, $this->EscapeString($sToFolder)));
+ }
+
+ /**
+ * @param string $sUidRangeIfSupported = ''
+ * @param bool $bForceUidExpunge = false
+ * @param bool $bExpungeAll = false
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageExpunge($sUidRangeIfSupported = '', $bForceUidExpunge = false, $bExpungeAll = false)
+ {
+ $sUidRangeIfSupported = \trim($sUidRangeIfSupported);
+
+ $sCmd = 'EXPUNGE';
+ $aArguments = array();
+
+ if (!$bExpungeAll && $bForceUidExpunge && 0 < \strlen($sUidRangeIfSupported) && $this->IsSupported('UIDPLUS'))
+ {
+ $sCmd = 'UID '.$sCmd;
+ $aArguments = array($sUidRangeIfSupported);
+ }
+
+ return $this->SendRequestWithCheck($sCmd, $aArguments);
+ }
+
+ /**
+ * @param string $sIndexRange
+ * @param bool $bIndexIsUid
+ * @param array $aInputStoreItems
+ * @param string $sStoreAction
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageStoreFlag($sIndexRange, $bIndexIsUid, $aInputStoreItems, $sStoreAction)
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sIndexRange, true) ||
+ !\MailSo\Base\Validator::NotEmptyString($sStoreAction, true) ||
+ 0 === \count($aInputStoreItems))
+ {
+ return false;
+ }
+
+ $sCmd = ($bIndexIsUid) ? 'UID STORE' : 'STORE';
+ return $this->SendRequestWithCheck($sCmd, array($sIndexRange, $sStoreAction, $aInputStoreItems));
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param resource $rMessageAppendStream
+ * @param int $iStreamSize
+ * @param array $aAppendFlags = null
+ * @param int $iUid = null
+ * @param int $sDateTime = 0
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageAppendStream($sFolderName, $rMessageAppendStream, $iStreamSize, $aAppendFlags = null, &$iUid = null, $sDateTime = 0)
+ {
+ $aData = array($this->EscapeString($sFolderName), $aAppendFlags);
+ if (0 < $sDateTime)
+ {
+ $aData[] = $this->EscapeString(\gmdate('d-M-Y H:i:s', $sDateTime).' +0000');
+ }
+
+ $aData[] = '{'.$iStreamSize.'}';
+
+ $this->SendRequest('APPEND', $aData);
+ $this->parseResponseWithValidation();
+
+ $this->writeLog('Write to connection stream', \MailSo\Log\Enumerations\Type::NOTE);
+
+ \MailSo\Base\Utils::MultipleStreamWriter($rMessageAppendStream, array($this->rConnect));
+
+ $this->sendRaw('');
+ $this->parseResponseWithValidation();
+
+ if (null !== $iUid)
+ {
+ $aLastResponse = $this->GetLastResponse();
+ if (\is_array($aLastResponse) && 0 < \count($aLastResponse) && $aLastResponse[\count($aLastResponse) - 1])
+ {
+ $oLast = $aLastResponse[count($aLastResponse) - 1];
+ if ($oLast && \MailSo\Imap\Enumerations\ResponseType::TAGGED === $oLast->ResponseType && \is_array($oLast->OptionalResponse))
+ {
+ if (0 < \strlen($oLast->OptionalResponse[0]) &&
+ 0 < \strlen($oLast->OptionalResponse[2]) &&
+ 'APPENDUID' === strtoupper($oLast->OptionalResponse[0]) &&
+ \is_numeric($oLast->OptionalResponse[2])
+ )
+ {
+ $iUid = (int) $oLast->OptionalResponse[2];
+ }
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Imap\FolderInformation
+ */
+ public function FolderCurrentInformation()
+ {
+ return $this->oCurrentFolderInfo;
+ }
+
+ /**
+ * @param string $sCommand
+ * @param array $aParams = array()
+ * @param bool $bBreakOnLiteral = false
+ *
+ * @return string
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ public function SendRequest($sCommand, $aParams = array(), $bBreakOnLiteral = false)
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sCommand, true) || !\is_array($aParams))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->IsConnected(true);
+
+ $sTag = $this->getNewTag();
+
+ $sCommand = \trim($sCommand);
+ $sRealCommand = $sTag.' '.$sCommand.$this->prepearParamLine($aParams);
+
+ $sFakeCommand = '';
+ $aFakeParams = $this->secureRequestParams($sCommand, $aParams);
+ if (null !== $aFakeParams)
+ {
+ $sFakeCommand = $sTag.' '.$sCommand.$this->prepearParamLine($aFakeParams);
+ }
+
+ $this->aTagTimeouts[$sTag] = \microtime(true);
+
+ if ($bBreakOnLiteral && !\preg_match('/\d\+\}\r\n/', $sRealCommand))
+ {
+ $iPos = \strpos($sRealCommand, "}\r\n");
+ if (false !== $iPos)
+ {
+ $iFakePos = \strpos($sFakeCommand, "}\r\n");
+
+ $this->sendRaw(\substr($sRealCommand, 0, $iPos + 1), true,
+ false !== $iFakePos ? \substr($sFakeCommand, 0, $iFakePos + 3) : '');
+
+ return \substr($sRealCommand, $iPos + 3);
+ }
+ }
+
+ $this->sendRaw($sRealCommand, true, $sFakeCommand);
+ return '';
+ }
+
+ /**
+ * @param string $sCommand
+ * @param array $aParams
+ *
+ * @return array|null
+ */
+ private function secureRequestParams($sCommand, $aParams)
+ {
+ $aResult = null;
+ switch ($sCommand)
+ {
+ case 'LOGIN':
+ $aResult = $aParams;
+ if (\is_array($aResult) && 2 === count($aResult))
+ {
+ $aResult[1] = '"********"';
+ }
+ break;
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sCommand
+ * @param array $aParams = array()
+ * @param bool $bFindCapa = false
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function SendRequestWithCheck($sCommand, $aParams = array(), $bFindCapa = false)
+ {
+ $this->SendRequest($sCommand, $aParams);
+ $this->parseResponseWithValidation(null, $bFindCapa);
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function GetLastResponse()
+ {
+ return $this->aLastResponse;
+ }
+
+ /**
+ * @param mixed $aResult
+ *
+ * @return array
+ *
+ * @throws \MailSo\Imap\Exceptions\ResponseNotFoundException
+ * @throws \MailSo\Imap\Exceptions\InvalidResponseException
+ * @throws \MailSo\Imap\Exceptions\NegativeResponseException
+ */
+ private function validateResponse($aResult)
+ {
+ if (!\is_array($aResult) || 0 === $iCnt = \count($aResult))
+ {
+ $this->writeLogException(
+ new Exceptions\ResponseNotFoundException(),
+ \MailSo\Log\Enumerations\Type::WARNING, true);
+ }
+
+ if ($aResult[$iCnt - 1]->ResponseType !== \MailSo\Imap\Enumerations\ResponseType::CONTINUATION)
+ {
+ if (!$aResult[$iCnt - 1]->IsStatusResponse)
+ {
+ $this->writeLogException(
+ new Exceptions\InvalidResponseException($aResult),
+ \MailSo\Log\Enumerations\Type::WARNING, true);
+ }
+
+ if (\MailSo\Imap\Enumerations\ResponseStatus::OK !== $aResult[$iCnt - 1]->StatusOrIndex)
+ {
+ $this->writeLogException(
+ new Exceptions\NegativeResponseException($aResult),
+ \MailSo\Log\Enumerations\Type::WARNING, true);
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sEndTag = null
+ * @param bool $bFindCapa = false
+ *
+ * @return array|bool
+ */
+ protected function parseResponse($sEndTag = null, $bFindCapa = false)
+ {
+ if (\is_resource($this->rConnect))
+ {
+ $oImapResponse = null;
+ $sEndTag = (null === $sEndTag) ? $this->getCurrentTag() : $sEndTag;
+
+ while (true)
+ {
+ $oImapResponse = Response::NewInstance();
+
+ $this->partialParseResponseBranch($oImapResponse);
+
+ if ($oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNKNOWN === $oImapResponse->ResponseType)
+ {
+ return false;
+ }
+
+ if ($bFindCapa)
+ {
+ $this->initCapabilityImapResponse($oImapResponse);
+ }
+
+ $this->aPartialResponses[] = $oImapResponse;
+ if ($sEndTag === $oImapResponse->Tag || \MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oImapResponse->ResponseType)
+ {
+ if (isset($this->aTagTimeouts[$sEndTag]))
+ {
+ $this->writeLog((\microtime(true) - $this->aTagTimeouts[$sEndTag]).' ('.$sEndTag.')',
+ \MailSo\Log\Enumerations\Type::TIME);
+
+ unset($this->aTagTimeouts[$sEndTag]);
+ }
+
+ break;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ unset($oImapResponse);
+ }
+ }
+
+ $this->iResponseBufParsedPos = 0;
+ $this->aLastResponse = $this->aPartialResponses;
+ $this->aPartialResponses = array();
+
+ return $this->aLastResponse;
+ }
+
+ /**
+ * @param string $sEndTag = null
+ * @param bool $bFindCapa = false
+ *
+ * @return array
+ */
+ private function parseResponseWithValidation($sEndTag = null, $bFindCapa = false)
+ {
+ return $this->validateResponse($this->parseResponse($sEndTag, $bFindCapa));
+ }
+
+ /**
+ * @param \MailSo\Imap\Response $oImapResponse
+ *
+ * @return void
+ */
+ private function initCapabilityImapResponse($oImapResponse)
+ {
+ if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oImapResponse->ResponseType
+ && \is_array($oImapResponse->ResponseList))
+ {
+ $aList = null;
+ if (isset($oImapResponse->ResponseList[1]) && \is_string($oImapResponse->ResponseList[1]) &&
+ 'CAPABILITY' === \strtoupper($oImapResponse->ResponseList[1]))
+ {
+ $aList = \array_slice($oImapResponse->ResponseList, 2);
+ }
+ else if ($oImapResponse->OptionalResponse && \is_array($oImapResponse->OptionalResponse) &&
+ 1 < \count($oImapResponse->OptionalResponse) && \is_string($oImapResponse->OptionalResponse[0]) &&
+ 'CAPABILITY' === \strtoupper($oImapResponse->OptionalResponse[0]))
+ {
+ $aList = \array_slice($oImapResponse->OptionalResponse, 1);
+ }
+
+ if (\is_array($aList) && 0 < \count($aList))
+ {
+ $this->aCapabilityItems = \array_map('strtoupper', $aList);
+ }
+ }
+ }
+
+ /**
+ * @return array|string
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ private function partialParseResponseBranch(&$oImapResponse, $iStackIndex = -1,
+ $bTreatAsAtom = false, $sParentToken = '', $sOpenBracket = '')
+ {
+ $mNull = null;
+
+ $iStackIndex++;
+ $iPos = $this->iResponseBufParsedPos;
+
+ $sPreviousAtomUpperCase = null;
+ $bIsEndOfList = false;
+ $bIsClosingBracketSquare = false;
+ $iLiteralLen = 0;
+ $iBufferEndIndex = 0;
+ $iDebugCount = 0;
+
+ $rImapLiteralStream = null;
+
+ $bIsGotoDefault = false;
+ $bIsGotoLiteral = false;
+ $bIsGotoLiteralEnd = false;
+ $bIsGotoAtomBracket = false;
+ $bIsGotoNotAtomBracket = false;
+
+ $bCountOneInited = false;
+ $bCountTwoInited = false;
+
+ $sAtomBuilder = $bTreatAsAtom ? '' : null;
+ $aList = array();
+ if (null !== $oImapResponse)
+ {
+ $aList =& $oImapResponse->ResponseList;
+ }
+
+ while (!$bIsEndOfList)
+ {
+ $iDebugCount++;
+ if (100000 === $iDebugCount)
+ {
+ $this->Logger()->Write('PartialParseOver: '.$iDebugCount, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+
+ if ($this->bNeedNext)
+ {
+ $iPos = 0;
+ $this->getNextBuffer();
+ $this->iResponseBufParsedPos = $iPos;
+ $this->bNeedNext = false;
+ }
+
+ $sChar = null;
+ if ($bIsGotoDefault)
+ {
+ $sChar = 'GOTO_DEFAULT';
+ $bIsGotoDefault = false;
+ }
+ else if ($bIsGotoLiteral)
+ {
+ $bIsGotoLiteral = false;
+ $bIsGotoLiteralEnd = true;
+
+ if ($this->partialResponseLiteralCallbackCallable(
+ $sParentToken, null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), $this->rConnect, $iLiteralLen))
+ {
+ if (!$bTreatAsAtom)
+ {
+ $aList[] = '';
+ }
+ }
+ else
+ {
+ $sLiteral = '';
+ $iRead = $iLiteralLen;
+
+ while (0 < $iRead)
+ {
+ $sAddRead = \fread($this->rConnect, $iRead);
+ if (false === $sAddRead)
+ {
+ $sLiteral = false;
+ break;
+ }
+
+ $sLiteral .= $sAddRead;
+ $iRead -= \strlen($sAddRead);
+
+ \MailSo\Base\Utils::ResetTimeLimit();
+ }
+
+ if (false !== $sLiteral)
+ {
+ $iLiteralSize = \strlen($sLiteral);
+ \MailSo\Base\Loader::IncStatistic('NetRead', $iLiteralSize);
+ if ($iLiteralLen !== $iLiteralSize)
+ {
+ $this->writeLog('Literal stream read warning "read '.$iLiteralSize.' of '.
+ $iLiteralLen.'" bytes', \MailSo\Log\Enumerations\Type::WARNING);
+ }
+
+ if (!$bTreatAsAtom)
+ {
+ $aList[] = $sLiteral;
+
+ if (\MailSo\Config::$LogSimpleLiterals)
+ {
+ $this->writeLog('{'.\strlen($sLiteral).'} '.$sLiteral, \MailSo\Log\Enumerations\Type::INFO);
+ }
+ }
+ }
+ else
+ {
+ $this->writeLog('Can\'t read imap stream', \MailSo\Log\Enumerations\Type::NOTE);
+ }
+
+ unset($sLiteral);
+ }
+
+ continue;
+ }
+ else if ($bIsGotoLiteralEnd)
+ {
+ $rImapLiteralStream = null;
+ $sPreviousAtomUpperCase = null;
+ $this->bNeedNext = true;
+ $bIsGotoLiteralEnd = false;
+
+ continue;
+ }
+ else if ($bIsGotoAtomBracket)
+ {
+ if ($bTreatAsAtom)
+ {
+ $sAtomBlock = $this->partialParseResponseBranch($mNull, $iStackIndex, true,
+ null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), $sOpenBracket);
+
+ $sAtomBuilder .= $sAtomBlock;
+ $iPos = $this->iResponseBufParsedPos;
+ $sAtomBuilder .= ($bIsClosingBracketSquare) ? ']' : ')';
+ }
+
+ $sPreviousAtomUpperCase = null;
+ $bIsGotoAtomBracket = false;
+
+ continue;
+ }
+ else if ($bIsGotoNotAtomBracket)
+ {
+ $aSubItems = $this->partialParseResponseBranch($mNull, $iStackIndex, false,
+ null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), $sOpenBracket);
+
+ $aList[] = $aSubItems;
+ $iPos = $this->iResponseBufParsedPos;
+ $sPreviousAtomUpperCase = null;
+ if (null !== $oImapResponse && $oImapResponse->IsStatusResponse)
+ {
+ $oImapResponse->OptionalResponse = $aSubItems;
+
+ $bIsGotoDefault = true;
+ $bIsGotoNotAtomBracket = false;
+ continue;
+ }
+ $bIsGotoNotAtomBracket = false;
+
+ continue;
+ }
+ else
+ {
+ $iBufferEndIndex = \strlen($this->sResponseBuffer) - 3;
+ $this->bResponseBufferChanged = false;
+
+ if ($iPos > $iBufferEndIndex)
+ {
+ break;
+ }
+
+ $sChar = $this->sResponseBuffer[$iPos];
+ }
+
+ switch (true)
+ {
+ case ']' === $sChar:
+ $iPos++;
+ $sPreviousAtomUpperCase = null;
+ $bIsEndOfList = true;
+ break;
+ case ')' === $sChar:
+ $iPos++;
+ $sPreviousAtomUpperCase = null;
+ $bIsEndOfList = true;
+ break;
+ case ' ' === $sChar:
+ if ($bTreatAsAtom)
+ {
+ $sAtomBuilder .= ' ';
+ }
+ $iPos++;
+ break;
+ case '[' === $sChar:
+ $bIsClosingBracketSquare = true;
+ case '(' === $sChar:
+ if ('(' === $sChar)
+ {
+ $bIsClosingBracketSquare = false;
+ }
+
+ if ($bTreatAsAtom)
+ {
+ $sAtomBuilder .= $bIsClosingBracketSquare ? '[' : '(';
+ }
+ $iPos++;
+
+ $this->iResponseBufParsedPos = $iPos;
+ if ($bTreatAsAtom)
+ {
+ $bIsGotoAtomBracket = true;
+ $sOpenBracket = $bIsClosingBracketSquare ? '[' : '(';
+ }
+ else
+ {
+ $bIsGotoNotAtomBracket = true;
+ $sOpenBracket = $bIsClosingBracketSquare ? '[' : '(';
+ }
+ break;
+ case '{' === $sChar:
+ $bIsLiteralParsed = false;
+ $mLiteralEndPos = \strpos($this->sResponseBuffer, '}', $iPos);
+ if (false !== $mLiteralEndPos && $mLiteralEndPos > $iPos)
+ {
+ $sLiteralLenAsString = \substr($this->sResponseBuffer, $iPos + 1, $mLiteralEndPos - $iPos - 1);
+ if (\is_numeric($sLiteralLenAsString))
+ {
+ $iLiteralLen = (int) $sLiteralLenAsString;
+ $bIsLiteralParsed = true;
+ $iPos = $mLiteralEndPos + 3;
+ $bIsGotoLiteral = true;
+ break;
+ }
+ }
+ if (!$bIsLiteralParsed)
+ {
+ $iPos = $iBufferEndIndex;
+ }
+ $sPreviousAtomUpperCase = null;
+ break;
+ case '"' === $sChar:
+ $bIsQuotedParsed = false;
+ while (true)
+ {
+ $iClosingPos = $iPos + 1;
+ if ($iClosingPos > $iBufferEndIndex)
+ {
+ break;
+ }
+
+ while (true)
+ {
+ $iClosingPos = \strpos($this->sResponseBuffer, '"', $iClosingPos);
+ if (false === $iClosingPos)
+ {
+ break;
+ }
+
+ // TODO
+ $iClosingPosNext = $iClosingPos + 1;
+ if (
+ isset($this->sResponseBuffer[$iClosingPosNext]) &&
+ ' ' !== $this->sResponseBuffer[$iClosingPosNext] &&
+ "\r" !== $this->sResponseBuffer[$iClosingPosNext] &&
+ "\n" !== $this->sResponseBuffer[$iClosingPosNext] &&
+ ']' !== $this->sResponseBuffer[$iClosingPosNext] &&
+ ')' !== $this->sResponseBuffer[$iClosingPosNext]
+ )
+ {
+ $iClosingPos++;
+ continue;
+ }
+
+ $iSlashCount = 0;
+ while ('\\' === $this->sResponseBuffer[$iClosingPos - $iSlashCount - 1])
+ {
+ $iSlashCount++;
+ }
+
+ if ($iSlashCount % 2 == 1)
+ {
+ $iClosingPos++;
+ continue;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (false === $iClosingPos)
+ {
+ break;
+ }
+ else
+ {
+// $iSkipClosingPos = 0;
+ $bIsQuotedParsed = true;
+ if ($bTreatAsAtom)
+ {
+ $sAtomBuilder .= \strtr(
+ \substr($this->sResponseBuffer, $iPos, $iClosingPos - $iPos + 1),
+ array('\\\\' => '\\', '\\"' => '"')
+ );
+ }
+ else
+ {
+ $aList[] = \strtr(
+ \substr($this->sResponseBuffer, $iPos + 1, $iClosingPos - $iPos - 1),
+ array('\\\\' => '\\', '\\"' => '"')
+ );
+ }
+
+ $iPos = $iClosingPos + 1;
+ break;
+ }
+ }
+
+ if (!$bIsQuotedParsed)
+ {
+ $iPos = $iBufferEndIndex;
+ }
+
+ $sPreviousAtomUpperCase = null;
+ break;
+
+ case 'GOTO_DEFAULT' === $sChar:
+ default:
+ $iCharBlockStartPos = $iPos;
+
+ if (null !== $oImapResponse && $oImapResponse->IsStatusResponse)
+ {
+ $iPos = $iBufferEndIndex;
+
+ while ($iPos > $iCharBlockStartPos && $this->sResponseBuffer[$iCharBlockStartPos] === ' ')
+ {
+ $iCharBlockStartPos++;
+ }
+ }
+
+ $bIsAtomDone = false;
+ while (!$bIsAtomDone && ($iPos <= $iBufferEndIndex))
+ {
+ $sCharDef = $this->sResponseBuffer[$iPos];
+ switch (true)
+ {
+ case '[' === $sCharDef:
+ if (null === $sAtomBuilder)
+ {
+ $sAtomBuilder = '';
+ }
+
+ $sAtomBuilder .= \substr($this->sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos + 1);
+
+ $iPos++;
+ $this->iResponseBufParsedPos = $iPos;
+
+ $sListBlock = $this->partialParseResponseBranch($mNull, $iStackIndex, true,
+ null === $sPreviousAtomUpperCase ? '' : \strtoupper($sPreviousAtomUpperCase), '[');
+
+ if (null !== $sListBlock)
+ {
+ $sAtomBuilder .= $sListBlock.']';
+ }
+
+ $iPos = $this->iResponseBufParsedPos;
+ $iCharBlockStartPos = $iPos;
+ break;
+ case ' ' === $sCharDef:
+ case ')' === $sCharDef && '(' === $sOpenBracket:
+ case ']' === $sCharDef && '[' === $sOpenBracket:
+ $bIsAtomDone = true;
+ break;
+ default:
+ $iPos++;
+ break;
+ }
+ }
+
+ if ($iPos > $iCharBlockStartPos || null !== $sAtomBuilder)
+ {
+ $sLastCharBlock = \substr($this->sResponseBuffer, $iCharBlockStartPos, $iPos - $iCharBlockStartPos);
+ if (null === $sAtomBuilder)
+ {
+ $aList[] = $sLastCharBlock;
+ $sPreviousAtomUpperCase = $sLastCharBlock;
+ }
+ else
+ {
+ $sAtomBuilder .= $sLastCharBlock;
+
+ if (!$bTreatAsAtom)
+ {
+ $aList[] = $sAtomBuilder;
+ $sPreviousAtomUpperCase = $sAtomBuilder;
+ $sAtomBuilder = null;
+ }
+ }
+
+ if (null !== $oImapResponse)
+ {
+// if (1 === \count($aList))
+ if (!$bCountOneInited && 1 === \count($aList))
+// if (isset($aList[0]) && !isset($aList[1])) // fast 1 === \count($aList)
+ {
+ $bCountOneInited = true;
+
+ $oImapResponse->Tag = $aList[0];
+ if ('+' === $oImapResponse->Tag)
+ {
+ $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::CONTINUATION;
+ }
+ else if ('*' === $oImapResponse->Tag)
+ {
+ $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::UNTAGGED;
+ }
+ else if ($this->getCurrentTag() === $oImapResponse->Tag)
+ {
+ $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::TAGGED;
+ }
+ else
+ {
+ $oImapResponse->ResponseType = \MailSo\Imap\Enumerations\ResponseType::UNKNOWN;
+ }
+ }
+// else if (2 === \count($aList))
+ else if (!$bCountTwoInited && 2 === \count($aList))
+// else if (isset($aList[1]) && !isset($aList[2])) // fast 2 === \count($aList)
+ {
+ $bCountTwoInited = true;
+
+ $oImapResponse->StatusOrIndex = strtoupper($aList[1]);
+
+ if ($oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::OK ||
+ $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::NO ||
+ $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::BAD ||
+ $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::BYE ||
+ $oImapResponse->StatusOrIndex == \MailSo\Imap\Enumerations\ResponseStatus::PREAUTH)
+ {
+ $oImapResponse->IsStatusResponse = true;
+ }
+ }
+ else if (\MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oImapResponse->ResponseType)
+ {
+ $oImapResponse->HumanReadable = $sLastCharBlock;
+ }
+ else if ($oImapResponse->IsStatusResponse)
+ {
+ $oImapResponse->HumanReadable = $sLastCharBlock;
+ }
+ }
+ }
+ }
+ }
+
+ $this->iResponseBufParsedPos = $iPos;
+ if (null !== $oImapResponse)
+ {
+ $this->bNeedNext = true;
+ $this->iResponseBufParsedPos = 0;
+ }
+
+ if (100000 < $iDebugCount)
+ {
+ $this->Logger()->Write('PartialParseOverResult: '.$iDebugCount, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+
+ return $bTreatAsAtom ? $sAtomBuilder : $aList;
+ }
+
+ /**
+ * @param string $sParent
+ * @param string $sLiteralAtomUpperCase
+ * @param resource $rImapStream
+ * @param int $iLiteralLen
+ *
+ * @return bool
+ */
+ private function partialResponseLiteralCallbackCallable($sParent, $sLiteralAtomUpperCase, $rImapStream, $iLiteralLen)
+ {
+ $sLiteralAtomUpperCasePeek = '';
+ if (0 === \strpos($sLiteralAtomUpperCase, 'BODY'))
+ {
+ $sLiteralAtomUpperCasePeek = \str_replace('BODY', 'BODY.PEEK', $sLiteralAtomUpperCase);
+ }
+
+ $sFetchKey = '';
+ if (\is_array($this->aFetchCallbacks))
+ {
+ if (0 < \strlen($sLiteralAtomUpperCasePeek) && isset($this->aFetchCallbacks[$sLiteralAtomUpperCasePeek]))
+ {
+ $sFetchKey = $sLiteralAtomUpperCasePeek;
+ }
+ else if (0 < \strlen($sLiteralAtomUpperCase) && isset($this->aFetchCallbacks[$sLiteralAtomUpperCase]))
+ {
+ $sFetchKey = $sLiteralAtomUpperCase;
+ }
+ }
+
+ $bResult = false;
+ if (0 < \strlen($sFetchKey) && '' !== $this->aFetchCallbacks[$sFetchKey] &&
+ \is_callable($this->aFetchCallbacks[$sFetchKey]))
+ {
+ $rImapLiteralStream =
+ \MailSo\Base\StreamWrappers\Literal::CreateStream($rImapStream, $iLiteralLen);
+
+ $bResult = true;
+ $this->writeLog('Start Callback for '.$sParent.' / '.$sLiteralAtomUpperCase.
+ ' - try to read '.$iLiteralLen.' bytes.', \MailSo\Log\Enumerations\Type::NOTE);
+
+ $this->bRunningCallback = true;
+
+ try
+ {
+ \call_user_func($this->aFetchCallbacks[$sFetchKey],
+ $sParent, $sLiteralAtomUpperCase, $rImapLiteralStream);
+ }
+ catch (\Exception $oException)
+ {
+ $this->writeLog('Callback Exception', \MailSo\Log\Enumerations\Type::NOTICE);
+ $this->writeLogException($oException);
+ }
+
+ if (\is_resource($rImapLiteralStream))
+ {
+ $iNotReadLiteralLen = 0;
+
+ $bFeof = \feof($rImapLiteralStream);
+ $this->writeLog('End Callback for '.$sParent.' / '.$sLiteralAtomUpperCase.
+ ' - feof = '.($bFeof ? 'good' : 'BAD'), $bFeof ?
+ \MailSo\Log\Enumerations\Type::NOTE : \MailSo\Log\Enumerations\Type::WARNING);
+
+ if (!$bFeof)
+ {
+ while (!@\feof($rImapLiteralStream))
+ {
+ $sBuf = @\fread($rImapLiteralStream, 1024 * 1024);
+ if (false === $sBuf || 0 === \strlen($sBuf) || null === $sBuf)
+ {
+ break;
+ }
+
+ \MailSo\Base\Utils::ResetTimeLimit();
+ $iNotReadLiteralLen += \strlen($sBuf);
+ }
+
+ if (\is_resource($rImapLiteralStream) && !@\feof($rImapLiteralStream))
+ {
+ @\stream_get_contents($rImapLiteralStream);
+ }
+ }
+
+ if (\is_resource($rImapLiteralStream))
+ {
+ @\fclose($rImapLiteralStream);
+ }
+
+ if ($iNotReadLiteralLen > 0)
+ {
+ $this->writeLog('Not read literal size is '.$iNotReadLiteralLen.' bytes.',
+ \MailSo\Log\Enumerations\Type::WARNING);
+ }
+ }
+ else
+ {
+ $this->writeLog('Literal stream is not resource after callback.',
+ \MailSo\Log\Enumerations\Type::WARNING);
+ }
+
+ \MailSo\Base\Loader::IncStatistic('NetRead', $iLiteralLen);
+
+ $this->bRunningCallback = false;
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @param array $aParams = null
+ *
+ * @return string
+ */
+ private function prepearParamLine($aParams = array())
+ {
+ $sReturn = '';
+ if (\is_array($aParams) && 0 < \count($aParams))
+ {
+ foreach ($aParams as $mParamItem)
+ {
+ if (\is_array($mParamItem) && 0 < \count($mParamItem))
+ {
+ $sReturn .= ' ('.\trim($this->prepearParamLine($mParamItem)).')';
+ }
+ else if (\is_string($mParamItem))
+ {
+ $sReturn .= ' '.$mParamItem;
+ }
+ }
+ }
+ return $sReturn;
+ }
+
+ /**
+ * @return string
+ */
+ private function getNewTag()
+ {
+ $this->iTagCount++;
+ return $this->getCurrentTag();
+ }
+
+ /**
+ * @return string
+ */
+ private function getCurrentTag()
+ {
+ return self::TAG_PREFIX.$this->iTagCount;
+ }
+
+ /**
+ * @param string $sStringForEscape
+ *
+ * @return string
+ */
+ public function EscapeString($sStringForEscape)
+ {
+ return '"'.\str_replace(array('\\', '"'), array('\\\\', '\\"'), $sStringForEscape).'"';
+ }
+
+ /**
+ * @return string
+ */
+ protected function getLogName()
+ {
+ return 'IMAP';
+ }
+
+ /**
+ * @param \MailSo\Log\Logger $oLogger
+ *
+ * @return \MailSo\Imap\ImapClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetLogger($oLogger)
+ {
+ parent::SetLogger($oLogger);
+
+ return $this;
+ }
+
+ /**
+ * @param resource $rConnect
+ * @param array $aCapabilityItems = array()
+ *
+ * @return \MailSo\Imap\ImapClient
+ */
+ public function TestSetValues($rConnect, $aCapabilityItems = array())
+ {
+ $this->rConnect = $rConnect;
+ $this->aCapabilityItems = $aCapabilityItems;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sEndTag = null
+ * @param string $bFindCapa = false
+ *
+ * @return array
+ */
+ public function TestParseResponseWithValidationProxy($sEndTag = null, $bFindCapa = false)
+ {
+ return $this->parseResponseWithValidation($sEndTag, $bFindCapa);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/NamespaceResult.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/NamespaceResult.php
new file mode 100644
index 0000000..7d053f2
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/NamespaceResult.php
@@ -0,0 +1,132 @@
+sPersonal = '';
+ $this->sPersonalDelimiter = '';
+ $this->sOtherUser = '';
+ $this->sOtherUserDelimiter = '';
+ $this->sShared = '';
+ $this->sSharedDelimiter = '';
+ }
+
+ /**
+ * @return \MailSo\Imap\NamespaceResult
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @param \MailSo\Imap\Response $oImapResponse
+ *
+ * @return \MailSo\Imap\NamespaceResult
+ */
+ public function InitByImapResponse($oImapResponse)
+ {
+ if ($oImapResponse && $oImapResponse instanceof \MailSo\Imap\Response)
+ {
+ if (isset($oImapResponse->ResponseList[2][0]) &&
+ \is_array($oImapResponse->ResponseList[2][0]) &&
+ 2 <= \count($oImapResponse->ResponseList[2][0]))
+ {
+ $this->sPersonal = $oImapResponse->ResponseList[2][0][0];
+ $this->sPersonalDelimiter = $oImapResponse->ResponseList[2][0][1];
+
+ $this->sPersonal = 'INBOX'.$this->sPersonalDelimiter === \substr(\strtoupper($this->sPersonal), 0, 6) ?
+ 'INBOX'.$this->sPersonalDelimiter.\substr($this->sPersonal, 6) : $this->sPersonal;
+ }
+
+ if (isset($oImapResponse->ResponseList[3][0]) &&
+ \is_array($oImapResponse->ResponseList[3][0]) &&
+ 2 <= \count($oImapResponse->ResponseList[3][0]))
+ {
+ $this->sOtherUser = $oImapResponse->ResponseList[3][0][0];
+ $this->sOtherUserDelimiter = $oImapResponse->ResponseList[3][0][1];
+
+ $this->sOtherUser = 'INBOX'.$this->sOtherUserDelimiter === \substr(\strtoupper($this->sOtherUser), 0, 6) ?
+ 'INBOX'.$this->sOtherUserDelimiter.\substr($this->sOtherUser, 6) : $this->sOtherUser;
+ }
+
+ if (isset($oImapResponse->ResponseList[4][0]) &&
+ \is_array($oImapResponse->ResponseList[4][0]) &&
+ 2 <= \count($oImapResponse->ResponseList[4][0]))
+ {
+ $this->sShared = $oImapResponse->ResponseList[4][0][0];
+ $this->sSharedDelimiter = $oImapResponse->ResponseList[4][0][1];
+
+ $this->sShared = 'INBOX'.$this->sSharedDelimiter === \substr(\strtoupper($this->sShared), 0, 6) ?
+ 'INBOX'.$this->sSharedDelimiter.\substr($this->sShared, 6) : $this->sShared;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetPersonalNamespace()
+ {
+ return $this->sPersonal;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetPersonalNamespaceDelimiter()
+ {
+ return $this->sPersonalDelimiter;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/Response.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/Response.php
new file mode 100644
index 0000000..fb787ba
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Imap/Response.php
@@ -0,0 +1,104 @@
+ResponseList = array();
+ $this->OptionalResponse = null;
+ $this->StatusOrIndex = '';
+ $this->HumanReadable = '';
+ $this->IsStatusResponse = false;
+ $this->ResponseType = \MailSo\Imap\Enumerations\ResponseType::UNKNOWN;
+ $this->Tag = '';
+ }
+
+ /**
+ * @return \MailSo\Imap\Response
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @param string $aList
+ *
+ * @return string
+ */
+ private function recToLine($aList)
+ {
+ $aResult = array();
+ if (\is_array($aList))
+ {
+ foreach ($aList as $mItem)
+ {
+ $aResult[] = \is_array($mItem) ? '('.$this->recToLine($mItem).')' : (string) $mItem;
+ }
+ }
+
+ return \implode(' ', $aResult);
+ }
+
+
+ /**
+ * @return string
+ */
+ public function ToLine()
+ {
+ return $this->recToLine($this->ResponseList);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/LICENSE b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/LICENSE
new file mode 100644
index 0000000..6229c40
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Usenko Timur
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Log/Driver.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Log/Driver.php
new file mode 100644
index 0000000..755df58
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Log/Driver.php
@@ -0,0 +1,403 @@
+sDatePattern = 'H:i:s';
+ $this->sName = 'INFO';
+ $this->sNewLine = "\r\n";
+ $this->bTimePrefix = true;
+ $this->bTypedPrefix = true;
+ $this->bGuidPrefix = true;
+
+ $this->iTimeOffset = 0;
+
+ $this->iWriteOnTimeoutOnly = 0;
+ $this->bWriteOnErrorOnly = false;
+ $this->bWriteOnPhpErrorOnly = false;
+ $this->bFlushCache = false;
+ $this->aCache = array();
+
+ $this->aPrefixes = array(
+ \MailSo\Log\Enumerations\Type::INFO => '[DATA]',
+ \MailSo\Log\Enumerations\Type::SECURE => '[SECURE]',
+ \MailSo\Log\Enumerations\Type::NOTE => '[NOTE]',
+ \MailSo\Log\Enumerations\Type::TIME => '[TIME]',
+ \MailSo\Log\Enumerations\Type::TIME_DELTA => '[TIME]',
+ \MailSo\Log\Enumerations\Type::MEMORY => '[MEMORY]',
+ \MailSo\Log\Enumerations\Type::NOTICE => '[NOTICE]',
+ \MailSo\Log\Enumerations\Type::WARNING => '[WARNING]',
+ \MailSo\Log\Enumerations\Type::ERROR => '[ERROR]',
+
+ \MailSo\Log\Enumerations\Type::NOTICE_PHP => '[NOTICE]',
+ \MailSo\Log\Enumerations\Type::WARNING_PHP => '[WARNING]',
+ \MailSo\Log\Enumerations\Type::ERROR_PHP => '[ERROR]',
+ );
+ }
+
+ /**
+ * @param int $iTimeOffset
+ *
+ * @return \MailSo\Log\Driver
+ */
+ public function SetTimeOffset($iTimeOffset)
+ {
+ $this->iTimeOffset = $iTimeOffset;
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Log\Driver
+ */
+ public function DisableGuidPrefix()
+ {
+ $this->bGuidPrefix = false;
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Log\Driver
+ */
+ public function DisableTimePrefix()
+ {
+ $this->bTimePrefix = false;
+ return $this;
+ }
+
+ /**
+ * @param bool $bValue
+ *
+ * @return \MailSo\Log\Driver
+ */
+ public function WriteOnErrorOnly($bValue)
+ {
+ $this->bWriteOnErrorOnly = !!$bValue;
+ return $this;
+ }
+
+ /**
+ * @param bool $bValue
+ *
+ * @return \MailSo\Log\Driver
+ */
+ public function WriteOnPhpErrorOnly($bValue)
+ {
+ $this->bWriteOnPhpErrorOnly = !!$bValue;
+ return $this;
+ }
+
+ /**
+ * @param int $iTimeout
+ *
+ * @return \MailSo\Log\Driver
+ */
+ public function WriteOnTimeoutOnly($iTimeout)
+ {
+ $this->iWriteOnTimeoutOnly = (int) $iTimeout;
+ if (0 > $this->iWriteOnTimeoutOnly)
+ {
+ $this->iWriteOnTimeoutOnly = 0;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Log\Driver
+ */
+ public function DisableTypedPrefix()
+ {
+ $this->bTypedPrefix = false;
+ return $this;
+ }
+
+ /**
+ * @param string|array $mDesc
+ * @return bool
+ */
+ abstract protected function writeImplementation($mDesc);
+
+ /**
+ * @return bool
+ */
+ protected function writeEmptyLineImplementation()
+ {
+ return $this->writeImplementation('');
+ }
+
+ /**
+ * @param string $sTimePrefix
+ * @param string $sDesc
+ * @param int $iType = \MailSo\Log\Enumerations\Type::INFO
+ * @param array $sName = ''
+ *
+ * @return string
+ */
+ protected function loggerLineImplementation($sTimePrefix, $sDesc,
+ $iType = \MailSo\Log\Enumerations\Type::INFO, $sName = '')
+ {
+ return \ltrim(
+ ($this->bTimePrefix ? '['.$sTimePrefix.']' : '').
+ ($this->bGuidPrefix ? '['.\MailSo\Log\Logger::Guid().']' : '').
+ ($this->bTypedPrefix ? ' '.$this->getTypedPrefix($iType, $sName) : '')
+ ).$sDesc;
+ }
+
+ /**
+ * @return bool
+ */
+ protected function clearImplementation()
+ {
+ return true;
+ }
+
+ /**
+ * @return string
+ */
+ protected function getTimeWithMicroSec()
+ {
+ $aMicroTimeItems = \explode(' ', \microtime());
+ return \MailSo\Log\Logger::DateHelper($this->sDatePattern, $this->iTimeOffset, $aMicroTimeItems[1]).'.'.
+ \str_pad((int) ($aMicroTimeItems[0] * 1000), 3, '0', STR_PAD_LEFT);
+ }
+
+ /**
+ * @param int $iType
+ * @param string $sName = ''
+ *
+ * @return string
+ */
+ protected function getTypedPrefix($iType, $sName = '')
+ {
+ $sName = 0 < \strlen($sName) ? $sName : $this->sName;
+ return isset($this->aPrefixes[$iType]) ? $sName.$this->aPrefixes[$iType].': ' : '';
+ }
+
+ /**
+ * @param string|array $mDesc
+ * @param bool $bDiplayCrLf = false
+ *
+ * @return string
+ */
+ protected function localWriteImplementation($mDesc, $bDiplayCrLf = false)
+ {
+ if ($bDiplayCrLf)
+ {
+ if (\is_array($mDesc))
+ {
+ foreach ($mDesc as &$sLine)
+ {
+ $sLine = \strtr($sLine, array("\r" => '\r', "\n" => '\n'.$this->sNewLine));
+ $sLine = \rtrim($sLine);
+ }
+ }
+ else
+ {
+ $mDesc = \strtr($mDesc, array("\r" => '\r', "\n" => '\n'.$this->sNewLine));
+ $mDesc = \rtrim($mDesc);
+ }
+ }
+
+ return $this->writeImplementation($mDesc);
+ }
+
+ /**
+ * @final
+ * @param string $sDesc
+ * @param int $iType = \MailSo\Log\Enumerations\Type::INFO
+ * @param string $sName = ''
+ * @param bool $bDiplayCrLf = false
+ *
+ * @return bool
+ */
+ final public function Write($sDesc, $iType = \MailSo\Log\Enumerations\Type::INFO, $sName = '', $bDiplayCrLf = false)
+ {
+ $bResult = true;
+ if (!$this->bFlushCache && ($this->bWriteOnErrorOnly || $this->bWriteOnPhpErrorOnly || 0 < $this->iWriteOnTimeoutOnly))
+ {
+ $bErrorPhp = false;
+
+ $bError = $this->bWriteOnErrorOnly && \in_array($iType, array(
+ \MailSo\Log\Enumerations\Type::NOTICE,
+ \MailSo\Log\Enumerations\Type::NOTICE_PHP,
+ \MailSo\Log\Enumerations\Type::WARNING,
+ \MailSo\Log\Enumerations\Type::WARNING_PHP,
+ \MailSo\Log\Enumerations\Type::ERROR,
+ \MailSo\Log\Enumerations\Type::ERROR_PHP
+ ));
+
+ if (!$bError)
+ {
+ $bErrorPhp = $this->bWriteOnPhpErrorOnly && \in_array($iType, array(
+ \MailSo\Log\Enumerations\Type::NOTICE_PHP,
+ \MailSo\Log\Enumerations\Type::WARNING_PHP,
+ \MailSo\Log\Enumerations\Type::ERROR_PHP
+ ));
+ }
+
+ if ($bError || $bErrorPhp)
+ {
+ $sFlush = '--- FlushLogCache: '.($bError ? 'WriteOnErrorOnly' : 'WriteOnPhpErrorOnly');
+ if (isset($this->aCache[0]) && empty($this->aCache[0]))
+ {
+ $this->aCache[0] = $sFlush;
+ \array_unshift($this->aCache, '');
+ }
+ else
+ {
+ \array_unshift($this->aCache, $sFlush);
+ }
+
+ $this->aCache[] = '--- FlushLogCache: Trigger';
+ $this->aCache[] = $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName);
+
+ $this->bFlushCache = true;
+ $bResult = $this->localWriteImplementation($this->aCache, $bDiplayCrLf);
+ $this->aCache = array();
+ }
+ else if (0 < $this->iWriteOnTimeoutOnly && \time() - APP_START_TIME > $this->iWriteOnTimeoutOnly)
+ {
+ $sFlush = '--- FlushLogCache: WriteOnTimeoutOnly ['.(\time() - APP_START_TIME).'sec]';
+ if (isset($this->aCache[0]) && empty($this->aCache[0]))
+ {
+ $this->aCache[0] = $sFlush;
+ \array_unshift($this->aCache, '');
+ }
+ else
+ {
+ \array_unshift($this->aCache, $sFlush);
+ }
+
+ $this->aCache[] = '--- FlushLogCache: Trigger';
+ $this->aCache[] = $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName);
+
+ $this->bFlushCache = true;
+ $bResult = $this->localWriteImplementation($this->aCache, $bDiplayCrLf);
+ $this->aCache = array();
+ }
+ else
+ {
+ $this->aCache[] = $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName);
+ }
+ }
+ else
+ {
+ $bResult = $this->localWriteImplementation(
+ $this->loggerLineImplementation($this->getTimeWithMicroSec(), $sDesc, $iType, $sName), $bDiplayCrLf);
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetNewLine()
+ {
+ return $this->sNewLine;
+ }
+
+ /**
+ * @final
+ * @return bool
+ */
+ final public function Clear()
+ {
+ return $this->clearImplementation();
+ }
+
+ /**
+ * @final
+ * @return void
+ */
+ final public function WriteEmptyLine()
+ {
+ if (!$this->bFlushCache && ($this->bWriteOnErrorOnly || $this->bWriteOnPhpErrorOnly || 0 < $this->iWriteOnTimeoutOnly))
+ {
+ $this->aCache[] = '';
+ }
+ else
+ {
+ $this->writeEmptyLineImplementation();
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Log/Drivers/Callback.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Log/Drivers/Callback.php
new file mode 100644
index 0000000..46e8789
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Log/Drivers/Callback.php
@@ -0,0 +1,83 @@
+fWriteCallback = \is_callable($fWriteCallback) ? $fWriteCallback : null;
+ $this->fClearCallback = \is_callable($fClearCallback) ? $fClearCallback : null;
+ }
+
+ /**
+ * @param mixed $fWriteCallback
+ * @param mixed $fClearCallback = null
+ *
+ * @return \MailSo\Log\Drivers\Callback
+ */
+ public static function NewInstance($fWriteCallback, $fClearCallback = null)
+ {
+ return new self($fWriteCallback, $fClearCallback);
+ }
+
+ /**
+ * @param string|array $mDesc
+ *
+ * @return bool
+ */
+ protected function writeImplementation($mDesc)
+ {
+ if ($this->fWriteCallback)
+ {
+ \call_user_func_array($this->fWriteCallback, array($mDesc));
+ }
+
+ return true;
+ }
+
+ /**
+ * @return bool
+ */
+ protected function clearImplementation()
+ {
+ if ($this->fClearCallback)
+ {
+ \call_user_func($this->fClearCallback);
+ }
+
+ return true;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Log/Drivers/File.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Log/Drivers/File.php
new file mode 100644
index 0000000..b3c3678
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Log/Drivers/File.php
@@ -0,0 +1,91 @@
+sLoggerFileName = $sLoggerFileName;
+ $this->sNewLine = $sNewLine;
+ }
+
+ /**
+ * @param string $sLoggerFileName
+ */
+ public function SetLoggerFileName($sLoggerFileName)
+ {
+ $this->sLoggerFileName = $sLoggerFileName;
+ }
+
+ /**
+ * @param string $sLoggerFileName
+ * @param string $sNewLine = "\r\n"
+ *
+ * @return \MailSo\Log\Drivers\File
+ */
+ public static function NewInstance($sLoggerFileName, $sNewLine = "\r\n")
+ {
+ return new self($sLoggerFileName, $sNewLine);
+ }
+
+ /**
+ * @param string|array $mDesc
+ *
+ * @return bool
+ */
+ protected function writeImplementation($mDesc)
+ {
+ return $this->writeToLogFile($mDesc);
+ }
+
+ /**
+ * @return bool
+ */
+ protected function clearImplementation()
+ {
+ return \unlink($this->sLoggerFileName);
+ }
+
+ /**
+ * @param string|array $mDesc
+ *
+ * @return bool
+ */
+ private function writeToLogFile($mDesc)
+ {
+ if (\is_array($mDesc))
+ {
+ $mDesc = \implode($this->sNewLine, $mDesc);
+ }
+
+ return \error_log($mDesc.$this->sNewLine, 3, $this->sLoggerFileName);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Log/Drivers/Inline.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Log/Drivers/Inline.php
new file mode 100644
index 0000000..817ffbb
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Log/Drivers/Inline.php
@@ -0,0 +1,89 @@
+sNewLine = $sNewLine;
+ $this->bHtmlEncodeSpecialChars = $bHtmlEncodeSpecialChars;
+ }
+
+ /**
+ * @param string $sNewLine = "\r\n"
+ * @param bool $bHtmlEncodeSpecialChars = false
+ *
+ * @return \MailSo\Log\Drivers\Inline
+ */
+ public static function NewInstance($sNewLine = "\r\n", $bHtmlEncodeSpecialChars = false)
+ {
+ return new self($sNewLine, $bHtmlEncodeSpecialChars);
+ }
+
+ /**
+ * @param string $mDesc
+ *
+ * @return bool
+ */
+ protected function writeImplementation($mDesc)
+ {
+ if (\is_array($mDesc))
+ {
+ if ($this->bHtmlEncodeSpecialChars)
+ {
+ $mDesc = \array_map(function ($sItem) {
+ return \htmlspecialchars($sItem);
+ }, $mDesc);
+ }
+
+ $mDesc = \implode($this->sNewLine, $mDesc);
+ }
+ else
+ {
+ echo ($this->bHtmlEncodeSpecialChars) ? \htmlspecialchars($mDesc).$this->sNewLine : $mDesc.$this->sNewLine;
+ }
+
+ return true;
+ }
+
+ /**
+ * @return bool
+ */
+ protected function clearImplementation()
+ {
+ if (\defined('PHP_SAPI') && 'cli' === PHP_SAPI && \MailSo\Base\Utils::FunctionExistsAndEnabled('system'))
+ {
+ \system('clear');
+ }
+
+ return true;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Log/Enumerations/Type.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Log/Enumerations/Type.php
new file mode 100644
index 0000000..6c3db90
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Log/Enumerations/Type.php
@@ -0,0 +1,34 @@
+bUsed = false;
+ $this->aForbiddenTypes = array();
+ $this->aSecretWords = array();
+ $this->bShowSecter = false;
+ $this->bHideErrorNotices = false;
+
+ if ($bRegPhpErrorHandler)
+ {
+ \set_error_handler(array(&$this, '__phpErrorHandler'));
+ }
+
+ \register_shutdown_function(array(&$this, '__loggerShutDown'));
+ }
+
+ /**
+ * @param bool $bRegPhpErrorHandler = false
+ *
+ * @return \MailSo\Log\Logger
+ */
+ public static function NewInstance($bRegPhpErrorHandler = false)
+ {
+ return new self($bRegPhpErrorHandler);
+ }
+
+ /**
+ * @staticvar \MailSo\Log\Logger $oInstance;
+ *
+ * @return \MailSo\Log\Logger
+ */
+ public static function SingletonInstance()
+ {
+ static $oInstance = null;
+ if (null === $oInstance)
+ {
+ $oInstance = self::NewInstance();
+ }
+
+ return $oInstance;
+ }
+
+ /**
+ * @param string $sFormat
+ * @param int $iTimeOffset = 0
+ * @param int $iTimestamp = 0
+ *
+ * @return string
+ */
+ public static function DateHelper($sFormat, $iTimeOffset = 0, $iTimestamp = null)
+ {
+ $iTimestamp = null === $iTimestamp ? \time() : (int) $iTimestamp;
+ $iTimeOffset = (int) $iTimeOffset;
+
+ return \gmdate($sFormat, $iTimestamp + $iTimeOffset * 3600);
+ }
+
+ /**
+ * @return bool
+ */
+ public static function IsSystemEnabled()
+ {
+ return !!(\MailSo\Config::$SystemLogger instanceof \MailSo\Log\Logger);
+ }
+
+ /**
+ * @param mixed $mData
+ * @param int $iType = \MailSo\Log\Enumerations\Type::INFO
+ */
+ public static function SystemLog($mData, $iType = \MailSo\Log\Enumerations\Type::INFO)
+ {
+ if (\MailSo\Config::$SystemLogger instanceof \MailSo\Log\Logger)
+ {
+ \MailSo\Config::$SystemLogger->WriteMixed($mData, $iType);
+ }
+ }
+
+ /**
+ * @staticvar string $sCache;
+ *
+ * @return string
+ */
+ public static function Guid()
+ {
+ static $sCache = null;
+ if (null === $sCache)
+ {
+ $sCache = \substr(\MailSo\Base\Utils::Md5Rand(), -8);
+ }
+
+ return $sCache;
+ }
+
+ /**
+ * @return bool
+ */
+ public function Ping()
+ {
+ return true;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsEnabled()
+ {
+ return 0 < $this->Count();
+ }
+
+ /**
+ * @param string $sWord
+ *
+ * @return bool
+ */
+ public function AddSecret($sWord)
+ {
+ if (\is_string($sWord) && 0 < \strlen(\trim($sWord)))
+ {
+ $this->aSecretWords[] = $sWord;
+ $this->aSecretWords = \array_unique($this->aSecretWords);
+ }
+ }
+
+ /**
+ * @param bool $bShow
+ *
+ * @return \MailSo\Log\Logger
+ */
+ public function SetShowSecter($bShow)
+ {
+ $this->bShowSecter = !!$bShow;
+ return $this;
+ }
+
+ /**
+ * @param bool $bValue
+ *
+ * @return \MailSo\Log\Logger
+ */
+ public function HideErrorNotices($bValue)
+ {
+ $this->bHideErrorNotices = !!$bValue;
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsShowSecter()
+ {
+ return $this->bShowSecter;
+ }
+
+ /**
+ * @param int $iType
+ *
+ * @return \MailSo\Log\Logger
+ */
+ public function AddForbiddenType($iType)
+ {
+ $this->aForbiddenTypes[$iType] = true;
+
+ return $this;
+ }
+
+ /**
+ * @param int $iType
+ *
+ * @return \MailSo\Log\Logger
+ */
+ public function RemoveForbiddenType($iType)
+ {
+ $this->aForbiddenTypes[$iType] = false;
+ return $this;
+ }
+
+ /**
+ * @param int $iErrNo
+ * @param string $sErrStr
+ * @param string $sErrFile
+ * @param int $iErrLine
+ *
+ * @return bool
+ */
+ public function __phpErrorHandler($iErrNo, $sErrStr, $sErrFile, $iErrLine)
+ {
+ $iType = \MailSo\Log\Enumerations\Type::NOTICE_PHP;
+ switch ($iErrNo)
+ {
+ case E_USER_ERROR:
+ $iType = \MailSo\Log\Enumerations\Type::ERROR_PHP;
+ break;
+ case E_USER_WARNING:
+ $iType = \MailSo\Log\Enumerations\Type::WARNING_PHP;
+ break;
+ }
+
+ $this->Write($sErrFile.' [line:'.$iErrLine.', code:'.$iErrNo.']', $iType, 'PHP');
+ $this->Write('Error: '.$sErrStr, $iType, 'PHP');
+
+ return !!(\MailSo\Log\Enumerations\Type::NOTICE === $iType && $this->bHideErrorNotices);
+ }
+
+ /**
+ * @return void
+ */
+ public function __loggerShutDown()
+ {
+ if ($this->bUsed)
+ {
+ $aStatistic = \MailSo\Base\Loader::Statistic();
+ if (\is_array($aStatistic))
+ {
+ if (isset($aStatistic['php']['memory_get_peak_usage']))
+ {
+ $this->Write('Memory peak usage: '.$aStatistic['php']['memory_get_peak_usage'],
+ \MailSo\Log\Enumerations\Type::MEMORY);
+ }
+
+ if (isset($aStatistic['time']))
+ {
+ $this->Write('Time delta: '.$aStatistic['time'], \MailSo\Log\Enumerations\Type::TIME_DELTA);
+ }
+ }
+ }
+ }
+
+ /**
+ * @return bool
+ */
+ public function WriteEmptyLine()
+ {
+ $iResult = 1;
+
+ $aLoggers =& $this->GetAsArray();
+ foreach ($aLoggers as /* @var $oLogger \MailSo\Log\Driver */ &$oLogger)
+ {
+ $iResult &= $oLogger->WriteEmptyLine();
+ }
+
+ return (bool) $iResult;
+ }
+
+ /**
+ * @param string $sDesc
+ * @param int $iType = \MailSo\Log\Enumerations\Type::INFO
+ * @param string $sName = ''
+ * @param bool $bSearchSecretWords = true
+ * @param bool $bDiplayCrLf = false
+ *
+ * @return bool
+ */
+ public function Write($sDesc, $iType = \MailSo\Log\Enumerations\Type::INFO,
+ $sName = '', $bSearchSecretWords = true, $bDiplayCrLf = false)
+ {
+ if (isset($this->aForbiddenTypes[$iType]) && true === $this->aForbiddenTypes[$iType])
+ {
+ return true;
+ }
+
+ $this->bUsed = true;
+
+ $oLogger = null;
+ $aLoggers = array();
+ $iResult = 1;
+
+ if ($bSearchSecretWords && !$this->bShowSecter && 0 < \count($this->aSecretWords))
+ {
+ $sDesc = \str_replace($this->aSecretWords, '*******', $sDesc);
+ }
+
+ $aLoggers =& $this->GetAsArray();
+ foreach ($aLoggers as /* @var $oLogger \MailSo\Log\Driver */ $oLogger)
+ {
+ $iResult &= $oLogger->Write($sDesc, $iType, $sName, $bDiplayCrLf);
+ }
+
+ return (bool) $iResult;
+ }
+
+ /**
+ * @param mixed $oValue
+ * @param int $iType = \MailSo\Log\Enumerations\Type::INFO
+ * @param string $sName = ''
+ * @param bool $bSearchSecretWords = false
+ * @param bool $bDiplayCrLf = false
+ *
+ * @return bool
+ */
+ public function WriteDump($oValue, $iType = \MailSo\Log\Enumerations\Type::INFO, $sName = '',
+ $bSearchSecretWords = false, $bDiplayCrLf = false)
+ {
+ return $this->Write(\print_r($oValue, true), $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
+ }
+
+ /**
+ * @param \Exception $oException
+ * @param int $iType = \MailSo\Log\Enumerations\Type::NOTICE
+ * @param string $sName = ''
+ * @param bool $bSearchSecretWords = true
+ * @param bool $bDiplayCrLf = false
+ *
+ * @return bool
+ */
+ public function WriteException($oException, $iType = \MailSo\Log\Enumerations\Type::NOTICE, $sName = '',
+ $bSearchSecretWords = true, $bDiplayCrLf = false)
+ {
+ if ($oException instanceof \Exception)
+ {
+ if (isset($oException->__LOGINNED__))
+ {
+ return true;
+ }
+
+ $oException->__LOGINNED__ = true;
+
+ return $this->Write((string) $oException, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
+ }
+
+ return false;
+ }
+
+ /**
+ * @param \Exception $oException
+ * @param int $iType = \MailSo\Log\Enumerations\Type::NOTICE
+ * @param string $sName = ''
+ * @param bool $bSearchSecretWords = true
+ * @param bool $bDiplayCrLf = false
+ *
+ * @return bool
+ */
+ public function WriteExceptionShort($oException, $iType = \MailSo\Log\Enumerations\Type::NOTICE, $sName = '',
+ $bSearchSecretWords = true, $bDiplayCrLf = false)
+ {
+ if ($oException instanceof \Exception)
+ {
+ if (isset($oException->__LOGINNED__))
+ {
+ return true;
+ }
+
+ $oException->__LOGINNED__ = true;
+
+ return $this->Write($oException->getMessage(), $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
+ }
+
+ return false;
+ }
+
+ /**
+ * @param mixed $mData
+ * @param int $iType = \MailSo\Log\Enumerations\Type::NOTICE
+ * @param string $sName = ''
+ * @param bool $bSearchSecretWords = true
+ * @param bool $bDiplayCrLf = false
+ *
+ * @return bool
+ */
+ public function WriteMixed($mData, $iType = null, $sName = '',
+ $bSearchSecretWords = true, $bDiplayCrLf = false)
+ {
+ $iType = null === $iType ? \MailSo\Log\Enumerations\Type::INFO : $iType;
+ if (\is_array($mData) || \is_object($mData))
+ {
+ if ($mData instanceof \Exception)
+ {
+ $iType = null === $iType ? \MailSo\Log\Enumerations\Type::NOTICE : $iType;
+ return $this->WriteException($mData, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
+ }
+ else
+ {
+ return $this->WriteDump($mData, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
+ }
+ }
+ else
+ {
+ return $this->Write($mData, $iType, $sName, $bSearchSecretWords, $bDiplayCrLf);
+ }
+
+ return false;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/Attachment.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/Attachment.php
new file mode 100644
index 0000000..51def4e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/Attachment.php
@@ -0,0 +1,239 @@
+Clear();
+ }
+
+ /**
+ * @return \MailSo\Mail\Attachment
+ */
+ public function Clear()
+ {
+ $this->sFolder = '';
+ $this->iUid = 0;
+ $this->oBodyStructure = null;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function Folder()
+ {
+ return $this->sFolder;
+ }
+
+ /**
+ * @return int
+ */
+ public function Uid()
+ {
+ return $this->iUid;
+ }
+
+ /**
+ * @return string
+ */
+ public function MimeIndex()
+ {
+ return $this->oBodyStructure ? $this->oBodyStructure->PartID() : '';
+ }
+
+ /**
+ * @param bool $bCalculateOnEmpty = false
+ *
+ * @return string
+ */
+ public function FileName($bCalculateOnEmpty = false)
+ {
+ $sFileName = '';
+ if ($this->oBodyStructure)
+ {
+ $sFileName = $this->oBodyStructure->FileName();
+ if ($bCalculateOnEmpty && 0 === \strlen(trim($sFileName)))
+ {
+ $sMimeType = \strtolower(\trim($this->MimeType()));
+ if ('message/rfc822' === $sMimeType)
+ {
+ $sFileName = 'message'.$this->MimeIndex().'.eml';
+ }
+ else if ('text/calendar' === $sMimeType)
+ {
+ $sFileName = 'calendar'.$this->MimeIndex().'.ics';
+ }
+ else if (0 < \strlen($sMimeType))
+ {
+ $sFileName = \str_replace('/', $this->MimeIndex().'.', $sMimeType);
+ }
+ }
+ }
+
+ return $sFileName;
+ }
+
+ /**
+ * @return string
+ */
+ public function MimeType()
+ {
+ return $this->oBodyStructure ? $this->oBodyStructure->ContentType() : '';
+ }
+
+ /**
+ * @return string
+ */
+ public function ContentTransferEncoding()
+ {
+ return $this->oBodyStructure ? $this->oBodyStructure->MailEncodingName() : '';
+ }
+
+ /**
+ * @return int
+ */
+ public function EncodedSize()
+ {
+ return $this->oBodyStructure ? $this->oBodyStructure->Size() : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function EstimatedSize()
+ {
+ return $this->oBodyStructure ? $this->oBodyStructure->EstimatedSize() : 0;
+ }
+
+ /**
+ * @return string
+ */
+ public function Cid()
+ {
+ return $this->oBodyStructure ? $this->oBodyStructure->ContentID() : '';
+ }
+
+ /**
+ * @return string
+ */
+ public function ContentLocation()
+ {
+ return $this->oBodyStructure ? $this->oBodyStructure->ContentLocation() : '';
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsInline()
+ {
+ return $this->oBodyStructure ? $this->oBodyStructure->IsInline() : false;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsImage()
+ {
+ return $this->oBodyStructure ? $this->oBodyStructure->IsImage() : false;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsArchive()
+ {
+ return $this->oBodyStructure ? $this->oBodyStructure->IsArchive() : false;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsPdf()
+ {
+ return $this->oBodyStructure ? $this->oBodyStructure->IsPdf() : false;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsDoc()
+ {
+ return $this->oBodyStructure ? $this->oBodyStructure->IsDoc() : false;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsPgpSignature()
+ {
+ return $this->oBodyStructure ? $this->oBodyStructure->IsPgpSignature() : false;
+ }
+
+ /**
+ * @return \MailSo\Mail\Attachment
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @param string $sFolder
+ * @param int $iUid
+ * @param \MailSo\Imap\BodyStructure $oBodyStructure
+ * @return \MailSo\Mail\Attachment
+ */
+ public static function NewBodyStructureInstance($sFolder, $iUid, $oBodyStructure)
+ {
+ return self::NewInstance()->InitByBodyStructure($sFolder, $iUid, $oBodyStructure);
+ }
+
+ /**
+ * @param string $sFolder
+ * @param int $iUid
+ * @param \MailSo\Imap\BodyStructure $oBodyStructure
+ * @return \MailSo\Mail\Attachment
+ */
+ public function InitByBodyStructure($sFolder, $iUid, $oBodyStructure)
+ {
+ $this->sFolder = $sFolder;
+ $this->iUid = $iUid;
+ $this->oBodyStructure = $oBodyStructure;
+ return $this;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/AttachmentCollection.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/AttachmentCollection.php
new file mode 100644
index 0000000..5cc64b5
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/AttachmentCollection.php
@@ -0,0 +1,74 @@
+FilterList(function ($oAttachment) {
+ return $oAttachment && $oAttachment->IsInline();
+ });
+
+ return \is_array($aList) ? \count($aList) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function NonInlineCount()
+ {
+ $aList = $this->FilterList(function ($oAttachment) {
+ return $oAttachment && !$oAttachment->IsInline();
+ });
+
+ return \is_array($aList) ? \count($aList) : 0;
+ }
+
+ /**
+ * @return array
+ */
+ public function SpecData()
+ {
+ return $this->MapList(function ($oAttachment) {
+ if ($oAttachment)
+ {
+ return array($oAttachment->FileName(true), $oAttachment->MimeType());
+ }
+
+ return null;
+ });
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/Exceptions/Exception.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/Exceptions/Exception.php
new file mode 100644
index 0000000..9bf1c42
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/Exceptions/Exception.php
@@ -0,0 +1,19 @@
+oImapFolder = $oImapFolder;
+ $this->oSubFolders = null;
+
+ $aNames = \explode($this->oImapFolder->Delimiter(), $this->oImapFolder->FullNameRaw());
+ $this->iNestingLevel = \count($aNames);
+
+ $this->sParentFullNameRaw = '';
+ if (1 < $this->iNestingLevel)
+ {
+ \array_pop($aNames);
+ $this->sParentFullNameRaw = \implode($this->oImapFolder->Delimiter(), $aNames);
+ }
+
+ $this->bSubscribed = $bSubscribed;
+ $this->bExisten = $bExisten;
+ }
+ else
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+ }
+
+ /**
+ * @param \MailSo\Imap\Folder $oImapFolder
+ * @param bool $bSubscribed = true
+ * @param bool $bExisten = true
+ *
+ * @return \MailSo\Mail\Folder
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public static function NewInstance($oImapFolder, $bSubscribed = true, $bExisten = true)
+ {
+ return new self($oImapFolder, $bSubscribed, $bExisten);
+ }
+
+ /**
+ * @param string $sFullNameRaw
+ * @param string $sDelimiter
+ *
+ * @return \MailSo\Mail\Folder
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public static function NewNonExistenInstance($sFullNameRaw, $sDelimiter)
+ {
+ return self::NewInstance(
+ \MailSo\Imap\Folder::NewInstance($sFullNameRaw, $sDelimiter, array('\NoSelect')), true, false);
+ }
+
+ /**
+ * @return string
+ */
+ public function Name()
+ {
+ return \MailSo\Base\Utils::ConvertEncoding($this->NameRaw(),
+ \MailSo\Base\Enumerations\Charset::UTF_7_IMAP,
+ \MailSo\Base\Enumerations\Charset::UTF_8);
+ }
+
+ /**
+ * @return string
+ */
+ public function FullName()
+ {
+ return \MailSo\Base\Utils::ConvertEncoding($this->FullNameRaw(),
+ \MailSo\Base\Enumerations\Charset::UTF_7_IMAP,
+ \MailSo\Base\Enumerations\Charset::UTF_8);
+ }
+
+ /**
+ * @return string
+ */
+ public function NameRaw()
+ {
+ return $this->oImapFolder->NameRaw();
+ }
+
+ /**
+ * @return string
+ */
+ public function FullNameRaw()
+ {
+ return $this->oImapFolder->FullNameRaw();
+ }
+
+ /**
+ * @return string
+ */
+ public function ParentFullName()
+ {
+ return \MailSo\Base\Utils::ConvertEncoding($this->sParentFullNameRaw,
+ \MailSo\Base\Enumerations\Charset::UTF_7_IMAP,
+ \MailSo\Base\Enumerations\Charset::UTF_8);
+ }
+
+ /**
+ * @return string
+ */
+ public function ParentFullNameRaw()
+ {
+ return $this->sParentFullNameRaw;
+ }
+
+ /**
+ * @return string
+ */
+ public function Delimiter()
+ {
+ return $this->oImapFolder->Delimiter();
+ }
+
+ /**
+ * @return array
+ */
+ public function Flags()
+ {
+ return $this->oImapFolder->Flags();
+ }
+
+ /**
+ * @return array
+ */
+ public function FlagsLowerCase()
+ {
+ return $this->oImapFolder->FlagsLowerCase();
+ }
+
+ /**
+ * @param bool $bCreateIfNull = false
+ * @return \MailSo\Mail\FolderCollection
+ */
+ public function SubFolders($bCreateIfNull = false)
+ {
+ if ($bCreateIfNull && !$this->oSubFolders)
+ {
+ $this->oSubFolders = FolderCollection::NewInstance();
+ }
+
+ return $this->oSubFolders;
+ }
+
+ /**
+ * @return bool
+ */
+ public function HasSubFolders()
+ {
+ return $this->oSubFolders && 0 < $this->oSubFolders->Count();
+ }
+
+ /**
+ * @return bool
+ */
+ public function HasVisibleSubFolders()
+ {
+ $sList = array();
+ if ($this->oSubFolders)
+ {
+ $sList = $this->oSubFolders->FilterList(function (\MailSo\Mail\Folder $oFolder) {
+ return $oFolder->IsSubscribed();
+ });
+ }
+
+ return 0 < \count($sList);
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsSubscribed()
+ {
+ return $this->bSubscribed;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsExists()
+ {
+ return $this->bExisten;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsSelectable()
+ {
+ return $this->IsExists() && $this->oImapFolder->IsSelectable();
+ }
+
+ /**
+ * @return mixed
+ */
+ public function Status()
+ {
+ return $this->oImapFolder->GetExtended('STATUS');
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsInbox()
+ {
+ return $this->oImapFolder->IsInbox();
+ }
+
+ /**
+ * @return int
+ */
+ public function GetFolderListType()
+ {
+ $aFlags = $this->oImapFolder->FlagsLowerCase();
+ $iListType = \MailSo\Imap\Enumerations\FolderType::USER;
+
+ if (\is_array($aFlags))
+ {
+ switch (true)
+ {
+ case \in_array('\inbox', $aFlags) || 'INBOX' === \strtoupper($this->FullNameRaw()):
+ $iListType = \MailSo\Imap\Enumerations\FolderType::INBOX;
+ break;
+ case \in_array('\sent', $aFlags):
+ case \in_array('\sentmail', $aFlags):
+ $iListType = \MailSo\Imap\Enumerations\FolderType::SENT;
+ break;
+ case \in_array('\drafts', $aFlags):
+ $iListType = \MailSo\Imap\Enumerations\FolderType::DRAFTS;
+ break;
+ case \in_array('\junk', $aFlags):
+ case \in_array('\spam', $aFlags):
+ $iListType = \MailSo\Imap\Enumerations\FolderType::JUNK;
+ break;
+ case \in_array('\trash', $aFlags):
+ case \in_array('\bin', $aFlags):
+ $iListType = \MailSo\Imap\Enumerations\FolderType::TRASH;
+ break;
+ case \in_array('\important', $aFlags):
+ $iListType = \MailSo\Imap\Enumerations\FolderType::IMPORTANT;
+ break;
+ case \in_array('\flagged', $aFlags):
+ case \in_array('\starred', $aFlags):
+ $iListType = \MailSo\Imap\Enumerations\FolderType::FLAGGED;
+ break;
+ case \in_array('\all', $aFlags):
+ case \in_array('\allmail', $aFlags):
+ case \in_array('\archive', $aFlags):
+ $iListType = \MailSo\Imap\Enumerations\FolderType::ALL;
+ break;
+ }
+ }
+
+ return $iListType;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/FolderCollection.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/FolderCollection.php
new file mode 100644
index 0000000..9f0c00a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/FolderCollection.php
@@ -0,0 +1,279 @@
+Namespace = '';
+ $this->FoldersHash = '';
+ $this->SystemFolders = array();
+ $this->IsThreadsSupported = false;
+ $this->Optimized = false;
+ }
+
+ /**
+ * @return \MailSo\Mail\FolderCollection
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @param string $sFullNameRaw
+ *
+ * @return \MailSo\Mail\Folder|null
+ */
+ public function GetByFullNameRaw($sFullNameRaw)
+ {
+ $mResult = null;
+ foreach ($this->aItems as /* @var $oFolder \MailSo\Mail\Folder */ $oFolder)
+ {
+ if ($oFolder->FullNameRaw() === $sFullNameRaw)
+ {
+ $mResult = $oFolder;
+ break;
+ }
+ else if ($oFolder->HasSubFolders())
+ {
+ $mResult = $oFolder->SubFolders(true)->GetByFullNameRaw($sFullNameRaw);
+ if ($mResult)
+ {
+ break;
+ }
+ else
+ {
+ $mResult = null;
+ }
+ }
+ }
+
+ return $mResult;
+ }
+
+ /**
+ * @return int
+ */
+ public function CountRec()
+ {
+ $iResult = $this->Count();
+ foreach ($this->aItems as /* @var $oFolder \MailSo\Mail\Folder */ $oFolder)
+ {
+ if ($oFolder)
+ {
+ $oSub = $oFolder->SubFolders();
+ $iResult += $oSub ? $oSub->CountRec() : 0;
+ }
+ }
+
+ return $iResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetNamespace()
+ {
+ return $this->Namespace;
+ }
+
+ /**
+ * @return string
+ */
+ public function FindDelimiter()
+ {
+ $sDelimiter = '/';
+
+ $oFolder = $this->GetByFullNameRaw('INBOX');
+ if (!$oFolder)
+ {
+ $oFolder = $this->GetByIndex(0);
+ }
+
+ if ($oFolder)
+ {
+ $sDelimiter = $oFolder->Delimiter();
+ }
+
+ return $sDelimiter;
+ }
+
+ /**
+ * @param string $sNamespace
+ *
+ * @return \MailSo\Mail\FolderCollection
+ */
+ public function SetNamespace($sNamespace)
+ {
+ $this->Namespace = $sNamespace;
+
+ return $this;
+ }
+
+ /**
+ * @param array $aUnsortedMailFolders
+ *
+ * @return void
+ */
+ public function InitByUnsortedMailFolderArray($aUnsortedMailFolders)
+ {
+ $this->Clear();
+
+ $aSortedByLenImapFolders = array();
+ foreach ($aUnsortedMailFolders as /* @var $oMailFolder \MailSo\Mail\Folder */ &$oMailFolder)
+ {
+ $aSortedByLenImapFolders[$oMailFolder->FullNameRaw()] =& $oMailFolder;
+ unset($oMailFolder);
+ }
+ unset($aUnsortedMailFolders);
+
+ $aAddedFolders = array();
+ foreach ($aSortedByLenImapFolders as /* @var $oMailFolder \MailSo\Mail\Folder */ $oMailFolder)
+ {
+ $sDelimiter = $oMailFolder->Delimiter();
+ $aFolderExplode = \explode($sDelimiter, $oMailFolder->FullNameRaw());
+
+ if (1 < \count($aFolderExplode))
+ {
+ \array_pop($aFolderExplode);
+
+ $sNonExistenFolderFullNameRaw = '';
+ foreach ($aFolderExplode as $sFolderExplodeItem)
+ {
+ $sNonExistenFolderFullNameRaw .= (0 < \strlen($sNonExistenFolderFullNameRaw))
+ ? $sDelimiter.$sFolderExplodeItem : $sFolderExplodeItem;
+
+ if (!isset($aSortedByLenImapFolders[$sNonExistenFolderFullNameRaw]))
+ {
+ try
+ {
+ $aAddedFolders[$sNonExistenFolderFullNameRaw] =
+ Folder::NewNonExistenInstance($sNonExistenFolderFullNameRaw, $sDelimiter);
+ }
+ catch (\Exception $oExc)
+ {
+ unset($oExc);
+ }
+ }
+ }
+ }
+ }
+
+ $aSortedByLenImapFolders = \array_merge($aSortedByLenImapFolders, $aAddedFolders);
+ unset($aAddedFolders);
+
+ \uasort($aSortedByLenImapFolders, function ($oFolderA, $oFolderB) {
+ return \strnatcmp($oFolderA->FullNameRaw(), $oFolderB->FullNameRaw());
+ });
+
+ foreach ($aSortedByLenImapFolders as /* @var $oMailFolder \MailSo\Mail\Folder */ &$oMailFolder)
+ {
+ $this->AddWithPositionSearch($oMailFolder);
+ unset($oMailFolder);
+ }
+
+ unset($aSortedByLenImapFolders);
+ }
+
+ /**
+ * @param \MailSo\Mail\Folder $oMailFolder
+ *
+ * @return bool
+ */
+ public function AddWithPositionSearch($oMailFolder)
+ {
+ $oItemFolder = null;
+ $bIsAdded = false;
+ $aList =& $this->GetAsArray();
+
+ foreach ($aList as /* @var $oItemFolder \MailSo\Mail\Folder */ $oItemFolder)
+ {
+ if ($oMailFolder instanceof \MailSo\Mail\Folder &&
+ 0 === \strpos($oMailFolder->FullNameRaw(), $oItemFolder->FullNameRaw().$oItemFolder->Delimiter()))
+ {
+ if ($oItemFolder->SubFolders(true)->AddWithPositionSearch($oMailFolder))
+ {
+ $bIsAdded = true;
+ }
+
+ break;
+ }
+ }
+
+ if (!$bIsAdded && $oMailFolder instanceof \MailSo\Mail\Folder)
+ {
+ $bIsAdded = true;
+ $this->Add($oMailFolder);
+ }
+
+ return $bIsAdded;
+ }
+
+ /**
+ * @param callable $fCallback
+ *
+ * @return void
+ */
+ public function SortByCallback($fCallback)
+ {
+ if (\is_callable($fCallback))
+ {
+ $aList =& $this->GetAsArray();
+
+ \usort($aList, $fCallback);
+
+ foreach ($aList as &$oItemFolder)
+ {
+ if ($oItemFolder->HasSubFolders())
+ {
+ $oItemFolder->SubFolders()->SortByCallback($fCallback);
+ }
+ }
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/MailClient.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/MailClient.php
new file mode 100644
index 0000000..a1143c5
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/MailClient.php
@@ -0,0 +1,2663 @@
+oLogger = null;
+
+ $this->oImapClient = \MailSo\Imap\ImapClient::NewInstance();
+ $this->oImapClient->SetTimeOuts(10, \MailSo\Config::$ImapTimeout);
+ }
+
+ /**
+ * @return \MailSo\Mail\MailClient
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @return \MailSo\Imap\ImapClient
+ */
+ public function ImapClient()
+ {
+ return $this->oImapClient;
+ }
+
+ /**
+ * @param string $sServerName
+ * @param int $iPort = 143
+ * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
+ * @param bool $bVerifySsl = false
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Connect($sServerName, $iPort = 143,
+ $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, $bVerifySsl = false)
+ {
+ $this->oImapClient->Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl);
+ return $this;
+ }
+
+ /**
+ * @param string $sLogin
+ * @param string $sPassword
+ * @param string $sProxyAuthUser = ''
+ * @param bool $bUseAuthPlainIfSupported = false
+ * @param bool $bUseAuthCramMd5IfSupported = false
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\LoginException
+ */
+ public function Login($sLogin, $sPassword, $sProxyAuthUser = '',
+ $bUseAuthPlainIfSupported = false, $bUseAuthCramMd5IfSupported = false)
+ {
+ $this->oImapClient->Login($sLogin, $sPassword, $sProxyAuthUser, $bUseAuthPlainIfSupported, $bUseAuthCramMd5IfSupported);
+ return $this;
+ }
+
+ /**
+ * @param string $sXOAuth2Token
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\LoginException
+ */
+ public function LoginWithXOauth2($sXOAuth2Token)
+ {
+ $this->oImapClient->LoginWithXOauth2($sXOAuth2Token);
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ public function Logout()
+ {
+ $this->oImapClient->Logout();
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ public function Disconnect()
+ {
+ $this->oImapClient->Disconnect();
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ public function LogoutAndDisconnect()
+ {
+ return $this->Logout()->Disconnect();
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsConnected()
+ {
+ return $this->oImapClient->IsConnected();
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsLoggined()
+ {
+ return $this->oImapClient->IsLoggined();
+ }
+
+ /**
+ * @return string
+ */
+ private function getEnvelopeOrHeadersRequestStringForSimpleList()
+ {
+ return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array(
+ \MailSo\Mime\Enumerations\Header::RETURN_PATH,
+ \MailSo\Mime\Enumerations\Header::RECEIVED,
+ \MailSo\Mime\Enumerations\Header::MIME_VERSION,
+ \MailSo\Mime\Enumerations\Header::FROM_,
+ \MailSo\Mime\Enumerations\Header::TO_,
+ \MailSo\Mime\Enumerations\Header::CC,
+ \MailSo\Mime\Enumerations\Header::SENDER,
+ \MailSo\Mime\Enumerations\Header::REPLY_TO,
+ \MailSo\Mime\Enumerations\Header::DATE,
+ \MailSo\Mime\Enumerations\Header::SUBJECT,
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE
+ ), true);
+ }
+
+ /**
+ * @return string
+ */
+ private function getEnvelopeOrHeadersRequestString()
+ {
+ if (\MailSo\Config::$MessageAllHeaders)
+ {
+ return \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK;
+ }
+
+ return \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array(
+ \MailSo\Mime\Enumerations\Header::RETURN_PATH,
+ \MailSo\Mime\Enumerations\Header::RECEIVED,
+ \MailSo\Mime\Enumerations\Header::MIME_VERSION,
+ \MailSo\Mime\Enumerations\Header::MESSAGE_ID,
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ \MailSo\Mime\Enumerations\Header::FROM_,
+ \MailSo\Mime\Enumerations\Header::TO_,
+ \MailSo\Mime\Enumerations\Header::CC,
+ \MailSo\Mime\Enumerations\Header::BCC,
+ \MailSo\Mime\Enumerations\Header::SENDER,
+ \MailSo\Mime\Enumerations\Header::REPLY_TO,
+ \MailSo\Mime\Enumerations\Header::DELIVERED_TO,
+ \MailSo\Mime\Enumerations\Header::IN_REPLY_TO,
+ \MailSo\Mime\Enumerations\Header::REFERENCES,
+ \MailSo\Mime\Enumerations\Header::DATE,
+ \MailSo\Mime\Enumerations\Header::SUBJECT,
+ \MailSo\Mime\Enumerations\Header::SENSITIVITY,
+ \MailSo\Mime\Enumerations\Header::X_MSMAIL_PRIORITY,
+ \MailSo\Mime\Enumerations\Header::IMPORTANCE,
+ \MailSo\Mime\Enumerations\Header::X_PRIORITY,
+ \MailSo\Mime\Enumerations\Header::X_DRAFT_INFO,
+ \MailSo\Mime\Enumerations\Header::RETURN_RECEIPT_TO,
+ \MailSo\Mime\Enumerations\Header::DISPOSITION_NOTIFICATION_TO,
+ \MailSo\Mime\Enumerations\Header::X_CONFIRM_READING_TO,
+ \MailSo\Mime\Enumerations\Header::AUTHENTICATION_RESULTS,
+ \MailSo\Mime\Enumerations\Header::X_DKIM_AUTHENTICATION_RESULTS,
+ ), true);
+//
+// return \MailSo\Imap\Enumerations\FetchType::ENVELOPE;
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param string $sMessageFlag
+ * @param bool $bSetAction = true
+ * @param bool $sSkipUnsupportedFlag = false
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ * @throws \MailSo\Mail\Exceptions\Exception
+ */
+ public function MessageSetFlagToAll($sFolderName, $sMessageFlag, $bSetAction = true, $sSkipUnsupportedFlag = false)
+ {
+ $this->oImapClient->FolderSelect($sFolderName);
+
+ $oFolderInfo = $this->oImapClient->FolderCurrentInformation();
+ if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag))
+ {
+ if (!$sSkipUnsupportedFlag)
+ {
+ throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag "'.$sMessageFlag.'" is not supported.');
+ }
+ }
+
+ if ($oFolderInfo && 0 < $oFolderInfo->Exists)
+ {
+ $sStoreAction = $bSetAction
+ ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT
+ : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT
+ ;
+
+ $this->oImapClient->MessageStoreFlag('1:*', false, array($sMessageFlag), $sStoreAction);
+ }
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param array $aIndexRange
+ * @param bool $bIndexIsUid
+ * @param string $sMessageFlag
+ * @param bool $bSetAction = true
+ * @param bool $sSkipUnsupportedFlag = false
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ * @throws \MailSo\Mail\Exceptions\Exception
+ */
+ public function MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid, $sMessageFlag, $bSetAction = true, $sSkipUnsupportedFlag = false)
+ {
+ $this->oImapClient->FolderSelect($sFolderName);
+
+ $oFolderInfo = $this->oImapClient->FolderCurrentInformation();
+ if (!$oFolderInfo || !$oFolderInfo->IsFlagSupported($sMessageFlag))
+ {
+ if (!$sSkipUnsupportedFlag)
+ {
+ throw new \MailSo\Mail\Exceptions\RuntimeException('Message flag "'.$sMessageFlag.'" is not supported.');
+ }
+ }
+ else
+ {
+ $sStoreAction = $bSetAction
+ ? \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT
+ : \MailSo\Imap\Enumerations\StoreAction::REMOVE_FLAGS_SILENT
+ ;
+
+ $this->oImapClient->MessageStoreFlag(\MailSo\Base\Utils::PrepearFetchSequence($aIndexRange),
+ $bIndexIsUid, array($sMessageFlag), $sStoreAction);
+ }
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param array $aIndexRange
+ * @param bool $bIndexIsUid
+ * @param bool $bSetAction = true
+ * @param bool $sSkipUnsupportedFlag = false
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSetFlagged($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true, $sSkipUnsupportedFlag = false)
+ {
+ $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid,
+ \MailSo\Imap\Enumerations\MessageFlag::FLAGGED, $bSetAction, $sSkipUnsupportedFlag);
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param bool $bSetAction = true
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSetSeenToAll($sFolderName, $bSetAction = true)
+ {
+ $this->MessageSetFlagToAll($sFolderName, \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction, true);
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param array $aIndexRange
+ * @param bool $bIndexIsUid
+ * @param bool $bSetAction = true
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageSetSeen($sFolderName, $aIndexRange, $bIndexIsUid, $bSetAction = true)
+ {
+ $this->MessageSetFlag($sFolderName, $aIndexRange, $bIndexIsUid,
+ \MailSo\Imap\Enumerations\MessageFlag::SEEN, $bSetAction, true);
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param int $iIndex
+ * @param bool $bIndexIsUid = true
+ * @param \MailSo\Cache\CacheClient $oCacher = null
+ * @param int $iBodyTextLimit = null
+ *
+ * @return \MailSo\Mail\Message|false
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function Message($sFolderName, $iIndex, $bIndexIsUid = true, $oCacher = null, $iBodyTextLimit = null)
+ {
+ if (!\MailSo\Base\Validator::RangeInt($iIndex, 1))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderSelect($sFolderName);
+
+ $oBodyStructure = null;
+ $oMessage = false;
+
+ $aBodyPeekMimeIndexes = array();
+ $aSignatureMimeIndexes = array();
+
+ $aFetchResponse = $this->oImapClient->Fetch(array(\MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE), $iIndex, $bIndexIsUid);
+ if (0 < \count($aFetchResponse) && isset($aFetchResponse[0]))
+ {
+ $oBodyStructure = $aFetchResponse[0]->GetFetchBodyStructure();
+ if ($oBodyStructure)
+ {
+ $aTextParts = $oBodyStructure->SearchHtmlOrPlainParts();
+ if (is_array($aTextParts) && 0 < \count($aTextParts))
+ {
+ foreach ($aTextParts as $oPart)
+ {
+ $aBodyPeekMimeIndexes[] = array($oPart->PartID(), $oPart->Size());
+ }
+ }
+
+ $aSignatureParts = $oBodyStructure->SearchByContentType('application/pgp-signature');
+ if (is_array($aSignatureParts) && 0 < \count($aSignatureParts))
+ {
+ foreach ($aSignatureParts as $oPart)
+ {
+ $aSignatureMimeIndexes[] = $oPart->PartID();
+ }
+ }
+ }
+ }
+
+ $aFetchItems = array(
+ \MailSo\Imap\Enumerations\FetchType::INDEX,
+ \MailSo\Imap\Enumerations\FetchType::UID,
+ \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE,
+ \MailSo\Imap\Enumerations\FetchType::INTERNALDATE,
+ \MailSo\Imap\Enumerations\FetchType::FLAGS,
+ $this->getEnvelopeOrHeadersRequestString()
+ );
+
+ if (0 < \count($aBodyPeekMimeIndexes))
+ {
+ foreach ($aBodyPeekMimeIndexes as $aTextMimeData)
+ {
+ $sLine = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$aTextMimeData[0].']';
+ if (\is_numeric($iBodyTextLimit) && 0 < $iBodyTextLimit && $iBodyTextLimit < $aTextMimeData[1])
+ {
+ $sLine .= '<0.'.((int) $iBodyTextLimit).'>';
+ }
+
+ $aFetchItems[] = $sLine;
+ }
+ }
+
+ if (0 < \count($aSignatureMimeIndexes))
+ {
+ foreach ($aSignatureMimeIndexes as $sTextMimeIndex)
+ {
+ $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sTextMimeIndex.']';
+ }
+ }
+
+ if (!$oBodyStructure)
+ {
+ $aFetchItems[] = \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE;
+ }
+
+ $aFetchResponse = $this->oImapClient->Fetch($aFetchItems, $iIndex, $bIndexIsUid);
+ if (0 < \count($aFetchResponse))
+ {
+ $oMessage = \MailSo\Mail\Message::NewFetchResponseInstance(
+ $sFolderName, $aFetchResponse[0], $oBodyStructure);
+ }
+
+ return $oMessage;
+ }
+
+ /**
+ * @param mixed $mCallback
+ * @param string $sFolderName
+ * @param int $iIndex
+ * @param bool $bIndexIsUid = true,
+ * @param string $sMimeIndex = ''
+ *
+ * @return bool
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageMimeStream($mCallback, $sFolderName, $iIndex, $bIndexIsUid = true, $sMimeIndex = '')
+ {
+ if (!is_callable($mCallback))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderSelect($sFolderName);
+
+ $sFileName = '';
+ $sContentType = '';
+ $sMailEncodingName = '';
+
+ $sMimeIndex = trim($sMimeIndex);
+ $aFetchResponse = $this->oImapClient->Fetch(array(
+ 0 === \strlen($sMimeIndex)
+ ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER_PEEK
+ : \MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.'.MIME]'
+ ), $iIndex, $bIndexIsUid);
+
+ if (0 < \count($aFetchResponse))
+ {
+ $sMime = $aFetchResponse[0]->GetFetchValue(
+ 0 === \strlen($sMimeIndex)
+ ? \MailSo\Imap\Enumerations\FetchType::BODY_HEADER
+ : \MailSo\Imap\Enumerations\FetchType::BODY.'['.$sMimeIndex.'.MIME]'
+ );
+
+ if (0 < \strlen($sMime))
+ {
+ $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sMime);
+
+ if (0 < \strlen($sMimeIndex))
+ {
+ $sFileName = $oHeaders->ParameterValue(
+ \MailSo\Mime\Enumerations\Header::CONTENT_DISPOSITION,
+ \MailSo\Mime\Enumerations\Parameter::FILENAME);
+
+ if (0 === \strlen($sFileName))
+ {
+ $sFileName = $oHeaders->ParameterValue(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ \MailSo\Mime\Enumerations\Parameter::NAME);
+ }
+
+ $sMailEncodingName = $oHeaders->ValueByName(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TRANSFER_ENCODING);
+
+ $sContentType = $oHeaders->ValueByName(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE);
+ }
+ else
+ {
+ $sSubject = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT);
+
+ $sFileName = 0 === \strlen($sSubject) ? (string) $iIndex : $sSubject;
+ $sFileName .= '.eml';
+
+ $sContentType = 'message/rfc822';
+ }
+ }
+ }
+
+ $aFetchResponse = $this->oImapClient->Fetch(array(
+ array(\MailSo\Imap\Enumerations\FetchType::BODY_PEEK.'['.$sMimeIndex.']',
+ function ($sParent, $sLiteralAtomUpperCase, $rImapLiteralStream) use ($mCallback, $sMimeIndex, $sMailEncodingName, $sContentType, $sFileName)
+ {
+ if (0 < \strlen($sLiteralAtomUpperCase))
+ {
+ if (is_resource($rImapLiteralStream) && 'FETCH' === $sParent)
+ {
+ $rMessageMimeIndexStream = (0 === \strlen($sMailEncodingName))
+ ? $rImapLiteralStream
+ : \MailSo\Base\StreamWrappers\Binary::CreateStream($rImapLiteralStream,
+ \MailSo\Base\StreamWrappers\Binary::GetInlineDecodeOrEncodeFunctionName(
+ $sMailEncodingName, true));
+
+ \call_user_func($mCallback, $rMessageMimeIndexStream, $sContentType, $sFileName, $sMimeIndex);
+ }
+ }
+ }
+ )), $iIndex, $bIndexIsUid);
+
+ return ($aFetchResponse && 1 === \count($aFetchResponse));
+ }
+
+ /**
+ * @param string $sFolder
+ * @param array $aIndexRange
+ * @param bool $bIndexIsUid
+ * @param bool $bUseExpunge = true
+ * @param bool $bExpungeAll = false
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageDelete($sFolder, $aIndexRange, $bIndexIsUid, $bUseExpunge = true, $bExpungeAll = false)
+ {
+ if (0 === \strlen($sFolder) || !\is_array($aIndexRange) || 0 === \count($aIndexRange))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderSelect($sFolder);
+
+ $sIndexRange = \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange);
+
+ $this->oImapClient->MessageStoreFlag($sIndexRange, $bIndexIsUid,
+ array(\MailSo\Imap\Enumerations\MessageFlag::DELETED),
+ \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT
+ );
+
+ if ($bUseExpunge)
+ {
+ $this->oImapClient->MessageExpunge($bIndexIsUid ? $sIndexRange : '', $bIndexIsUid, $bExpungeAll);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFromFolder
+ * @param string $sToFolder
+ * @param array $aIndexRange
+ * @param bool $bIndexIsUid
+ * @param bool $bUseMoveSupported = false
+ * @param bool $bExpungeAll = false
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageMove($sFromFolder, $sToFolder, $aIndexRange, $bIndexIsUid, $bUseMoveSupported = false, $bExpungeAll = false)
+ {
+ if (0 === \strlen($sFromFolder) || 0 === \strlen($sToFolder) ||
+ !\is_array($aIndexRange) || 0 === \count($aIndexRange))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderSelect($sFromFolder);
+
+ if ($bUseMoveSupported && $this->oImapClient->IsSupported('MOVE'))
+ {
+ $this->oImapClient->MessageMove($sToFolder,
+ \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid);
+ }
+ else
+ {
+ $this->oImapClient->MessageCopy($sToFolder,
+ \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid);
+
+ $this->MessageDelete($sFromFolder, $aIndexRange, $bIndexIsUid, true, $bExpungeAll);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFromFolder
+ * @param string $sToFolder
+ * @param array $aIndexRange
+ * @param bool $bIndexIsUid
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageCopy($sFromFolder, $sToFolder, $aIndexRange, $bIndexIsUid)
+ {
+ if (0 === \strlen($sFromFolder) || 0 === \strlen($sToFolder) ||
+ !\is_array($aIndexRange) || 0 === \count($aIndexRange))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderSelect($sFromFolder);
+ $this->oImapClient->MessageCopy($sToFolder,
+ \MailSo\Base\Utils::PrepearFetchSequence($aIndexRange), $bIndexIsUid);
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderUnSelect()
+ {
+ if ($this->oImapClient->IsSelected())
+ {
+ $this->oImapClient->FolderUnSelect();
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param resource $rMessageStream
+ * @param int $iMessageStreamSize
+ * @param string $sFolderToSave
+ * @param array $aAppendFlags = null
+ * @param int $iUid = null
+ *
+ * @return \MailSo\Mail\MailClient
+ */
+ public function MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags = null, &$iUid = null)
+ {
+ if (!\is_resource($rMessageStream) || 0 === \strlen($sFolderToSave))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->MessageAppendStream(
+ $sFolderToSave, $rMessageStream, $iMessageStreamSize, $aAppendFlags, $iUid);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sMessageFileName
+ * @param string $sFolderToSave
+ * @param array $aAppendFlags = null
+ * @param int &$iUid = null
+ *
+ * @return \MailSo\Mail\MailClient
+ */
+ public function MessageAppendFile($sMessageFileName, $sFolderToSave, $aAppendFlags = null, &$iUid = null)
+ {
+ if (!@\is_file($sMessageFileName) || !@\is_readable($sMessageFileName))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $iMessageStreamSize = \filesize($sMessageFileName);
+ $rMessageStream = \fopen($sMessageFileName, 'rb');
+
+ $this->MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderToSave, $aAppendFlags, $iUid);
+
+ if (\is_resource($rMessageStream))
+ {
+ @fclose($rMessageStream);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param int $iCount
+ * @param int $iUnseenCount
+ * @param string $sUidNext
+ * @param string $sHighestModSeq
+ *
+ * @return void
+ */
+ protected function initFolderValues($sFolderName, &$iCount, &$iUnseenCount,
+ &$sUidNext, &$sHighestModSeq = '')
+ {
+ $aTypes = array(
+ \MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES,
+ \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN,
+ \MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT
+ );
+
+ if ($this->oImapClient->IsSupported('CONDSTORE'))
+ {
+ $aTypes[] = \MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ;
+ }
+
+ $aFolderStatus = $this->oImapClient->FolderStatus($sFolderName, $aTypes);
+
+ $iCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES])
+ ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::MESSAGES] : 0;
+
+ $iUnseenCount = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN])
+ ? (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0;
+
+ $sUidNext = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT])
+ ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UIDNEXT] : '0';
+
+ $sHighestModSeq = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ])
+ ? (string) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::HIGHESTMODSEQ] : '';
+
+ if ($this->IsGmail() &&
+ ('INBOX' === $sFolderName || '[gmail]' === \strtolower(\substr($sFolderName, 0, 7))))
+ {
+ $oFolder = $this->oImapClient->FolderCurrentInformation();
+ if ($oFolder && null !== $oFolder->Exists && $oFolder->FolderName === $sFolderName)
+ {
+ $iSubCount = (int) $oFolder->Exists;
+ if (0 < $iSubCount && $iSubCount < $iCount)
+ {
+ $iCount = $iSubCount;
+ }
+ }
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function GenerateImapClientHash()
+ {
+ return \md5('ImapClientHash/'.
+ $this->oImapClient->GetLogginedUser().'@'.
+ $this->oImapClient->GetConnectedHost().':'.
+ $this->oImapClient->GetConnectedPort()
+ );
+ }
+
+ /**
+ * @param string $sFolder
+ * @param int $iCount
+ * @param int $iUnseenCount
+ * @param string $sUidNext
+ * @param string $sHighestModSeq = ''
+ *
+ * @return string
+ */
+ public function GenerateFolderHash($sFolder, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq = '')
+ {
+ $iUnseenCount = 0; // unneccessery
+ return \md5('FolderHash/'.$sFolder.'-'.$iCount.'-'.$iUnseenCount.'-'.$sUidNext.'-'.
+ $sHighestModSeq.'-'.$this->GenerateImapClientHash().'-'.
+ \MailSo\Config::$MessageListPermanentFilter
+ );
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param string $sPrevUidNext
+ * @param string $sCurrentUidNext
+ *
+ * @return array
+ */
+ private function getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sCurrentUidNext)
+ {
+ $aNewMessages = array();
+
+ if (0 < \strlen($sPrevUidNext) && (string) $sPrevUidNext !== (string) $sCurrentUidNext)
+ {
+ $this->oImapClient->FolderSelect($sFolderName);
+
+ $aFetchResponse = $this->oImapClient->Fetch(array(
+ \MailSo\Imap\Enumerations\FetchType::INDEX,
+ \MailSo\Imap\Enumerations\FetchType::UID,
+ \MailSo\Imap\Enumerations\FetchType::FLAGS,
+ \MailSo\Imap\Enumerations\FetchType::BuildBodyCustomHeaderRequest(array(
+ \MailSo\Mime\Enumerations\Header::FROM_,
+ \MailSo\Mime\Enumerations\Header::SUBJECT,
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE
+ ))
+ ), $sPrevUidNext.':*', true);
+
+ if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse))
+ {
+ foreach ($aFetchResponse as /* @var $oFetchResponse \MailSo\Imap\FetchResponse */ $oFetchResponse)
+ {
+ $aFlags = \array_map('strtolower', $oFetchResponse->GetFetchValue(
+ \MailSo\Imap\Enumerations\FetchType::FLAGS));
+
+ if (!\in_array(\strtolower(\MailSo\Imap\Enumerations\MessageFlag::SEEN), $aFlags))
+ {
+ $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID);
+ $sHeaders = $oFetchResponse->GetHeaderFieldsValue();
+
+ $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sHeaders);
+
+ $sContentTypeCharset = $oHeaders->ParameterValue(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ \MailSo\Mime\Enumerations\Parameter::CHARSET
+ );
+
+ $sCharset = '';
+ if (0 < \strlen($sContentTypeCharset))
+ {
+ $sCharset = $sContentTypeCharset;
+ }
+
+ if (0 < \strlen($sCharset))
+ {
+ $oHeaders->SetParentCharset($sCharset);
+ }
+
+ $aNewMessages[] = array(
+ 'Folder' => $sFolderName,
+ 'Uid' => $sUid,
+ 'Subject' => $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT, 0 === \strlen($sCharset)),
+ 'From' => $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::FROM_, 0 === \strlen($sCharset))
+ );
+ }
+ }
+ }
+ }
+
+ return $aNewMessages;
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param string $sPrevUidNext = ''
+ * @param array $aUids = ''
+ *
+ * @return string
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderInformation($sFolderName, $sPrevUidNext = '', $aUids = array())
+ {
+ $aFlags = array();
+
+ $bSelect = false;
+ if ($this->IsGmail() &&
+ ('INBOX' === $sFolderName || '[gmail]' === \strtolower(\substr($sFolderName, 0, 7))))
+ {
+ $this->oImapClient->FolderSelect($sFolderName);
+ $bSelect = true;
+ }
+
+ if (\is_array($aUids) && 0 < \count($aUids))
+ {
+ if (!$bSelect)
+ {
+ $this->oImapClient->FolderSelect($sFolderName);
+ }
+
+ $aFetchResponse = $this->oImapClient->Fetch(array(
+ \MailSo\Imap\Enumerations\FetchType::INDEX,
+ \MailSo\Imap\Enumerations\FetchType::UID,
+ \MailSo\Imap\Enumerations\FetchType::FLAGS
+ ), \MailSo\Base\Utils::PrepearFetchSequence($aUids), true);
+
+ if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse))
+ {
+ foreach ($aFetchResponse as $oFetchResponse)
+ {
+ $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID);
+ $aFlags[(\is_numeric($sUid) ? (int) $sUid : 0)] =
+ $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::FLAGS);
+ }
+ }
+ }
+
+ $iCount = 0;
+ $iUnseenCount = 0;
+ $sUidNext = '0';
+ $sHighestModSeq = '';
+
+ $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq);
+
+ $aResult = array(
+ 'Folder' => $sFolderName,
+ 'Hash' => $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq),
+ 'MessageCount' => $iCount,
+ 'MessageUnseenCount' => $iUnseenCount,
+ 'UidNext' => $sUidNext,
+ 'Flags' => $aFlags,
+ 'HighestModSeq' => $sHighestModSeq,
+ 'NewMessages' => 'INBOX' === $sFolderName ?
+ $this->getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sUidNext) : array()
+ );
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sFolderName
+ *
+ * @return string
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function FolderHash($sFolderName)
+ {
+ $iCount = 0;
+ $iUnseenCount = 0;
+ $sUidNext = '0';
+ $sHighestModSeq = '';
+
+ $this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq);
+
+ return $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext, $sHighestModSeq);
+ }
+
+ /**
+ * @return int
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function InboxUnreadCount()
+ {
+ $aFolderStatus = $this->oImapClient->FolderStatus('INBOX', array(
+ \MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN
+ ));
+
+ $iResult = isset($aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN]) ?
+ (int) $aFolderStatus[\MailSo\Imap\Enumerations\FolderResponseStatus::UNSEEN] : 0;
+
+ return 0 < $iResult ? $iResult : 0;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsGmail()
+ {
+ return 'ssl://imap.gmail.com' === \strtolower($this->oImapClient->GetConnectedHost());
+ }
+
+ /**
+ * @param string $sSearch
+ * @param bool $bDetectGmail = true
+ *
+ * @return string
+ */
+ private function escapeSearchString($sSearch, $bDetectGmail = true)
+ {
+ return !\MailSo\Base\Utils::IsAscii($sSearch)
+ ? '{'.\strlen($sSearch).'}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch);
+// return ($bDetectGmail && !\MailSo\Base\Utils::IsAscii($sSearch) && $this->IsGmail())
+// ? '{'.\strlen($sSearch).'+}'."\r\n".$sSearch : $this->oImapClient->EscapeString($sSearch);
+ }
+
+ /**
+ * @param string $sDate
+ * @param int $iTimeZoneOffset
+ *
+ * @return int
+ */
+ private function parseSearchDate($sDate, $iTimeZoneOffset)
+ {
+ $iResult = 0;
+ if (0 < \strlen($sDate))
+ {
+ $oDateTime = \DateTime::createFromFormat('Y.m.d', $sDate, \MailSo\Base\DateTimeHelper::GetUtcTimeZoneObject());
+ return $oDateTime ? $oDateTime->getTimestamp() - $iTimeZoneOffset : 0;
+ }
+
+ return $iResult;
+ }
+
+ /**
+ * @param string $sSize
+ *
+ * @return int
+ */
+ private function parseFriendlySize($sSize)
+ {
+ $sSize = preg_replace('/[^0-9bBkKmM]/', '', $sSize);
+
+ $iResult = 0;
+ $aMatch = array();
+
+ if (\preg_match('/([\d]+)(B|KB|M|MB|G|GB)$/i', $sSize, $aMatch) && isset($aMatch[1], $aMatch[2]))
+ {
+ $iResult = (int) $aMatch[1];
+ switch (\strtoupper($aMatch[2]))
+ {
+ case 'K':
+ case 'KB':
+ $iResult *= 1024;
+ case 'M':
+ case 'MB':
+ $iResult *= 1024;
+ case 'G':
+ case 'GB':
+ $iResult *= 1024;
+ }
+ }
+ else
+ {
+ $iResult = (int) $sSize;
+ }
+
+ return $iResult;
+ }
+
+ /**
+ * @param string $sSearch
+ *
+ * @return array
+ */
+ private function parseSearchString($sSearch)
+ {
+ $aResult = array(
+ 'OTHER' => ''
+ );
+
+ $aCache = array();
+
+ $sReg = 'e?mail|from|to|subject|has|is|date|text|body|size|larger|bigger|smaller|maxsize|minsize';
+
+ $sSearch = \MailSo\Base\Utils::StripSpaces($sSearch);
+ $sSearch = \trim(\preg_replace('/('.$sReg.'): /i', '\\1:', $sSearch));
+
+ $mMatch = array();
+ \preg_match_all('/".*?(? $sName)
+ {
+ if (isset($mMatch[2][$iIndex]) && 0 < \strlen($mMatch[2][$iIndex]))
+ {
+ $sName = \strtoupper($sName);
+ $sValue = $mMatch[2][$iIndex];
+ switch ($sName)
+ {
+ case 'TEXT':
+ case 'BODY':
+ case 'EMAIL':
+ case 'MAIL':
+ case 'FROM':
+ case 'TO':
+ case 'SUBJECT':
+ case 'IS':
+ case 'HAS':
+ case 'SIZE':
+ case 'SMALLER':
+ case 'LARGER':
+ case 'BIGGER':
+ case 'MAXSIZE':
+ case 'MINSIZE':
+ case 'DATE':
+ if ('MAIL' === $sName)
+ {
+ $sName = 'EMAIL';
+ }
+ if ('BODY' === $sName)
+ {
+ $sName = 'TEXT';
+ }
+ if ('SIZE' === $sName || 'BIGGER' === $sName || 'MINSIZE' === $sName)
+ {
+ $sName = 'LARGER';
+ }
+ if ('MAXSIZE' === $sName)
+ {
+ $sName = 'SMALLER';
+ }
+ $aResult[$sName] = $sValue;
+ break;
+ }
+ }
+ }
+ }
+
+ $aResult['OTHER'] = $sSearch;
+ foreach ($aResult as $sName => $sValue)
+ {
+ if (isset($aCache[$sValue]))
+ {
+ $aResult[$sName] = \trim($aCache[$sValue], '"\' ');
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sSearch
+ * @param string $sFilter
+ * @param int $iTimeZoneOffset = 0
+ * @param bool $bUseCache = true
+ *
+ * @return string
+ */
+ private function getImapSearchCriterias($sSearch, $sFilter, $iTimeZoneOffset = 0, &$bUseCache = true)
+ {
+ $bUseCache = true;
+ $iTimeFilter = 0;
+ $aCriteriasResult = array();
+
+ if (0 < \MailSo\Config::$MessageListDateFilter)
+ {
+ $iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter;
+ $iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD));
+ }
+
+ if (0 < \strlen(\trim($sSearch)))
+ {
+ $sGmailRawSearch = '';
+ $sResultBodyTextSearch = '';
+
+ $aLines = $this->parseSearchString($sSearch);
+ $bIsGmail = $this->oImapClient->IsSupported('X-GM-EXT-1');
+
+ if (1 === \count($aLines) && isset($aLines['OTHER']))
+ {
+ $sValue = $this->escapeSearchString($aLines['OTHER']);
+
+ if (\MailSo\Config::$MessageListFastSimpleSearch)
+ {
+ $aCriteriasResult[] = 'OR OR OR';
+ $aCriteriasResult[] = 'FROM';
+ $aCriteriasResult[] = $sValue;
+ $aCriteriasResult[] = 'TO';
+ $aCriteriasResult[] = $sValue;
+ $aCriteriasResult[] = 'CC';
+ $aCriteriasResult[] = $sValue;
+ $aCriteriasResult[] = 'SUBJECT';
+ $aCriteriasResult[] = $sValue;
+ }
+ else
+ {
+ $aCriteriasResult[] = 'TEXT';
+ $aCriteriasResult[] = $sValue;
+ }
+ }
+ else
+ {
+ if (isset($aLines['EMAIL']))
+ {
+ $sValue = $this->escapeSearchString($aLines['EMAIL']);
+
+ $aCriteriasResult[] = 'OR OR';
+ $aCriteriasResult[] = 'FROM';
+ $aCriteriasResult[] = $sValue;
+ $aCriteriasResult[] = 'TO';
+ $aCriteriasResult[] = $sValue;
+ $aCriteriasResult[] = 'CC';
+ $aCriteriasResult[] = $sValue;
+
+ unset($aLines['EMAIL']);
+ }
+
+ if (isset($aLines['TO']))
+ {
+ $sValue = $this->escapeSearchString($aLines['TO']);
+
+ $aCriteriasResult[] = 'OR';
+ $aCriteriasResult[] = 'TO';
+ $aCriteriasResult[] = $sValue;
+ $aCriteriasResult[] = 'CC';
+ $aCriteriasResult[] = $sValue;
+
+ unset($aLines['TO']);
+ }
+
+ $sMainText = '';
+ foreach ($aLines as $sName => $sRawValue)
+ {
+ if ('' === \trim($sRawValue))
+ {
+ continue;
+ }
+
+ $sValue = $this->escapeSearchString($sRawValue);
+ switch ($sName)
+ {
+ case 'FROM':
+ $aCriteriasResult[] = 'FROM';
+ $aCriteriasResult[] = $sValue;
+ break;
+ case 'SUBJECT':
+ $aCriteriasResult[] = 'SUBJECT';
+ $aCriteriasResult[] = $sValue;
+ break;
+ case 'OTHER':
+ case 'TEXT':
+ $sMainText .= ' '.$sRawValue;
+ break;
+ case 'HAS':
+ $aValue = \explode(',', \strtolower($sRawValue));
+ $aValue = \array_map('trim', $aValue);
+
+ $aCompareArray = array('file', 'files', 'attach', 'attachs', 'attachment', 'attachments');
+ if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue)))
+ {
+ if ($bIsGmail)
+ {
+ $sGmailRawSearch .= ' has:attachment';
+ }
+ else
+ {
+ // Simple, is not detailed search (Sometimes doesn't work)
+ $aCriteriasResult[] = 'OR OR OR';
+ $aCriteriasResult[] = 'HEADER Content-Type application/';
+ $aCriteriasResult[] = 'HEADER Content-Type multipart/m';
+ $aCriteriasResult[] = 'HEADER Content-Type multipart/signed';
+ $aCriteriasResult[] = 'HEADER Content-Type multipart/report';
+ }
+ }
+
+ case 'IS':
+ $aValue = \explode(',', \strtolower($sRawValue));
+ $aValue = \array_map('trim', $aValue);
+
+ $aCompareArray = array('flag', 'flagged', 'star', 'starred', 'pinned');
+ $aCompareArray2 = array('unflag', 'unflagged', 'unstar', 'unstarred', 'unpinned');
+ if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue)))
+ {
+ $aCriteriasResult[] = 'FLAGGED';
+ $bUseCache = false;
+ }
+ else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue)))
+ {
+ $aCriteriasResult[] = 'UNFLAGGED';
+ $bUseCache = false;
+ }
+
+ $aCompareArray = array('unread', 'unseen');
+ $aCompareArray2 = array('read', 'seen');
+ if (\count($aCompareArray) > \count(\array_diff($aCompareArray, $aValue)))
+ {
+ $aCriteriasResult[] = 'UNSEEN';
+ $bUseCache = false;
+ }
+ else if (\count($aCompareArray2) > \count(\array_diff($aCompareArray2, $aValue)))
+ {
+ $aCriteriasResult[] = 'SEEN';
+ $bUseCache = false;
+ }
+ break;
+
+ case 'LARGER':
+ $aCriteriasResult[] = 'LARGER';
+ $aCriteriasResult[] = $this->parseFriendlySize($sRawValue);
+ break;
+ case 'SMALLER':
+ $aCriteriasResult[] = 'SMALLER';
+ $aCriteriasResult[] = $this->parseFriendlySize($sRawValue);
+ break;
+ case 'DATE':
+ $iDateStampFrom = $iDateStampTo = 0;
+
+ $sDate = $sRawValue;
+ $aDate = \explode('/', $sDate);
+
+ if (\is_array($aDate) && 2 === \count($aDate))
+ {
+ if (0 < \strlen($aDate[0]))
+ {
+ $iDateStampFrom = $this->parseSearchDate($aDate[0], $iTimeZoneOffset);
+ }
+
+ if (0 < \strlen($aDate[1]))
+ {
+ $iDateStampTo = $this->parseSearchDate($aDate[1], $iTimeZoneOffset);
+ $iDateStampTo += 60 * 60 * 24;
+ }
+ }
+ else
+ {
+ if (0 < \strlen($sDate))
+ {
+ $iDateStampFrom = $this->parseSearchDate($sDate, $iTimeZoneOffset);
+ $iDateStampTo = $iDateStampFrom + 60 * 60 * 24;
+ }
+ }
+
+ if (0 < $iDateStampFrom)
+ {
+ $aCriteriasResult[] = 'SINCE';
+ $aCriteriasResult[] = \gmdate('j-M-Y', $iTimeFilter > $iDateStampFrom ?
+ $iTimeFilter : $iDateStampFrom);
+
+ $iTimeFilter = 0;
+ }
+
+ if (0 < $iDateStampTo)
+ {
+ $aCriteriasResult[] = 'BEFORE';
+ $aCriteriasResult[] = \gmdate('j-M-Y', $iDateStampTo);
+ }
+ break;
+ }
+ }
+
+ if ('' !== \trim($sMainText))
+ {
+ $sMainText = \trim(\MailSo\Base\Utils::StripSpaces($sMainText), '"');
+ if ($bIsGmail)
+ {
+ $sGmailRawSearch .= ' '.$sMainText;
+ }
+ else
+ {
+ $sResultBodyTextSearch .= ' '.$sMainText;
+ }
+ }
+ }
+
+ $sGmailRawSearch = \trim($sGmailRawSearch);
+ if ($bIsGmail && 0 < \strlen($sGmailRawSearch))
+ {
+ $aCriteriasResult[] = 'X-GM-RAW';
+ $aCriteriasResult[] = $this->escapeSearchString($sGmailRawSearch, false);
+ }
+
+ $sResultBodyTextSearch = \trim($sResultBodyTextSearch);
+ if (0 < \strlen($sResultBodyTextSearch))
+ {
+ $aCriteriasResult[] = 'BODY';
+ $aCriteriasResult[] = $this->escapeSearchString($sResultBodyTextSearch);
+ }
+ }
+
+ $sCriteriasResult = \trim(\implode(' ', $aCriteriasResult));
+
+ if (0 < $iTimeFilter)
+ {
+ $sCriteriasResult .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter);
+ }
+
+ $sCriteriasResult = \trim($sCriteriasResult);
+ if (\MailSo\Config::$MessageListUndeletedOnly)
+ {
+ $sCriteriasResult = \trim($sCriteriasResult.' UNDELETED');
+ }
+
+ $sFilter = \trim($sFilter);
+ if ('' !== $sFilter)
+ {
+ $sCriteriasResult .= ' '.$sFilter;
+ }
+
+ $sCriteriasResult = \trim($sCriteriasResult);
+ if ('' !== \MailSo\Config::$MessageListPermanentFilter)
+ {
+ $sCriteriasResult = \trim($sCriteriasResult.' '.\MailSo\Config::$MessageListPermanentFilter);
+ }
+
+ $sCriteriasResult = \trim($sCriteriasResult);
+ if ('' === $sCriteriasResult)
+ {
+ $sCriteriasResult = 'ALL';
+ }
+
+ return $sCriteriasResult;
+ }
+
+ /**
+ * @param array $aThreads
+ * @return array
+ */
+ private function threadArrayMap($aThreads)
+ {
+ $aNew = array();
+ foreach ($aThreads as $mItem)
+ {
+ if (!\is_array($mItem))
+ {
+ $aNew[] = $mItem;
+ }
+ else
+ {
+ $mMap = $this->threadArrayMap($mItem);
+ if (\is_array($mMap) && 0 < \count($mMap))
+ {
+ $aNew = \array_merge($aNew, $mMap);
+ }
+ }
+ }
+
+ return $aNew;
+ }
+
+ /**
+ * @param array $aThreads
+ *
+ * @return array
+ */
+ private function compileThreadArray($aThreads)
+ {
+ $aResult = array();
+ foreach ($aThreads as $mItem)
+ {
+ if (\is_array($mItem))
+ {
+ $aMap = $this->threadArrayMap($mItem);
+ if (\is_array($aMap))
+ {
+ if (1 < \count($aMap))
+ {
+ $aResult[] = $aMap;
+ }
+ else if (0 < \count($aMap))
+ {
+ $aResult[] = $aMap[0];
+ }
+ }
+ }
+ else
+ {
+ $aResult[] = $mItem;
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param string $sFolderHash
+ * @param array $aIndexOrUids
+ * @param \MailSo\Cache\CacheClient $oCacher
+ * @param bool $bCacheOnly = false
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageListThreadsMap($sFolderName, $sFolderHash, $aIndexOrUids, $oCacher, $bCacheOnly = false)
+ {
+ $iThreadLimit = \MailSo\Config::$LargeThreadLimit;
+
+ $sSearchHash = '';
+ if (0 < \MailSo\Config::$MessageListDateFilter)
+ {
+ $iD = \time() - 3600 * 24 * 30 * \MailSo\Config::$MessageListDateFilter;
+ $iTimeFilter = \gmmktime(1, 1, 1, \gmdate('n', $iD), 1, \gmdate('Y', $iD));
+
+ $sSearchHash .= ' SINCE '.\gmdate('j-M-Y', $iTimeFilter);
+ }
+
+ if ('' === \trim($sSearchHash))
+ {
+ $sSearchHash = 'ALL';
+ }
+
+ if ($oCacher && $oCacher->IsInited())
+ {
+ $sSerializedHashKey =
+ 'ThreadsMapSorted/'.$sSearchHash.'/'.
+ 'Limit='.$iThreadLimit.'/'.$sFolderName.'/'.$sFolderHash;
+
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write($sSerializedHashKey);
+ }
+
+ $sSerializedUids = $oCacher->Get($sSerializedHashKey);
+ if (!empty($sSerializedUids))
+ {
+ $aSerializedUids = @\json_decode($sSerializedUids, true);
+ if (isset($aSerializedUids['ThreadsUids']) && \is_array($aSerializedUids['ThreadsUids']))
+ {
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('Get Serialized Thread UIDS from cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aSerializedUids['ThreadsUids']).']');
+ }
+
+ return $aSerializedUids['ThreadsUids'];
+ }
+ }
+ }
+
+ if ($bCacheOnly)
+ {
+ return null;
+ }
+
+ $this->oImapClient->FolderExamine($sFolderName);
+
+ $aThreadUids = array();
+ try
+ {
+ $aThreadUids = $this->oImapClient->MessageSimpleThread($sSearchHash);
+ }
+ catch (\MailSo\Imap\Exceptions\RuntimeException $oException)
+ {
+ unset($oException);
+ $aThreadUids = array();
+ }
+
+ $aResult = array();
+ $aCompiledThreads = $this->compileThreadArray($aThreadUids);
+
+ foreach ($aCompiledThreads as $mData)
+ {
+ if (\is_array($mData))
+ {
+ foreach ($mData as $mSubData)
+ {
+ $aResult[(int) $mSubData] =
+ \array_diff($mData, array((int) $mSubData));
+ }
+ }
+ else if (\is_int($mData) || \is_string($mData))
+ {
+ $aResult[(int) $mData] = (int) $mData;
+ }
+ }
+
+ $aParentsMap = array();
+ foreach ($aIndexOrUids as $iUid)
+ {
+ if (isset($aResult[$iUid]) && \is_array($aResult[$iUid]))
+ {
+ foreach ($aResult[$iUid] as $iTempUid)
+ {
+ $aParentsMap[$iTempUid] = $iUid;
+ if (isset($aResult[$iTempUid]))
+ {
+ unset($aResult[$iTempUid]);
+ }
+ }
+ }
+ }
+
+ $aSortedThreads = array();
+ foreach ($aIndexOrUids as $iUid)
+ {
+ if (isset($aResult[$iUid]))
+ {
+ $aSortedThreads[$iUid] = $iUid;
+ }
+ }
+
+ foreach ($aIndexOrUids as $iUid)
+ {
+ if (!isset($aSortedThreads[$iUid]) &&
+ isset($aParentsMap[$iUid]) &&
+ isset($aSortedThreads[$aParentsMap[$iUid]]))
+ {
+ if (!\is_array($aSortedThreads[$aParentsMap[$iUid]]))
+ {
+ $aSortedThreads[$aParentsMap[$iUid]] = array();
+ }
+
+ $aSortedThreads[$aParentsMap[$iUid]][] = $iUid;
+ }
+ }
+
+ $aResult = $aSortedThreads;
+ unset($aParentsMap, $aSortedThreads);
+
+ $aTemp = array();
+ foreach ($aResult as $iUid => $mValue)
+ {
+ if (0 < $iThreadLimit && \is_array($mValue) && $iThreadLimit < \count($mValue))
+ {
+ $aParts = \array_chunk($mValue, $iThreadLimit);
+ if (0 < count($aParts))
+ {
+ foreach ($aParts as $iIndex => $aItem)
+ {
+ if (0 === $iIndex)
+ {
+ $aResult[$iUid] = $aItem;
+ }
+ else if (0 < $iIndex && \is_array($aItem))
+ {
+ $mFirst = \array_shift($aItem);
+ if (!empty($mFirst))
+ {
+ $aTemp[$mFirst] = 0 < \count($aItem) ? $aItem : $mFirst;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ foreach ($aTemp as $iUid => $mValue)
+ {
+ $aResult[$iUid] = $mValue;
+ }
+
+ unset($aTemp);
+
+ $aLastResult = array();
+ foreach ($aIndexOrUids as $iUid)
+ {
+ if (isset($aResult[$iUid]))
+ {
+ $aLastResult[$iUid] = $aResult[$iUid];
+ }
+ }
+
+ $aResult = $aLastResult;
+ unset($aLastResult);
+
+ if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHashKey))
+ {
+ $oCacher->Set($sSerializedHashKey, @\json_encode(array(
+ 'ThreadsUids' => $aResult
+ )));
+
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('Save Serialized Thread UIDS to cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aResult).']');
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param \MailSo\Mail\MessageCollection &$oMessageCollection
+ * @param array $aRequestIndexOrUids
+ * @param bool $bIndexAsUid
+ * @param bool $bSimple = false
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageListByRequestIndexOrUids(&$oMessageCollection, $aRequestIndexOrUids, $bIndexAsUid, $bSimple = false)
+ {
+ if (\is_array($aRequestIndexOrUids) && 0 < \count($aRequestIndexOrUids))
+ {
+ $aFetchResponse = $this->oImapClient->Fetch(array(
+ \MailSo\Imap\Enumerations\FetchType::INDEX,
+ \MailSo\Imap\Enumerations\FetchType::UID,
+ \MailSo\Imap\Enumerations\FetchType::RFC822_SIZE,
+ \MailSo\Imap\Enumerations\FetchType::INTERNALDATE,
+ \MailSo\Imap\Enumerations\FetchType::FLAGS,
+ \MailSo\Imap\Enumerations\FetchType::BODYSTRUCTURE,
+ $bSimple ?
+ $this->getEnvelopeOrHeadersRequestStringForSimpleList() :
+ $this->getEnvelopeOrHeadersRequestString()
+ ), \MailSo\Base\Utils::PrepearFetchSequence($aRequestIndexOrUids), $bIndexAsUid);
+
+ if (\is_array($aFetchResponse) && 0 < \count($aFetchResponse))
+ {
+ $aFetchIndexArray = array();
+ $oFetchResponseItem = null;
+ foreach ($aFetchResponse as /* @var $oFetchResponseItem \MailSo\Imap\FetchResponse */ &$oFetchResponseItem)
+ {
+ $aFetchIndexArray[($bIndexAsUid)
+ ? $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID)
+ : $oFetchResponseItem->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::INDEX)] =& $oFetchResponseItem;
+
+ unset($oFetchResponseItem);
+ }
+
+ foreach ($aRequestIndexOrUids as $iFUid)
+ {
+ if (isset($aFetchIndexArray[$iFUid]))
+ {
+ $oMessageCollection->Add(
+ Message::NewFetchResponseInstance(
+ $oMessageCollection->FolderName, $aFetchIndexArray[$iFUid]));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @return bool
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ public function IsThreadsSupported()
+ {
+ return $this->oImapClient->IsSupported('THREAD=REFS') ||
+ $this->oImapClient->IsSupported('THREAD=REFERENCES') ||
+ $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT');
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param array $aUids
+ *
+ * @return \MailSo\Mail\MessageCollection
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageListSimple($sFolderName, $aUids)
+ {
+ if (0 === \strlen($sFolderName) || !\MailSo\Base\Validator::NotEmptyArray($aUids))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderExamine($sFolderName);
+
+ $oMessageCollection = \MailSo\Mail\MessageCollection::NewInstance();
+ $oMessageCollection->FolderName = $sFolderName;
+
+ $this->MessageListByRequestIndexOrUids($oMessageCollection, $aUids, true, true);
+
+ return $oMessageCollection->GetAsArray();
+ }
+
+ /**
+ * @param \MailSo\Cache\CacheClient|null $oCacher
+ * @param string $sSearch
+ * @param string $sFilter
+ * @param string $sFolderName
+ * @param string $sFolderHash
+ * @param bool $bUseSortIfSupported = false
+ *
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function GetUids($oCacher, $sSearch, $sFilter, $sFolderName, $sFolderHash, $bUseSortIfSupported = false)
+ {
+ $aResultUids = false;
+ $bUidsFromCacher = false;
+ $bUseCacheAfterSearch = true;
+
+ $sSerializedHash = '';
+ $sSerializedLog = '';
+
+ $bUseSortIfSupported = $bUseSortIfSupported ? !!$this->oImapClient->IsSupported('SORT') : false;
+
+ if (0 < \strlen($sSearch))
+ {
+ $bUseSortIfSupported = false;
+ }
+
+ $sSearchCriterias = $this->getImapSearchCriterias($sSearch, $sFilter, 0, $bUseCacheAfterSearch);
+ if ($bUseCacheAfterSearch && $oCacher && $oCacher->IsInited())
+ {
+ $sSerializedHash = 'GetUids/'.
+ ($bUseSortIfSupported ? 'S': 'N').'/'.
+ $this->GenerateImapClientHash().'/'.
+ $sFolderName.'/'.$sSearchCriterias;
+
+ $sSerializedLog = '"'.$sFolderName.'" / '.$sSearchCriterias.'';
+
+ $sSerialized = $oCacher->Get($sSerializedHash);
+ if (!empty($sSerialized))
+ {
+ $aSerialized = @\json_decode($sSerialized, true);
+ if (\is_array($aSerialized) && isset($aSerialized['FolderHash'], $aSerialized['Uids']) &&
+ $sFolderHash === $aSerialized['FolderHash'] &&
+ \is_array($aSerialized['Uids'])
+ )
+ {
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('Get Serialized UIDS from cache ('.$sSerializedLog.') [count:'.\count($aSerialized['Uids']).']');
+ }
+
+ $aResultUids = $aSerialized['Uids'];
+ $bUidsFromCacher = true;
+ }
+ }
+ }
+
+ if (!\is_array($aResultUids))
+ {
+ $aResultUids = $bUseSortIfSupported ?
+ $this->oImapClient->MessageSimpleSort(array('REVERSE ARRIVAL'), $sSearchCriterias, true) :
+ $this->oImapClient->MessageSimpleSearch($sSearchCriterias, true, \MailSo\Base\Utils::IsAscii($sSearchCriterias) ? '' : 'UTF-8')
+ ;
+
+ if (!$bUidsFromCacher && $bUseCacheAfterSearch && \is_array($aResultUids) && $oCacher && $oCacher->IsInited() && 0 < \strlen($sSerializedHash))
+ {
+ $oCacher->Set($sSerializedHash, @\json_encode(array(
+ 'FolderHash' => $sFolderHash,
+ 'Uids' => $aResultUids
+ )));
+
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('Save Serialized UIDS to cache ('.$sSerializedLog.') [count:'.\count($aResultUids).']');
+ }
+ }
+ }
+
+ return \is_array($aResultUids) ? $aResultUids : array();
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param int $iOffset = 0
+ * @param int $iLimit = 10
+ * @param string $sSearch = ''
+ * @param string $sPrevUidNext = ''
+ * @param \MailSo\Cache\CacheClient|null $oCacher = null
+ * @param bool $bUseSortIfSupported = false
+ * @param bool $bUseThreadSortIfSupported = false
+ * @param bool $bUseESearchOrESortRequest = false
+ * @param string $sThreadUid = ''
+ * @param string $sFilter = ''
+ *
+ * @return \MailSo\Mail\MessageCollection
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Imap\Exceptions\Exception
+ */
+ public function MessageList($sFolderName, $iOffset = 0, $iLimit = 10, $sSearch = '', $sPrevUidNext = '', $oCacher = null,
+ $bUseSortIfSupported = false, $bUseThreadSortIfSupported = false, $sThreadUid = '', $sFilter = '')
+ {
+ $sFilter = \trim($sFilter);
+ $sSearch = \trim($sSearch);
+ if (!\MailSo\Base\Validator::RangeInt($iOffset, 0) ||
+ !\MailSo\Base\Validator::RangeInt($iLimit, 0, 999))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $bUseFilter = '' !== $sFilter;
+
+ $this->oImapClient->FolderSelect($sFolderName);
+
+ $oMessageCollection = MessageCollection::NewInstance();
+ $oMessageCollection->FolderName = $sFolderName;
+ $oMessageCollection->Offset = $iOffset;
+ $oMessageCollection->Limit = $iLimit;
+ $oMessageCollection->Search = $sSearch;
+ $oMessageCollection->ThreadUid = $sThreadUid;
+ $oMessageCollection->Filtered = '' !== \MailSo\Config::$MessageListPermanentFilter;
+
+ $aUids = array();
+ $mAllSortedUids = null;
+ $mAllThreads = null;
+
+ $iThreadUid = empty($sThreadUid) ? 0 : (int) $sThreadUid;
+
+ $iMessageRealCount = 0;
+ $iMessageUnseenCount = 0;
+ $sUidNext = '0';
+ $sHighestModSeq = '';
+
+ $bUseSortIfSupported = $bUseSortIfSupported ? $this->oImapClient->IsSupported('SORT') : false;
+
+ $bUseThreadSortIfSupported = $bUseThreadSortIfSupported ?
+ ($this->oImapClient->IsSupported('THREAD=REFS') || $this->oImapClient->IsSupported('THREAD=REFERENCES') || $this->oImapClient->IsSupported('THREAD=ORDEREDSUBJECT')) : false;
+
+ if (!empty($sThreadUid) && !$bUseThreadSortIfSupported)
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ if (!$oCacher || !($oCacher instanceof \MailSo\Cache\CacheClient))
+ {
+ $oCacher = null;
+ }
+
+ $this->initFolderValues($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext, $sHighestModSeq);
+
+ if ($bUseFilter)
+ {
+ $iMessageUnseenCount = 0;
+ }
+
+ $oMessageCollection->FolderHash = $this->GenerateFolderHash(
+ $sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext, $sHighestModSeq);
+
+ $oMessageCollection->UidNext = $sUidNext;
+
+ if (empty($sThreadUid) && 0 < \strlen($sPrevUidNext) && 'INBOX' === $sFolderName)
+ {
+ $oMessageCollection->NewMessages = $this->getFolderNextMessageInformation(
+ $sFolderName, $sPrevUidNext, $sUidNext);
+ }
+
+ $bSearch = false;
+ $bMessageListOptimization = 0 < \MailSo\Config::$MessageListCountLimitTrigger &&
+ \MailSo\Config::$MessageListCountLimitTrigger < $iMessageRealCount;
+
+ if ($bMessageListOptimization)
+ {
+ $bUseSortIfSupported = false;
+ $bUseThreadSortIfSupported = false;
+ }
+
+ if (0 < $iMessageRealCount && !$bMessageListOptimization)
+ {
+ $mAllSortedUids = $this->GetUids($oCacher, '', $sFilter,
+ $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $bUseSortIfSupported);
+
+ $mAllThreads = $bUseThreadSortIfSupported ? $this->MessageListThreadsMap(
+ $oMessageCollection->FolderName, $oMessageCollection->FolderHash, $mAllSortedUids, $oCacher) : null;
+
+ if ($bUseThreadSortIfSupported && 0 < $iThreadUid && \is_array($mAllThreads))
+ {
+ $aUids = array();
+ $iResultRootUid = 0;
+
+ if (isset($mAllThreads[$iThreadUid]))
+ {
+ $iResultRootUid = $iThreadUid;
+ if (\is_array($mAllThreads[$iThreadUid]))
+ {
+ $aUids = $mAllThreads[$iThreadUid];
+ }
+ }
+ else
+ {
+ foreach ($mAllThreads as $iRootUid => $mSubUids)
+ {
+ if (\is_array($mSubUids) && \in_array($iThreadUid, $mSubUids))
+ {
+ $iResultRootUid = $iRootUid;
+ $aUids = $mSubUids;
+ continue;
+ }
+ }
+ }
+
+ if (0 < $iResultRootUid && \in_array($iResultRootUid, $mAllSortedUids))
+ {
+ \array_unshift($aUids, $iResultRootUid);
+ }
+ }
+ else if ($bUseThreadSortIfSupported && \is_array($mAllThreads))
+ {
+ $aUids = \array_keys($mAllThreads);
+ }
+ else
+ {
+ $bUseThreadSortIfSupported = false;
+ $aUids = $mAllSortedUids;
+ }
+
+ if (0 < \strlen($sSearch) && \is_array($aUids))
+ {
+ $aSearchedUids = $this->GetUids($oCacher, $sSearch, $sFilter,
+ $oMessageCollection->FolderName, $oMessageCollection->FolderHash);
+
+ if (\is_array($aSearchedUids) && 0 < \count($aSearchedUids))
+ {
+ $aFlippedSearchedUids = \array_flip($aSearchedUids);
+
+ $bSearch = true;
+ $aNewUids = array();
+
+ foreach ($aUids as $iUid)
+ {
+ if (isset($aFlippedSearchedUids[$iUid]))
+ {
+ $aNewUids[] = $iUid;
+ }
+ else if ($bUseThreadSortIfSupported && 0 === $iThreadUid && isset($mAllThreads[$iUid]) && \is_array($mAllThreads[$iUid]))
+ {
+ foreach ($mAllThreads[$iUid] as $iSubUid)
+ {
+ if (isset($aFlippedSearchedUids[$iSubUid]))
+ {
+ $aNewUids[] = $iUid;
+ continue;
+ }
+ }
+ }
+ }
+
+ $aUids = \array_unique($aNewUids);
+ unset($aNewUids);
+ }
+ else
+ {
+ $aUids = array();
+ }
+ }
+
+ if (\is_array($aUids))
+ {
+ $oMessageCollection->MessageCount = $iMessageRealCount;
+ $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount;
+ $oMessageCollection->MessageResultCount = \count($aUids);
+
+ if (0 < \count($aUids))
+ {
+ $aRequestUids = \array_slice($aUids, $iOffset, $iLimit);
+ $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestUids, true);
+ }
+ }
+ }
+ else if (0 < $iMessageRealCount)
+ {
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('List optimization (count: '.$iMessageRealCount.
+ ', limit:'.\MailSo\Config::$MessageListCountLimitTrigger.')');
+ }
+
+ $oMessageCollection->MessageCount = $iMessageRealCount;
+ $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount;
+
+ if (0 < \strlen($sSearch) || $bUseFilter)
+ {
+ $aUids = $this->GetUids($oCacher, $sSearch, $sFilter,
+ $oMessageCollection->FolderName, $oMessageCollection->FolderHash);
+
+ if (0 < \count($aUids))
+ {
+ $oMessageCollection->MessageResultCount = \count($aUids);
+
+ $aRequestUids = \array_slice($aUids, $iOffset, $iLimit);
+ $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestUids, true);
+ }
+ else
+ {
+ $oMessageCollection->MessageResultCount = 0;
+ }
+ }
+ else
+ {
+ $oMessageCollection->MessageResultCount = $iMessageRealCount;
+
+ if (1 < $iMessageRealCount)
+ {
+ $aRequestIndexes = \array_slice(array_reverse(range(1, $iMessageRealCount)), $iOffset, $iLimit);
+ }
+ else
+ {
+ $aRequestIndexes = \array_slice(array(1), $iOffset, $iLimit);
+ }
+
+ $this->MessageListByRequestIndexOrUids($oMessageCollection, $aRequestIndexes, false);
+ }
+ }
+
+ if ($bUseThreadSortIfSupported && 0 === $iThreadUid && \is_array($mAllThreads) && 0 < \count($mAllThreads))
+ {
+ $oMessageCollection->ForeachList(function (/* @var $oMessage \MailSo\Mail\Message */ $oMessage) use ($mAllThreads) {
+
+ $iUid = $oMessage->Uid();
+ if (isset($mAllThreads[$iUid]) && \is_array($mAllThreads[$iUid]) && 0 < \count($mAllThreads[$iUid]))
+ {
+ $aSubThreads = $mAllThreads[$iUid];
+ \array_unshift($aSubThreads, $iUid);
+
+ $oMessage->SetThreads(\array_map('trim', $aSubThreads));
+ unset($aSubThreads);
+ }
+ });
+ }
+
+ return $oMessageCollection;
+ }
+
+ /**
+ * @return array|false
+ */
+ public function Quota()
+ {
+ return $this->oImapClient->Quota();
+ }
+
+ /**
+ * @param string $sFolderName
+ * @param string $sMessageId
+ *
+ * @return int|null
+ */
+ public function FindMessageUidByMessageId($sFolderName, $sMessageId)
+ {
+ if (0 === \strlen($sMessageId))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderExamine($sFolderName);
+
+ $aUids = $this->oImapClient->MessageSimpleSearch(
+ 'HEADER Message-ID '.$sMessageId, true);
+
+ return \is_array($aUids) && 1 === \count($aUids) && \is_numeric($aUids[0]) ? (int) $aUids[0] : null;
+ }
+
+ /**
+ * @param array $aMailFoldersHelper
+ * @param int $iOptimizationLimit = 0
+ *
+ * @return array
+ */
+ public function folderListOptimization($aMailFoldersHelper, $iOptimizationLimit = 0)
+ {
+ // optimization
+ if (10 < $iOptimizationLimit && \is_array($aMailFoldersHelper) && $iOptimizationLimit < \count($aMailFoldersHelper))
+ {
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('Start optimization (limit:'.$iOptimizationLimit.') for '.\count($aMailFoldersHelper).' folders');
+ }
+
+ $iForeachLimit = 1;
+
+ $aFilteredNames = array(
+ 'inbox',
+ 'sent', 'outbox', 'sentmail',
+ 'drafts',
+ 'junk', 'spam',
+ 'trash', 'bin',
+ 'archives', 'archive', 'allmail', 'all',
+ 'starred', 'flagged', 'important',
+ 'contacts', 'chats'
+ );
+
+ $aNewMailFoldersHelper = array();
+
+ $iCountLimit = $iForeachLimit;
+
+ foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder)
+ {
+ // mandatory folders
+ if ($oFolder && \in_array(\strtolower($oFolder->NameRaw()), $aFilteredNames))
+ {
+ $aNewMailFoldersHelper[] = $oFolder;
+ $aMailFoldersHelper[$iIndex] = null;
+ }
+ }
+
+ foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder)
+ {
+ // subscribed folders
+ if ($oFolder && $oFolder->IsSubscribed())
+ {
+ $aNewMailFoldersHelper[] = $oFolder;
+
+ $aMailFoldersHelper[$iIndex] = null;
+ $iCountLimit--;
+ }
+
+ if (0 > $iCountLimit)
+ {
+ if ($iOptimizationLimit < \count($aNewMailFoldersHelper))
+ {
+ break;
+ }
+ else
+ {
+ $iCountLimit = $iForeachLimit;
+ }
+ }
+ }
+
+ $iCountLimit = $iForeachLimit;
+ if ($iOptimizationLimit >= \count($aNewMailFoldersHelper))
+ {
+ // name filter
+ foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder)
+ {
+ if ($oFolder && !\preg_match('/[{}\[\]]/', $oFolder->NameRaw()))
+ {
+ $aNewMailFoldersHelper[] = $oFolder;
+
+ $aMailFoldersHelper[$iIndex] = null;
+ $iCountLimit--;
+ }
+
+ if (0 > $iCountLimit)
+ {
+ if ($iOptimizationLimit < \count($aNewMailFoldersHelper))
+ {
+ break;
+ }
+ else
+ {
+ $iCountLimit = $iForeachLimit;
+ }
+ }
+ }
+ }
+
+ $iCountLimit = $iForeachLimit;
+ if ($iOptimizationLimit >= \count($aNewMailFoldersHelper))
+ {
+ // other
+ foreach ($aMailFoldersHelper as $iIndex => /* @var $oImapFolder \MailSo\Mail\Folder */ $oFolder)
+ {
+ if ($oFolder)
+ {
+ $aNewMailFoldersHelper[] = $oFolder;
+
+ $aMailFoldersHelper[$iIndex] = null;
+ $iCountLimit--;
+ }
+
+ if (0 > $iCountLimit)
+ {
+ if ($iOptimizationLimit < \count($aNewMailFoldersHelper))
+ {
+ break;
+ }
+ else
+ {
+ $iCountLimit = $iForeachLimit;
+ }
+ }
+ }
+ }
+
+ $aMailFoldersHelper = $aNewMailFoldersHelper;
+
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write('Result optimization: '.\count($aMailFoldersHelper).' folders');
+ }
+ }
+
+ return $aMailFoldersHelper;
+ }
+
+ /**
+ * @param string $sParent = ''
+ * @param string $sListPattern = '*'
+ * @param bool $bUseListSubscribeStatus = false
+ * @param int $iOptimizationLimit = 0
+ *
+ * @return \MailSo\Mail\FolderCollection|false
+ */
+ public function Folders($sParent = '', $sListPattern = '*', $bUseListSubscribeStatus = true, $iOptimizationLimit = 0)
+ {
+ $oFolderCollection = false;
+
+ $aSubscribedFolders = null;
+ if ($bUseListSubscribeStatus)
+ {
+ try
+ {
+ $aSubscribedFolders = $this->oImapClient->FolderSubscribeList($sParent, $sListPattern);
+ }
+ catch (\Exception $oException)
+ {
+ unset($oException);
+ }
+ }
+
+ $aImapSubscribedFoldersHelper = null;
+ if (\is_array($aSubscribedFolders))
+ {
+ $aImapSubscribedFoldersHelper = array();
+ foreach ($aSubscribedFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder)
+ {
+ $aImapSubscribedFoldersHelper[] = $oImapFolder->FullNameRaw();
+ }
+ }
+
+ $aFolders = $this->oImapClient->FolderList($sParent, $sListPattern);
+
+ $bOptimized = false;
+ $aMailFoldersHelper = null;
+
+ if (\is_array($aFolders))
+ {
+ $aMailFoldersHelper = array();
+
+ foreach ($aFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder)
+ {
+ $aMailFoldersHelper[] = Folder::NewInstance($oImapFolder,
+ (null === $aImapSubscribedFoldersHelper || \in_array($oImapFolder->FullNameRaw(), $aImapSubscribedFoldersHelper)) ||
+ $oImapFolder->IsInbox()
+ );
+ }
+
+ $iCount = \count($aMailFoldersHelper);
+ $aMailFoldersHelper = $this->folderListOptimization($aMailFoldersHelper, $iOptimizationLimit);
+
+ $bOptimized = $iCount !== \count($aMailFoldersHelper);
+ }
+
+ if (\is_array($aMailFoldersHelper))
+ {
+ $oFolderCollection = FolderCollection::NewInstance();
+ $oFolderCollection->InitByUnsortedMailFolderArray($aMailFoldersHelper);
+
+ $oFolderCollection->Optimized = $bOptimized;
+ }
+
+ if ($oFolderCollection)
+ {
+ $oFolderCollection->SortByCallback(function ($oFolderA, $oFolderB) {
+ $sA = \strtoupper($oFolderA->FullNameRaw());
+ $sB = \strtoupper($oFolderB->FullNameRaw());
+ switch (true)
+ {
+ case 'INBOX' === $sA:
+ return -1;
+ case 'INBOX' === $sB:
+ return 1;
+ case '[GMAIL]' === $sA:
+ return -1;
+ case '[GMAIL]' === $sB:
+ return 1;
+ }
+
+ return \strnatcasecmp($oFolderA->FullName(), $oFolderB->FullName());
+ });
+
+ $oNamespace = $this->oImapClient->GetNamespace();
+ if ($oNamespace)
+ {
+ $oFolderCollection->SetNamespace($oNamespace->GetPersonalNamespace());
+ }
+
+ $oFolderCollection->IsThreadsSupported = $this->IsThreadsSupported();
+ }
+
+ return $oFolderCollection;
+ }
+
+ /**
+ * @param string $sFolderNameInUtf8
+ * @param string $sFolderParentFullNameRaw = ''
+ * @param bool $bSubscribeOnCreation = true
+ * @param string $sDelimiter = ''
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function FolderCreate($sFolderNameInUtf8, $sFolderParentFullNameRaw = '', $bSubscribeOnCreation = true, $sDelimiter = '')
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sFolderNameInUtf8, true) ||
+ !\is_string($sFolderParentFullNameRaw))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $sFolderNameInUtf8 = \trim($sFolderNameInUtf8);
+
+ if (0 === \strlen($sDelimiter) || 0 < \strlen(\trim($sFolderParentFullNameRaw)))
+ {
+ $aFolders = $this->oImapClient->FolderList('', 0 === \strlen(\trim($sFolderParentFullNameRaw)) ? 'INBOX' : $sFolderParentFullNameRaw);
+ if (!\is_array($aFolders) || !isset($aFolders[0]))
+ {
+ // TODO
+ throw new \MailSo\Mail\Exceptions\RuntimeException(
+ 0 === \strlen(trim($sFolderParentFullNameRaw))
+ ? 'Cannot get folder delimiter'
+ : 'Cannot create folder in non-existen parent folder');
+ }
+
+ $sDelimiter = $aFolders[0]->Delimiter();
+ if (0 < \strlen($sDelimiter) && 0 < \strlen(\trim($sFolderParentFullNameRaw)))
+ {
+ $sFolderParentFullNameRaw .= $sDelimiter;
+ }
+ }
+
+ $sFullNameRawToCreate = \MailSo\Base\Utils::ConvertEncoding($sFolderNameInUtf8,
+ \MailSo\Base\Enumerations\Charset::UTF_8,
+ \MailSo\Base\Enumerations\Charset::UTF_7_IMAP);
+
+ if (0 < \strlen($sDelimiter) && false !== \strpos($sFullNameRawToCreate, $sDelimiter))
+ {
+ // TODO
+ throw new \MailSo\Mail\Exceptions\RuntimeException(
+ 'New folder name contains delimiter');
+ }
+
+ $sFullNameRawToCreate = $sFolderParentFullNameRaw.$sFullNameRawToCreate;
+
+ $this->oImapClient->FolderCreate($sFullNameRawToCreate);
+
+ if ($bSubscribeOnCreation)
+ {
+ $this->oImapClient->FolderSubscribe($sFullNameRawToCreate);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sPrevFolderFullNameRaw
+ * @param string $sNextFolderFullNameInUtf
+ * @param bool $bSubscribeOnMove = true
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function FolderMove($sPrevFolderFullNameRaw, $sNextFolderFullNameInUtf, $bSubscribeOnMove = true)
+ {
+ return $this->folderModify($sPrevFolderFullNameRaw, $sNextFolderFullNameInUtf, false, $bSubscribeOnMove);
+ }
+
+ /**
+ * @param string $sPrevFolderFullNameRaw
+ * @param string $sNewTopFolderNameInUtf
+ * @param bool $bSubscribeOnRename = true
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function FolderRename($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf, $bSubscribeOnRename = true)
+ {
+ return $this->folderModify($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf, true, $bSubscribeOnRename);
+ }
+
+ /**
+ * @param string $sPrevFolderFullNameRaw
+ * @param string $sNextFolderNameInUtf
+ * @param bool $bRenameOrMove
+ * @param bool $bSubscribeOnModify
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function folderModify($sPrevFolderFullNameRaw, $sNextFolderNameInUtf, $bRenameOrMove, $bSubscribeOnModify)
+ {
+ if (0 === \strlen($sPrevFolderFullNameRaw) || 0 === \strlen($sNextFolderNameInUtf))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $aFolders = $this->oImapClient->FolderList('', $sPrevFolderFullNameRaw);
+ if (!\is_array($aFolders) || !isset($aFolders[0]))
+ {
+ // TODO
+ throw new \MailSo\Mail\Exceptions\RuntimeException('Cannot rename non-existen folder');
+ }
+
+ $sDelimiter = $aFolders[0]->Delimiter();
+ $iLast = \strrpos($sPrevFolderFullNameRaw, $sDelimiter);
+
+ $mSubscribeFolders = null;
+ if ($bSubscribeOnModify)
+ {
+ $mSubscribeFolders = $this->oImapClient->FolderSubscribeList($sPrevFolderFullNameRaw, '*');
+ if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders))
+ {
+ foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder)
+ {
+ $this->oImapClient->FolderUnSubscribe($oFolder->FullNameRaw());
+ }
+ }
+ }
+
+ $sNewFolderFullNameRaw = \MailSo\Base\Utils::ConvertEncoding($sNextFolderNameInUtf,
+ \MailSo\Base\Enumerations\Charset::UTF_8,
+ \MailSo\Base\Enumerations\Charset::UTF_7_IMAP);
+
+ if($bRenameOrMove)
+ {
+ if (0 < \strlen($sDelimiter) && false !== \strpos($sNewFolderFullNameRaw, $sDelimiter))
+ {
+ // TODO
+ throw new \MailSo\Mail\Exceptions\RuntimeException('New folder name contains delimiter');
+ }
+
+ $sFolderParentFullNameRaw = false === $iLast ? '' : \substr($sPrevFolderFullNameRaw, 0, $iLast + 1);
+ $sNewFolderFullNameRaw = $sFolderParentFullNameRaw.$sNewFolderFullNameRaw;
+ }
+
+ $this->oImapClient->FolderRename($sPrevFolderFullNameRaw, $sNewFolderFullNameRaw);
+
+ if (\is_array($mSubscribeFolders) && 0 < count($mSubscribeFolders))
+ {
+ foreach ($mSubscribeFolders as /* @var $oFolder \MailSo\Imap\Folder */ $oFolder)
+ {
+ $sFolderFullNameRawForResubscrine = $oFolder->FullNameRaw();
+ if (0 === \strpos($sFolderFullNameRawForResubscrine, $sPrevFolderFullNameRaw))
+ {
+ $sNewFolderFullNameRawForResubscrine = $sNewFolderFullNameRaw.
+ \substr($sFolderFullNameRawForResubscrine, \strlen($sPrevFolderFullNameRaw));
+
+ $this->oImapClient->FolderSubscribe($sNewFolderFullNameRawForResubscrine);
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFolderFullNameRaw
+ * @param bool $bUnsubscribeOnDeletion = true
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Mail\Exceptions\RuntimeException
+ */
+ public function FolderDelete($sFolderFullNameRaw, $bUnsubscribeOnDeletion = true)
+ {
+ if (0 === \strlen($sFolderFullNameRaw) || 'INBOX' === $sFolderFullNameRaw)
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->FolderExamine($sFolderFullNameRaw);
+
+ $aIndexOrUids = $this->oImapClient->MessageSimpleSearch('ALL');
+ if (0 < \count($aIndexOrUids))
+ {
+ throw new \MailSo\Mail\Exceptions\NonEmptyFolder();
+ }
+
+ $this->oImapClient->FolderExamine('INBOX');
+
+ if ($bUnsubscribeOnDeletion)
+ {
+ $this->oImapClient->FolderUnSubscribe($sFolderFullNameRaw);
+ }
+
+ $this->oImapClient->FolderDelete($sFolderFullNameRaw);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFolderFullNameRaw
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function FolderClear($sFolderFullNameRaw)
+ {
+ $this->oImapClient->FolderSelect($sFolderFullNameRaw);
+
+ $oFolderInformation = $this->oImapClient->FolderCurrentInformation();
+ if ($oFolderInformation && $oFolderInformation->Exists && 0 < $oFolderInformation->Exists) // STATUS?
+ {
+ $this->oImapClient->MessageStoreFlag('1:*', false,
+ array(\MailSo\Imap\Enumerations\MessageFlag::DELETED),
+ \MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT
+ );
+
+ $this->oImapClient->MessageExpunge();
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFolderFullNameRaw
+ * @param bool $bSubscribe
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function FolderSubscribe($sFolderFullNameRaw, $bSubscribe)
+ {
+ if (0 === \strlen($sFolderFullNameRaw))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oImapClient->{($bSubscribe) ? 'FolderSubscribe' : 'FolderUnSubscribe'}($sFolderFullNameRaw);
+
+ return $this;
+ }
+
+ /**
+ * @param \MailSo\Log\Logger $oLogger
+ *
+ * @return \MailSo\Mail\MailClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetLogger($oLogger)
+ {
+ if (!($oLogger instanceof \MailSo\Log\Logger))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oLogger = $oLogger;
+ $this->oImapClient->SetLogger($this->oLogger);
+
+ return $this;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/Message.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/Message.php
new file mode 100644
index 0000000..029b5b7
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/Message.php
@@ -0,0 +1,859 @@
+Clear();
+ }
+
+ /**
+ * @return \MailSo\Mail\Message
+ */
+ public function Clear()
+ {
+ $this->sFolder = '';
+ $this->iUid = 0;
+ $this->sSubject = '';
+ $this->sMessageId = '';
+ $this->sContentType = '';
+ $this->iSize = 0;
+ $this->iInternalTimeStampInUTC = 0;
+ $this->iHeaderTimeStampInUTC = 0;
+ $this->sHeaderDate = '';
+ $this->aFlags = array();
+ $this->aFlagsLowerCase = array();
+
+ $this->oFrom = null;
+ $this->oSender = null;
+ $this->oReplyTo = null;
+ $this->oDeliveredTo = null;
+ $this->oTo = null;
+ $this->oCc = null;
+ $this->oBcc = null;
+
+ $this->sPlain = '';
+ $this->sHtml = '';
+
+ $this->oAttachments = null;
+ $this->aDraftInfo = null;
+
+ $this->sInReplyTo = '';
+ $this->sReferences = '';
+
+ $this->iSensitivity = \MailSo\Mime\Enumerations\Sensitivity::NOTHING;
+ $this->iPriority = \MailSo\Mime\Enumerations\MessagePriority::NORMAL;
+ $this->sDeliveryReceipt = '';
+ $this->sReadReceipt = '';
+
+ $this->aThreads = array();
+
+ $this->bTextPartIsTrimmed = false;
+
+ $this->sPgpSignature = '';
+ $this->bPgpSigned = false;
+ $this->bPgpEncrypted = false;
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Mail\Message
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @return string
+ */
+ public function Plain()
+ {
+ return $this->sPlain;
+ }
+
+ /**
+ * @return string
+ */
+ public function Html()
+ {
+ return $this->sHtml;
+ }
+
+ /**
+ * @return string
+ */
+ public function PgpSignature()
+ {
+ return $this->sPgpSignature;
+ }
+
+ /**
+ * @return bool
+ */
+ public function PgpSigned()
+ {
+ return $this->bPgpSigned;
+ }
+
+ /**
+ * @return bool
+ */
+ public function PgpEncrypted()
+ {
+ return $this->bPgpEncrypted;
+ }
+
+ /**
+ * @param string $sHtml
+ *
+ * @retun void
+ */
+ public function SetHtml($sHtml)
+ {
+ $this->sHtml = $sHtml;
+ }
+
+ /**
+ * @return string
+ */
+ public function Folder()
+ {
+ return $this->sFolder;
+ }
+
+ /**
+ * @return int
+ */
+ public function Uid()
+ {
+ return $this->iUid;
+ }
+
+ /**
+ * @return string
+ */
+ public function MessageId()
+ {
+ return $this->sMessageId;
+ }
+
+ /**
+ * @return string
+ */
+ public function Subject()
+ {
+ return $this->sSubject;
+ }
+
+ /**
+ * @return string
+ */
+ public function ContentType()
+ {
+ return $this->sContentType;
+ }
+
+ /**
+ * @return int
+ */
+ public function Size()
+ {
+ return $this->iSize;
+ }
+
+ /**
+ * @return int
+ */
+ public function InternalTimeStampInUTC()
+ {
+ return $this->iInternalTimeStampInUTC;
+ }
+
+ /**
+ * @return int
+ */
+ public function HeaderTimeStampInUTC()
+ {
+ return $this->iHeaderTimeStampInUTC;
+ }
+
+ /**
+ * @return string
+ */
+ public function HeaderDate()
+ {
+ return $this->sHeaderDate;
+ }
+
+ /**
+ * @return array
+ */
+ public function Flags()
+ {
+ return $this->aFlags;
+ }
+
+ /**
+ * @return array
+ */
+ public function FlagsLowerCase()
+ {
+ return $this->aFlagsLowerCase;
+ }
+
+ /**
+ * @return \MailSo\Mime\EmailCollection
+ */
+ public function From()
+ {
+ return $this->oFrom;
+ }
+
+ /**
+ * @return int
+ */
+ public function Sensitivity()
+ {
+ return $this->iSensitivity;
+ }
+
+ /**
+ * @return int
+ */
+ public function Priority()
+ {
+ return $this->iPriority;
+ }
+
+ /**
+ * @return \MailSo\Mime\EmailCollection
+ */
+ public function Sender()
+ {
+ return $this->oSender;
+ }
+
+ /**
+ * @return \MailSo\Mime\EmailCollection
+ */
+ public function ReplyTo()
+ {
+ return $this->oReplyTo;
+ }
+
+ /**
+ * @return \MailSo\Mime\EmailCollection
+ */
+ public function DeliveredTo()
+ {
+ return $this->oDeliveredTo;
+ }
+
+ /**
+ * @return \MailSo\Mime\EmailCollection
+ */
+ public function To()
+ {
+ return $this->oTo;
+ }
+
+ /**
+ * @return \MailSo\Mime\EmailCollection
+ */
+ public function Cc()
+ {
+ return $this->oCc;
+ }
+
+ /**
+ * @return \MailSo\Mime\EmailCollection
+ */
+ public function Bcc()
+ {
+ return $this->oBcc;
+ }
+
+ /**
+ * @return \MailSo\Mail\AttachmentCollection
+ */
+ public function Attachments()
+ {
+ return $this->oAttachments;
+ }
+
+ /**
+ * @return string
+ */
+ public function InReplyTo()
+ {
+ return $this->sInReplyTo;
+ }
+
+ /**
+ * @return string
+ */
+ public function References()
+ {
+ return $this->sReferences;
+ }
+
+ /**
+ * @return string
+ */
+ public function DeliveryReceipt()
+ {
+ return $this->sDeliveryReceipt;
+ }
+
+ /**
+ * @return string
+ */
+ public function ReadReceipt()
+ {
+ return $this->sReadReceipt;
+ }
+
+ /**
+ * @return string
+ */
+ public function ReadingConfirmation()
+ {
+ return $this->ReadReceipt();
+ }
+
+ /**
+ * @return array | null
+ */
+ public function DraftInfo()
+ {
+ return $this->aDraftInfo;
+ }
+
+ /**
+ * @return array
+ */
+ public function Threads()
+ {
+ return $this->aThreads;
+ }
+
+ /**
+ * @param array $aThreads
+ */
+ public function SetThreads($aThreads)
+ {
+ $this->aThreads = \is_array($aThreads) ? $aThreads : array();
+ }
+
+ /**
+ * @return boole
+ */
+ public function TextPartIsTrimmed()
+ {
+ return $this->bTextPartIsTrimmed;
+ }
+
+ /**
+ * @param string $sFolder
+ * @param \MailSo\Imap\FetchResponse $oFetchResponse
+ * @param \MailSo\Imap\BodyStructure $oBodyStructure = null
+ *
+ * @return \MailSo\Mail\Message
+ */
+ public static function NewFetchResponseInstance($sFolder, $oFetchResponse, $oBodyStructure = null)
+ {
+ return self::NewInstance()->InitByFetchResponse($sFolder, $oFetchResponse, $oBodyStructure);
+ }
+
+ /**
+ * @param string $sFolder
+ * @param \MailSo\Imap\FetchResponse $oFetchResponse
+ * @param \MailSo\Imap\BodyStructure $oBodyStructure = null
+ *
+ * @return \MailSo\Mail\Message
+ */
+ public function InitByFetchResponse($sFolder, $oFetchResponse, $oBodyStructure = null)
+ {
+ if (!$oBodyStructure)
+ {
+ $oBodyStructure = $oFetchResponse->GetFetchBodyStructure();
+ }
+
+ $sUid = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::UID);
+ $sSize = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::RFC822_SIZE);
+ $sInternalDate = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::INTERNALDATE);
+ $aFlags = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::FLAGS);
+
+ $this->sFolder = $sFolder;
+ $this->iUid = \is_numeric($sUid) ? (int) $sUid : 0;
+ $this->iSize = \is_numeric($sSize) ? (int) $sSize : 0;
+ $this->aFlags = \is_array($aFlags) ? $aFlags : array();
+ $this->aFlagsLowerCase = \array_map('strtolower', $this->aFlags);
+
+ $this->iInternalTimeStampInUTC =
+ \MailSo\Base\DateTimeHelper::ParseInternalDateString($sInternalDate);
+
+ $sCharset = $oBodyStructure ? $oBodyStructure->SearchCharset() : '';
+ $sCharset = \MailSo\Base\Utils::NormalizeCharset($sCharset);
+
+ $sHeaders = $oFetchResponse->GetHeaderFieldsValue();
+ if (0 < \strlen($sHeaders))
+ {
+ $oHeaders = \MailSo\Mime\HeaderCollection::NewInstance()->Parse($sHeaders, false, $sCharset);
+
+ $sContentTypeCharset = $oHeaders->ParameterValue(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ \MailSo\Mime\Enumerations\Parameter::CHARSET
+ );
+
+ if (0 < \strlen($sContentTypeCharset))
+ {
+ $sCharset = $sContentTypeCharset;
+ $sCharset = \MailSo\Base\Utils::NormalizeCharset($sCharset);
+ }
+
+ if (0 < \strlen($sCharset))
+ {
+ $oHeaders->SetParentCharset($sCharset);
+ }
+
+ $bCharsetAutoDetect = 0 === \strlen($sCharset);
+
+ $this->sSubject = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SUBJECT, $bCharsetAutoDetect);
+ $this->sMessageId = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::MESSAGE_ID);
+ $this->sContentType = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::CONTENT_TYPE);
+
+ $this->oFrom = $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::FROM_, $bCharsetAutoDetect);
+ $this->oTo = $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::TO_, $bCharsetAutoDetect);
+ $this->oCc = $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::CC, $bCharsetAutoDetect);
+ $this->oBcc = $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::BCC, $bCharsetAutoDetect);
+
+ $oHeaders->PopulateEmailColectionByDkim($this->oFrom);
+
+ $this->oSender = $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::SENDER, $bCharsetAutoDetect);
+ $this->oReplyTo = $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::REPLY_TO, $bCharsetAutoDetect);
+ $this->oDeliveredTo = $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::DELIVERED_TO, $bCharsetAutoDetect);
+
+ $this->sInReplyTo = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::IN_REPLY_TO);
+ $this->sReferences = \MailSo\Base\Utils::StripSpaces(
+ $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::REFERENCES));
+
+ $sHeaderDate = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::DATE);
+ $this->sHeaderDate = $sHeaderDate;
+ $this->iHeaderTimeStampInUTC = \MailSo\Base\DateTimeHelper::ParseRFC2822DateString($sHeaderDate);
+
+ // Sensitivity
+ $this->iSensitivity = \MailSo\Mime\Enumerations\Sensitivity::NOTHING;
+ $sSensitivity = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::SENSITIVITY);
+ switch (\strtolower($sSensitivity))
+ {
+ case 'personal':
+ $this->iSensitivity = \MailSo\Mime\Enumerations\Sensitivity::PERSONAL;
+ break;
+ case 'private':
+ $this->iSensitivity = \MailSo\Mime\Enumerations\Sensitivity::PRIVATE_;
+ break;
+ case 'company-confidential':
+ $this->iSensitivity = \MailSo\Mime\Enumerations\Sensitivity::CONFIDENTIAL;
+ break;
+ }
+
+ // Priority
+ $this->iPriority = \MailSo\Mime\Enumerations\MessagePriority::NORMAL;
+ $sPriority = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::X_MSMAIL_PRIORITY);
+ if (0 === \strlen($sPriority))
+ {
+ $sPriority = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::IMPORTANCE);
+ }
+ if (0 === \strlen($sPriority))
+ {
+ $sPriority = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::X_PRIORITY);
+ }
+ if (0 < \strlen($sPriority))
+ {
+ switch (\str_replace(' ', '', \strtolower($sPriority)))
+ {
+ case 'high':
+ case '1(highest)':
+ case '2(high)':
+ case '1':
+ case '2':
+ $this->iPriority = \MailSo\Mime\Enumerations\MessagePriority::HIGH;
+ break;
+
+ case 'low':
+ case '4(low)':
+ case '5(lowest)':
+ case '4':
+ case '5':
+ $this->iPriority = \MailSo\Mime\Enumerations\MessagePriority::LOW;
+ break;
+ }
+ }
+
+ // Delivery Receipt
+ $this->sDeliveryReceipt = \trim($oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::RETURN_RECEIPT_TO));
+
+ // Read Receipt
+ $this->sReadReceipt = \trim($oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::DISPOSITION_NOTIFICATION_TO));
+ if (empty($this->sReadReceipt))
+ {
+ $this->sReadReceipt = \trim($oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::X_CONFIRM_READING_TO));
+ }
+
+ $sDraftInfo = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::X_DRAFT_INFO);
+ if (0 < \strlen($sDraftInfo))
+ {
+ $sType = '';
+ $sFolder = '';
+ $sUid = '';
+
+ \MailSo\Mime\ParameterCollection::NewInstance($sDraftInfo)
+ ->ForeachList(function ($oParameter) use (&$sType, &$sFolder, &$sUid) {
+
+ switch (\strtolower($oParameter->Name()))
+ {
+ case 'type':
+ $sType = $oParameter->Value();
+ break;
+ case 'uid':
+ $sUid = $oParameter->Value();
+ break;
+ case 'folder':
+ $sFolder = \base64_decode($oParameter->Value());
+ break;
+ }
+ })
+ ;
+
+ if (0 < \strlen($sType) && 0 < \strlen($sFolder) && 0 < \strlen($sUid))
+ {
+ $this->aDraftInfo = array($sType, $sUid, $sFolder);
+ }
+ }
+ }
+ else if ($oFetchResponse->GetEnvelope())
+ {
+ if (0 === \strlen($sCharset) && $oBodyStructure)
+ {
+ $sCharset = $oBodyStructure->SearchCharset();
+ $sCharset = \MailSo\Base\Utils::NormalizeCharset($sCharset);
+ }
+
+ if (0 === \strlen($sCharset))
+ {
+ $sCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1;
+ }
+
+ // date, subject, from, sender, reply-to, to, cc, bcc, in-reply-to, message-id
+ $this->sMessageId = $oFetchResponse->GetFetchEnvelopeValue(9, '');
+ $this->sSubject = \MailSo\Base\Utils::DecodeHeaderValue($oFetchResponse->GetFetchEnvelopeValue(1, ''), $sCharset);
+
+ $this->oFrom = $oFetchResponse->GetFetchEnvelopeEmailCollection(2, $sCharset);
+ $this->oSender = $oFetchResponse->GetFetchEnvelopeEmailCollection(3, $sCharset);
+ $this->oReplyTo = $oFetchResponse->GetFetchEnvelopeEmailCollection(4, $sCharset);
+ $this->oTo = $oFetchResponse->GetFetchEnvelopeEmailCollection(5, $sCharset);
+ $this->oCc = $oFetchResponse->GetFetchEnvelopeEmailCollection(6, $sCharset);
+ $this->oBcc = $oFetchResponse->GetFetchEnvelopeEmailCollection(7, $sCharset);
+ $this->sInReplyTo = $oFetchResponse->GetFetchEnvelopeValue(8, '');
+ }
+
+ $aTextParts = $oBodyStructure ? $oBodyStructure->SearchHtmlOrPlainParts() : null;
+ if (\is_array($aTextParts) && 0 < \count($aTextParts))
+ {
+ if (0 === \strlen($sCharset))
+ {
+ $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8;
+ }
+
+ $aHtmlParts = array();
+ $aPlainParts = array();
+
+ foreach ($aTextParts as $oPart)
+ {
+ $sText = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::BODY.'['.$oPart->PartID().']');
+ if (null === $sText)
+ {
+ $sText = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::BODY.'['.$oPart->PartID().']<0>');
+ if (\is_string($sText) && 0 < \strlen($sText))
+ {
+ $this->bTextPartIsTrimmed = true;
+ }
+ }
+
+ if (\is_string($sText) && 0 < \strlen($sText))
+ {
+ $sTextCharset = $oPart->Charset();
+ if (empty($sTextCharset))
+ {
+ $sTextCharset = $sCharset;
+ }
+
+ $sTextCharset = \MailSo\Base\Utils::NormalizeCharset($sTextCharset, true);
+
+ $sText = \MailSo\Base\Utils::DecodeEncodingValue($sText, $oPart->MailEncodingName());
+ $sText = \MailSo\Base\Utils::ConvertEncoding($sText, $sTextCharset, \MailSo\Base\Enumerations\Charset::UTF_8);
+ $sText = \MailSo\Base\Utils::Utf8Clear($sText);
+
+ if ('text/html' === $oPart->ContentType())
+ {
+ $aHtmlParts[] = $sText;
+ }
+ else
+ {
+ if ($oPart->IsFlowedFormat())
+ {
+ $sText = \MailSo\Base\Utils::DecodeFlowedFormat($sText);
+ }
+
+ $aPlainParts[] = $sText;
+ }
+ }
+ }
+
+ if (0 < \count($aHtmlParts))
+ {
+ $this->sHtml = \implode(' ', $aHtmlParts);
+ }
+ else
+ {
+ $this->sPlain = \trim(\implode("\n", $aPlainParts));
+ }
+
+ $aMatch = array();
+ if (\preg_match('/-----BEGIN PGP SIGNATURE-----(.+)-----END PGP SIGNATURE-----/ism', $this->sPlain, $aMatch) && !empty($aMatch[0]))
+ {
+ $this->sPgpSignature = \trim($aMatch[0]);
+ $this->bPgpSigned = true;
+ }
+
+ $aMatch = array();
+ if (\preg_match('/-----BEGIN PGP MESSAGE-----/ism', $this->sPlain, $aMatch) && !empty($aMatch[0]))
+ {
+ $this->bPgpEncrypted = true;
+ }
+
+ unset($aHtmlParts, $aPlainParts, $aMatch);
+ }
+
+// if (empty($this->sPgpSignature) && 'multipart/signed' === \strtolower($this->sContentType) &&
+// 'application/pgp-signature' === \strtolower($oHeaders->ParameterValue(
+// \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+// \MailSo\Mime\Enumerations\Parameter::PROTOCOL
+// )))
+// {
+// $aPgpSignatureParts = $oBodyStructure ? $oBodyStructure->SearchByContentType('application/pgp-signature') : null;
+// if (\is_array($aPgpSignatureParts) && 0 < \count($aPgpSignatureParts) && isset($aPgpSignatureParts[0]))
+// {
+// $sPgpSignatureText = $oFetchResponse->GetFetchValue(\MailSo\Imap\Enumerations\FetchType::BODY.'['.$aPgpSignatureParts[0]->PartID().']');
+// if (\is_string($sPgpSignatureText) && 0 < \strlen($sPgpSignatureText) && 0 < \strpos($sPgpSignatureText, 'BEGIN PGP SIGNATURE'))
+// {
+// $this->sPgpSignature = \trim($sPgpSignatureText);
+// $this->bPgpSigned = true;
+// }
+// }
+// }
+
+ if ($oBodyStructure)
+ {
+ $aAttachmentsParts = $oBodyStructure->SearchAttachmentsParts();
+ if ($aAttachmentsParts && 0 < count($aAttachmentsParts))
+ {
+ $this->oAttachments = AttachmentCollection::NewInstance();
+ foreach ($aAttachmentsParts as /* @var $oAttachmentItem \MailSo\Imap\BodyStructure */ $oAttachmentItem)
+ {
+ $this->oAttachments->Add(
+ \MailSo\Mail\Attachment::NewBodyStructureInstance($this->sFolder, $this->iUid, $oAttachmentItem)
+ );
+ }
+ }
+ }
+
+ return $this;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/MessageCollection.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/MessageCollection.php
new file mode 100644
index 0000000..427a18c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mail/MessageCollection.php
@@ -0,0 +1,123 @@
+Clear();
+ }
+
+ /**
+ * @return \MailSo\Mail\MessageCollection
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @return \MailSo\Mail\MessageCollection
+ */
+ public function Clear()
+ {
+ parent::Clear();
+
+ $this->FolderHash = '';
+
+ $this->MessageCount = 0;
+ $this->MessageUnseenCount = 0;
+ $this->MessageResultCount = 0;
+
+ $this->FolderName = '';
+ $this->Offset = 0;
+ $this->Limit = 0;
+ $this->Search = '';
+ $this->UidNext = '';
+ $this->ThreadUid = '';
+ $this->NewMessages = array();
+
+ $this->Filtered = false;
+
+ return $this;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/MailSo.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/MailSo.php
new file mode 100644
index 0000000..aa294dc
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/MailSo.php
@@ -0,0 +1,40 @@
+rResource = $rResource;
+ $this->sFileName = $sFileName;
+ $this->iFileSize = $iFileSize;
+ $this->bIsInline = $bIsInline;
+ $this->bIsLinked = $bIsLinked;
+ $this->sCID = $sCID;
+ $this->aCustomContentTypeParams = $aCustomContentTypeParams;
+ $this->sContentLocation = $sContentLocation;
+ }
+
+ /**
+ * @param resource $rResource
+ * @param string $sFileName = ''
+ * @param int $iFileSize = 0
+ * @param bool $bIsInline = false
+ * @param bool $bIsLinked = false
+ * @param string $sCID = ''
+ * @param array $aCustomContentTypeParams = array()
+ * @param string $sContentLocation = ''
+ *
+ * @return \MailSo\Mime\Attachment
+ */
+ public static function NewInstance($rResource, $sFileName = '', $iFileSize = 0, $bIsInline = false,
+ $bIsLinked = false, $sCID = '', $aCustomContentTypeParams = array(), $sContentLocation = '')
+ {
+ return new self($rResource, $sFileName, $iFileSize, $bIsInline, $bIsLinked, $sCID, $aCustomContentTypeParams, $sContentLocation);
+ }
+
+ /**
+ * @return resource
+ */
+ public function Resource()
+ {
+ return $this->rResource;
+ }
+
+ /**
+ * @return string
+ */
+ public function ContentType()
+ {
+ return \MailSo\Base\Utils::MimeContentType($this->sFileName);
+ }
+
+ /**
+ * @return array
+ */
+ public function CustomContentTypeParams()
+ {
+ return $this->aCustomContentTypeParams;
+ }
+
+ /**
+ * @return string
+ */
+ public function CID()
+ {
+ return $this->sCID;
+ }
+
+ /**
+ * @return string
+ */
+ public function ContentLocation()
+ {
+ return $this->sContentLocation;
+ }
+
+ /**
+ * @return string
+ */
+ public function FileName()
+ {
+ return $this->sFileName;
+ }
+
+ /**
+ * @return int
+ */
+ public function FileSize()
+ {
+ return $this->iFileSize;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsInline()
+ {
+ return $this->bIsInline;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsImage()
+ {
+ return 'image' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsArchive()
+ {
+ return 'archive' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsPdf()
+ {
+ return 'pdf' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsDoc()
+ {
+ return 'doc' === \MailSo\Base\Utils::ContentTypeType($this->ContentType(), $this->FileName());
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsLinked()
+ {
+ return $this->bIsLinked && 0 < \strlen($this->sCID);
+ }
+}
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/AttachmentCollection.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/AttachmentCollection.php
new file mode 100644
index 0000000..68376fd
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/AttachmentCollection.php
@@ -0,0 +1,71 @@
+FilterList(function ($oItem) {
+ return $oItem && $oItem->IsLinked();
+ });
+ }
+
+ /**
+ * @return array
+ */
+ public function UnlinkedAttachments()
+ {
+ return $this->FilterList(function ($oItem) {
+ return $oItem && !$oItem->IsLinked();
+ });
+ }
+
+ /**
+ * @return int
+ */
+ public function SizeOfAttachments()
+ {
+ $iResult = 0;
+ $this->ForeachList(function ($oItem) use (&$iResult) {
+ if ($oItem)
+ {
+ $iResult += $oItem->FileSize();
+ }
+ });
+
+ return $iResult;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Email.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Email.php
new file mode 100644
index 0000000..ee03c67
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Email.php
@@ -0,0 +1,337 @@
+sEmail = \MailSo\Base\Utils::IdnToAscii(
+ \MailSo\Base\Utils::Trim($sEmail), true);
+
+ $this->sDisplayName = \MailSo\Base\Utils::Trim($sDisplayName);
+ $this->sRemark = \MailSo\Base\Utils::Trim($sRemark);
+
+ $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::NONE;
+ $this->sDkimValue = '';
+ }
+
+ /**
+ * @param string $sEmail
+ * @param string $sDisplayName = ''
+ * @param string $sRemark = ''
+ *
+ * @return \MailSo\Mime\Email
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public static function NewInstance($sEmail, $sDisplayName = '', $sRemark = '')
+ {
+ return new self($sEmail, $sDisplayName, $sRemark);
+ }
+
+ /**
+ * @param string $sEmailAddress
+ * @return \MailSo\Mime\Email
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public static function Parse($sEmailAddress)
+ {
+ $sEmailAddress = \MailSo\Base\Utils::Trim($sEmailAddress);
+ if (!\MailSo\Base\Validator::NotEmptyString($sEmailAddress, true))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $sName = '';
+ $sEmail = '';
+ $sComment = '';
+
+ $bInName = false;
+ $bInAddress = false;
+ $bInComment = false;
+
+ $iStartIndex = 0;
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+
+ while ($iCurrentIndex < \strlen($sEmailAddress))
+ {
+ switch ($sEmailAddress{$iCurrentIndex})
+ {
+// case '\'':
+ case '"':
+// $sQuoteChar = $sEmailAddress{$iCurrentIndex};
+ if ((!$bInName) && (!$bInAddress) && (!$bInComment))
+ {
+ $bInName = true;
+ $iStartIndex = $iCurrentIndex;
+ }
+ else if ((!$bInAddress) && (!$bInComment))
+ {
+ $iEndIndex = $iCurrentIndex;
+ $sName = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
+ $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+ $iStartIndex = 0;
+ $bInName = false;
+ }
+ break;
+ case '<':
+ if ((!$bInName) && (!$bInAddress) && (!$bInComment))
+ {
+ if ($iCurrentIndex > 0 && \strlen($sName) === 0)
+ {
+ $sName = \substr($sEmailAddress, 0, $iCurrentIndex);
+ }
+
+ $bInAddress = true;
+ $iStartIndex = $iCurrentIndex;
+ }
+ break;
+ case '>':
+ if ($bInAddress)
+ {
+ $iEndIndex = $iCurrentIndex;
+ $sEmail = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
+ $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+ $iStartIndex = 0;
+ $bInAddress = false;
+ }
+ break;
+ case '(':
+ if ((!$bInName) && (!$bInAddress) && (!$bInComment))
+ {
+ $bInComment = true;
+ $iStartIndex = $iCurrentIndex;
+ }
+ break;
+ case ')':
+ if ($bInComment)
+ {
+ $iEndIndex = $iCurrentIndex;
+ $sComment = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
+ $sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+ $iStartIndex = 0;
+ $bInComment = false;
+ }
+ break;
+ case '\\':
+ $iCurrentIndex++;
+ break;
+ }
+
+ $iCurrentIndex++;
+ }
+
+ if (\strlen($sEmail) === 0)
+ {
+ $aRegs = array('');
+ if (\preg_match('/[^@\s]+@\S+/i', $sEmailAddress, $aRegs) && isset($aRegs[0]))
+ {
+ $sEmail = $aRegs[0];
+ }
+ else
+ {
+ $sName = $sEmailAddress;
+ }
+ }
+
+ if ((\strlen($sEmail) > 0) && (\strlen($sName) == 0) && (\strlen($sComment) == 0))
+ {
+ $sName = \str_replace($sEmail, '', $sEmailAddress);
+ }
+
+ $sEmail = \trim(\trim($sEmail), '<>');
+ $sEmail = \rtrim(\trim($sEmail), '.');
+ $sEmail = \trim($sEmail);
+
+ $sName = \trim(\trim($sName), '"');
+ $sName = \trim($sName, '\'');
+ $sComment = \trim(\trim($sComment), '()');
+
+ // Remove backslash
+ $sName = \preg_replace('/\\\\(.)/s', '$1', $sName);
+ $sComment = \preg_replace('/\\\\(.)/s', '$1', $sComment);
+
+ return Email::NewInstance($sEmail, $sName, $sComment);
+ }
+
+ /**
+ * @param bool $bIdn = false
+ *
+ * @return string
+ */
+ public function GetEmail($bIdn = false)
+ {
+ return $bIdn ? \MailSo\Base\Utils::IdnToUtf8($this->sEmail) : $this->sEmail;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetDisplayName()
+ {
+ return $this->sDisplayName;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetRemark()
+ {
+ return $this->sRemark;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetDkimStatus()
+ {
+ return $this->sDkimStatus;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetDkimValue()
+ {
+ return $this->sDkimValue;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetAccountName()
+ {
+ return \MailSo\Base\Utils::GetAccountNameFromEmail($this->GetEmail(false));
+ }
+
+ /**
+ * @param bool $bIdn = false
+ *
+ * @return string
+ */
+ public function GetDomain($bIdn = false)
+ {
+ return \MailSo\Base\Utils::GetDomainFromEmail($this->GetEmail($bIdn));
+ }
+
+ /**
+ * @param string $sDkimStatus
+ * @param string $sDkimValue = ''
+ */
+ public function SetDkimStatusAndValue($sDkimStatus, $sDkimValue = '')
+ {
+ $this->sDkimStatus = \MailSo\Mime\Enumerations\DkimStatus::normalizeValue($sDkimStatus);
+ $this->sDkimValue = $sDkimValue;
+ }
+
+ /**
+ * @param bool $bIdn = false
+ *
+ * @return array
+ */
+ public function ToArray($bIdn = false)
+ {
+ return array($this->sDisplayName, $this->GetEmail($bIdn), $this->sRemark,
+ $this->sDkimStatus, $this->sDkimValue);
+ }
+
+ /**
+ * @param bool $bConvertSpecialsName = false
+ * @param bool $bIdn = false
+ *
+ * @return string
+ */
+ public function ToString($bConvertSpecialsName = false, $bIdn = false)
+ {
+ $sReturn = '';
+
+ $sRemark = \str_replace(')', '\)', $this->sRemark);
+ $sDisplayName = \str_replace('"', '\"', $this->sDisplayName);
+
+ if ($bConvertSpecialsName)
+ {
+ $sDisplayName = 0 === \strlen($sDisplayName) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue(
+ \MailSo\Base\Enumerations\Encoding::BASE64_SHORT,
+ $sDisplayName);
+
+ $sRemark = 0 === \strlen($sRemark) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue(
+ \MailSo\Base\Enumerations\Encoding::BASE64_SHORT,
+ $sRemark);
+ }
+
+ $sDisplayName = 0 === \strlen($sDisplayName) ? '' : '"'.$sDisplayName.'"';
+ $sRemark = 0 === \strlen($sRemark) ? '' : '('.$sRemark.')';
+
+ if (0 < \strlen($this->sEmail))
+ {
+ $sReturn = $this->GetEmail($bIdn);
+ if (0 < \strlen($sDisplayName.$sRemark))
+ {
+ $sReturn = $sDisplayName.' <'.$sReturn.'> '.$sRemark;
+ }
+ }
+
+ return \trim($sReturn);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/EmailCollection.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/EmailCollection.php
new file mode 100644
index 0000000..53e5db3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/EmailCollection.php
@@ -0,0 +1,243 @@
+parseEmailAddresses($sEmailAddresses);
+ }
+ }
+
+ /**
+ * @param string $sEmailAddresses = ''
+ *
+ * @return \MailSo\Mime\EmailCollection
+ */
+ public static function NewInstance($sEmailAddresses = '')
+ {
+ return new self($sEmailAddresses);
+ }
+
+ /**
+ * @param string $sEmailAddresses
+ *
+ * @return \MailSo\Mime\EmailCollection
+ */
+ public static function Parse($sEmailAddresses)
+ {
+ return self::NewInstance($sEmailAddresses);
+ }
+
+ /**
+ * @return array
+ */
+ public function ToArray()
+ {
+ $aReturn = $aEmails = array();
+ $aEmails =& $this->GetAsArray();
+ foreach ($aEmails as /* @var $oEmail \MailSo\Mime\Email */ $oEmail)
+ {
+ $aReturn[] = $oEmail->ToArray();
+ }
+
+ return $aReturn;
+ }
+
+ /**
+ * @param \MailSo\Mime\EmailCollection $oEmails
+ *
+ * @return \MailSo\Mime\EmailCollection
+ */
+ public function MergeWithOtherCollection(\MailSo\Mime\EmailCollection $oEmails)
+ {
+ $aEmails =& $oEmails->GetAsArray();
+ foreach ($aEmails as /* @var $oEmail \MailSo\Mime\Email */ $oEmail)
+ {
+ $this->Add($oEmail);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Mime\EmailCollection
+ */
+ public function Unique()
+ {
+ $aCache = array();
+ $aReturn = array();
+
+ $aEmails =& $this->GetAsArray();
+ foreach ($aEmails as /* @var $oEmail \MailSo\Mime\Email */ $oEmail)
+ {
+ $sEmail = $oEmail->GetEmail();
+ if (!isset($aCache[$sEmail]))
+ {
+ $aCache[$sEmail] = true;
+ $aReturn[] = $oEmail;
+ }
+ }
+
+ $this->SetAsArray($aReturn);
+
+ return $this;
+ }
+
+ /**
+ * @param bool $bConvertSpecialsName = false
+ * @param bool $bIdn = false
+ *
+ * @return string
+ */
+ public function ToString($bConvertSpecialsName = false, $bIdn = false)
+ {
+ $aReturn = $aEmails = array();
+ $aEmails =& $this->GetAsArray();
+ foreach ($aEmails as /* @var $oEmail \MailSo\Mime\Email */ $oEmail)
+ {
+ $aReturn[] = $oEmail->ToString($bConvertSpecialsName, $bIdn);
+ }
+
+ return \implode(', ', $aReturn);
+ }
+
+ /**
+ * @param string $sRawEmails
+ *
+ * @return \MailSo\Mime\EmailCollection
+ */
+ private function parseEmailAddresses($sRawEmails)
+ {
+ $this->Clear();
+
+ $sWorkingRecipients = \trim($sRawEmails);
+
+ if (0 === \strlen($sWorkingRecipients))
+ {
+ return $this;
+ }
+
+ $iEmailStartPos = 0;
+ $iEmailEndPos = 0;
+
+ $bIsInQuotes = false;
+ $sChQuote = '"';
+ $bIsInAngleBrackets = false;
+ $bIsInBrackets = false;
+
+ $iCurrentPos = 0;
+
+ $sWorkingRecipientsLen = \strlen($sWorkingRecipients);
+
+ while ($iCurrentPos < $sWorkingRecipientsLen)
+ {
+ switch ($sWorkingRecipients{$iCurrentPos})
+ {
+ case '\'':
+ case '"':
+ if (!$bIsInQuotes)
+ {
+ $sChQuote = $sWorkingRecipients{$iCurrentPos};
+ $bIsInQuotes = true;
+ }
+ else if ($sChQuote == $sWorkingRecipients{$iCurrentPos})
+ {
+ $bIsInQuotes = false;
+ }
+ break;
+
+ case '<':
+ if (!$bIsInAngleBrackets)
+ {
+ $bIsInAngleBrackets = true;
+ if ($bIsInQuotes)
+ {
+ $bIsInQuotes = false;
+ }
+ }
+ break;
+
+ case '>':
+ if ($bIsInAngleBrackets)
+ {
+ $bIsInAngleBrackets = false;
+ }
+ break;
+
+ case '(':
+ if (!$bIsInBrackets)
+ {
+ $bIsInBrackets = true;
+ }
+ break;
+
+ case ')':
+ if ($bIsInBrackets)
+ {
+ $bIsInBrackets = false;
+ }
+ break;
+
+ case ',':
+ case ';':
+ if (!$bIsInAngleBrackets && !$bIsInBrackets && !$bIsInQuotes)
+ {
+ $iEmailEndPos = $iCurrentPos;
+
+ try
+ {
+ $this->Add(
+ \MailSo\Mime\Email::Parse(\substr($sWorkingRecipients, $iEmailStartPos, $iEmailEndPos - $iEmailStartPos))
+ );
+
+ $iEmailStartPos = $iCurrentPos + 1;
+ }
+ catch (\MailSo\Base\Exceptions\InvalidArgumentException $oException)
+ {
+ }
+ }
+ break;
+ }
+
+ $iCurrentPos++;
+ }
+
+ if ($iEmailStartPos < $iCurrentPos)
+ {
+ try
+ {
+ $this->Add(
+ \MailSo\Mime\Email::Parse(\substr($sWorkingRecipients, $iEmailStartPos, $iCurrentPos - $iEmailStartPos))
+ );
+ }
+ catch (\MailSo\Base\Exceptions\InvalidArgumentException $oException) {}
+ }
+
+ return $this;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Enumerations/Constants.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Enumerations/Constants.php
new file mode 100644
index 0000000..41da581
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Enumerations/Constants.php
@@ -0,0 +1,25 @@
+sParentCharset = $sParentCharset;
+
+ $this->initInputData($sName, $sValue, $sEncodedValueForReparse);
+ }
+
+ /**
+ * @param string $sName
+ * @param string $sValue
+ * @param string $sEncodedValueForReparse
+ *
+ * @return void
+ */
+ private function initInputData($sName, $sValue, $sEncodedValueForReparse)
+ {
+ $this->sName = trim($sName);
+ $this->sFullValue = trim($sValue);
+ $this->sEncodedValueForReparse = '';
+
+ $this->oParameters = null;
+ if (0 < \strlen($sEncodedValueForReparse) && $this->IsReparsed())
+ {
+ $this->sEncodedValueForReparse = \trim($sEncodedValueForReparse);
+ }
+
+ if (0 < \strlen($this->sFullValue) && $this->IsParameterized())
+ {
+ $aRawExplode = \explode(';', $this->sFullValue, 2);
+ if (2 === \count($aRawExplode))
+ {
+ $this->sValue = $aRawExplode[0];
+ $this->oParameters =
+ \MailSo\Mime\ParameterCollection::NewInstance($aRawExplode[1]);
+ }
+ else
+ {
+ $this->sValue = $this->sFullValue;
+ }
+ }
+ else
+ {
+ $this->sValue = $this->sFullValue;
+ }
+ }
+
+ /**
+ * @param string $sName
+ * @param string $sValue = ''
+ * @param string $sEncodedValueForReparse = ''
+ * @param string $sParentCharset = ''
+ *
+ * @return \MailSo\Mime\Header
+ */
+ public static function NewInstance($sName, $sValue = '', $sEncodedValueForReparse = '', $sParentCharset = '')
+ {
+ return new self($sName, $sValue, $sEncodedValueForReparse, $sParentCharset);
+ }
+
+ /**
+ * @param string $sEncodedLines
+ * @param string $sIncomingCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1
+ *
+ * @return \MailSo\Mime\Header | false
+ */
+ public static function NewInstanceFromEncodedString($sEncodedLines, $sIncomingCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1)
+ {
+ if (empty($sIncomingCharset))
+ {
+ $sIncomingCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1;
+ }
+
+ $aParts = \explode(':', \str_replace("\r", '', $sEncodedLines), 2);
+ if (isset($aParts[0]) && isset($aParts[1]) && 0 < \strlen($aParts[0]) && 0 < \strlen($aParts[1]))
+ {
+ return self::NewInstance(
+ \trim($aParts[0]),
+ \trim(\MailSo\Base\Utils::DecodeHeaderValue(\trim($aParts[1]), $sIncomingCharset)),
+ \trim($aParts[1]),
+ $sIncomingCharset
+ );
+ }
+
+ return false;
+ }
+
+ /**
+ * @return string
+ */
+ public function Name()
+ {
+ return $this->sName;
+ }
+
+ /**
+ * @return string
+ */
+ public function NameWithDelimitrom()
+ {
+ return $this->Name().': ';
+ }
+
+ /**
+ * @return string
+ */
+ public function Value()
+ {
+ return $this->sValue;
+ }
+
+ /**
+ * @return string
+ */
+ public function FullValue()
+ {
+ return $this->sFullValue;
+ }
+
+ /**
+ * @param string $sParentCharset
+ * @return \MailSo\Mime\Header
+ */
+ public function SetParentCharset($sParentCharset)
+ {
+ if ($this->sParentCharset !== $sParentCharset && $this->IsReparsed() && 0 < \strlen($this->sEncodedValueForReparse))
+ {
+ $this->initInputData(
+ $this->sName,
+ \trim(\MailSo\Base\Utils::DecodeHeaderValue($this->sEncodedValueForReparse, $sParentCharset)),
+ $this->sEncodedValueForReparse
+ );
+ }
+
+ $this->sParentCharset = $sParentCharset;
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Mime\ParameterCollection | null
+ */
+ public function Parameters()
+ {
+ return $this->oParameters;
+ }
+
+ /**
+ * @param string $sValue
+ * @return string
+ */
+ private function wordWrapHelper($sValue, $sGlue = "\r\n ")
+ {
+ return \trim(substr(wordwrap($this->NameWithDelimitrom().$sValue,
+ \MailSo\Mime\Enumerations\Constants::LINE_LENGTH, $sGlue
+ ), \strlen($this->NameWithDelimitrom())));
+ }
+
+ /**
+ * @return string
+ */
+ public function EncodedValue()
+ {
+ $sResult = $this->sFullValue;
+
+ if ($this->IsSubject())
+ {
+ if (!\MailSo\Base\Utils::IsAscii($sResult) &&
+ \MailSo\Base\Utils::IsIconvSupported() &&
+ \function_exists('iconv_mime_encode'))
+ {
+ $aPreferences = array(
+// 'scheme' => \MailSo\Base\Enumerations\Encoding::QUOTED_PRINTABLE_SHORT,
+ 'scheme' => \MailSo\Base\Enumerations\Encoding::BASE64_SHORT,
+ 'input-charset' => \MailSo\Base\Enumerations\Charset::UTF_8,
+ 'output-charset' => \MailSo\Base\Enumerations\Charset::UTF_8,
+ 'line-length' => \MailSo\Mime\Enumerations\Constants::LINE_LENGTH,
+ 'line-break-chars' => \MailSo\Mime\Enumerations\Constants::CRLF
+ );
+
+ return \iconv_mime_encode($this->Name(), $sResult, $aPreferences);
+ }
+ }
+ else if ($this->IsParameterized() && $this->oParameters && 0 < $this->oParameters->Count())
+ {
+ $sResult = $this->sValue.'; '.$this->oParameters->ToString(true);
+ }
+ else if ($this->IsEmail())
+ {
+ $oEmailCollection = \MailSo\Mime\EmailCollection::NewInstance($this->sFullValue);
+ if ($oEmailCollection && 0 < $oEmailCollection->Count())
+ {
+ $sResult = $oEmailCollection->ToString(true, false);
+ }
+ }
+
+ return $this->NameWithDelimitrom().$this->wordWrapHelper($sResult);
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsSubject()
+ {
+ return \strtolower(\MailSo\Mime\Enumerations\Header::SUBJECT) === \strtolower($this->Name());
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsParameterized()
+ {
+ return \in_array(\strtolower($this->sName), array(
+ \strtolower(\MailSo\Mime\Enumerations\Header::CONTENT_TYPE),
+ \strtolower(\MailSo\Mime\Enumerations\Header::CONTENT_DISPOSITION)
+ ));
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsEmail()
+ {
+ return \in_array(\strtolower($this->sName), array(
+ \strtolower(\MailSo\Mime\Enumerations\Header::FROM_),
+ \strtolower(\MailSo\Mime\Enumerations\Header::TO_),
+ \strtolower(\MailSo\Mime\Enumerations\Header::CC),
+ \strtolower(\MailSo\Mime\Enumerations\Header::BCC),
+ \strtolower(\MailSo\Mime\Enumerations\Header::REPLY_TO),
+ \strtolower(\MailSo\Mime\Enumerations\Header::RETURN_PATH),
+ \strtolower(\MailSo\Mime\Enumerations\Header::SENDER)
+ ));
+ }
+
+ /**
+ * @return string
+ */
+ public function ValueWithCharsetAutoDetect()
+ {
+ $sValue = $this->Value();
+ if (!\MailSo\Base\Utils::IsAscii($sValue) &&
+ 0 < \strlen($this->sEncodedValueForReparse) &&
+ !\MailSo\Base\Utils::IsAscii($this->sEncodedValueForReparse))
+ {
+ $sValueCharset = \MailSo\Base\Utils::CharsetDetect($this->sEncodedValueForReparse);
+ if (0 < \strlen($sValueCharset))
+ {
+ $this->SetParentCharset($sValueCharset);
+ $sValue = $this->Value();
+ }
+ }
+
+ return $sValue;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsReparsed()
+ {
+ return $this->IsEmail() || $this->IsSubject() || $this->IsParameterized();
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/HeaderCollection.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/HeaderCollection.php
new file mode 100644
index 0000000..f890b01
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/HeaderCollection.php
@@ -0,0 +1,480 @@
+sRawHeaders = '';
+ $this->sParentCharset = '';
+
+ if (0 < \strlen($sRawHeaders))
+ {
+ $this->Parse($sRawHeaders, $bStoreRawHeaders);
+ }
+ }
+
+ /**
+ * @param string $sRawHeaders = ''
+ * @param bool $bStoreRawHeaders = true
+ *
+ * @return \MailSo\Mime\HeaderCollection
+ */
+ public static function NewInstance($sRawHeaders = '', $bStoreRawHeaders = true)
+ {
+ return new self($sRawHeaders, $bStoreRawHeaders);
+ }
+
+ /**
+ * @param string $sName
+ * @param string $sValue
+ * @param bool $bToTop = false
+ *
+ * @return \MailSo\Mime\HeaderCollection
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function AddByName($sName, $sValue, $bToTop = false)
+ {
+ return $this->Add(Header::NewInstance($sName, $sValue), $bToTop);
+ }
+
+ /**
+ * @param string $sName
+ * @param string $sValue
+ * @param bool $bToTop = false
+ *
+ * @return \MailSo\Mime\HeaderCollection
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetByName($sName, $sValue, $bToTop = false)
+ {
+ return $this->RemoveByName($sName)->Add(Header::NewInstance($sName, $sValue), $bToTop);
+ }
+
+ /**
+ * @return \MailSo\Mime\Header | null
+ */
+ public function &GetByIndex($iIndex)
+ {
+ $mResult = null;
+ $mResult =& parent::GetByIndex($iIndex);
+ return $mResult;
+ }
+
+ /**
+ * @param string $sHeaderName
+ * @param bool $bCharsetAutoDetect = false
+ * @return string
+ */
+ public function ValueByName($sHeaderName, $bCharsetAutoDetect = false)
+ {
+ $oHeader = null;
+ $oHeader =& $this->GetByName($sHeaderName);
+ return (null !== $oHeader) ? ($bCharsetAutoDetect ? $oHeader->ValueWithCharsetAutoDetect() : $oHeader->Value()) : '';
+ }
+
+ /**
+ * @param string $sHeaderName
+ * @param bool $bCharsetAutoDetect = false
+ * @return array
+ */
+ public function ValuesByName($sHeaderName, $bCharsetAutoDetect = false)
+ {
+ $aResult = array();
+ $oHeader = null;
+
+ $sHeaderNameLower = \strtolower($sHeaderName);
+ $aHeaders =& $this->GetAsArray();
+ foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader)
+ {
+ if ($sHeaderNameLower === \strtolower($oHeader->Name()))
+ {
+ $aResult[] = $bCharsetAutoDetect ? $oHeader->ValueWithCharsetAutoDetect() : $oHeader->Value();
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sHeaderName
+ *
+ * @return \MailSo\Mime\HeaderCollection
+ */
+ public function RemoveByName($sHeaderName)
+ {
+ $aResult = $this->FilterList(function ($oHeader) use ($sHeaderName) {
+ return $oHeader && \strtolower($oHeader->Name()) !== \strtolower($sHeaderName);
+ });
+
+ return $this->SetAsArray($aResult);
+ }
+
+ /**
+ * @param string $sHeaderName
+ * @param bool $bCharsetAutoDetect = false
+ *
+ * @return \MailSo\Mime\EmailCollection|null
+ */
+ public function GetAsEmailCollection($sHeaderName, $bCharsetAutoDetect = false)
+ {
+ $oResult = null;
+ $sValue = $this->ValueByName($sHeaderName, $bCharsetAutoDetect);
+ if (0 < \strlen($sValue))
+ {
+ $oResult = \MailSo\Mime\EmailCollection::NewInstance($sValue);
+ }
+
+ return $oResult && 0 < $oResult->Count() ? $oResult : null;
+ }
+
+ /**
+ * @param string $sHeaderName
+ * @return \MailSo\Mime\ParameterCollection|null
+ */
+ public function ParametersByName($sHeaderName)
+ {
+ $oParameters = $oHeader = null;
+ $oHeader =& $this->GetByName($sHeaderName);
+ if ($oHeader)
+ {
+ $oParameters = $oHeader->Parameters();
+ }
+
+ return $oParameters;
+ }
+
+ /**
+ * @param string $sHeaderName
+ * @param string $sParamName
+ * @return string
+ */
+ public function ParameterValue($sHeaderName, $sParamName)
+ {
+ $oParameters = $this->ParametersByName($sHeaderName);
+ return (null !== $oParameters) ? $oParameters->ParameterValueByName($sParamName) : '';
+ }
+
+ /**
+ * @param string $sHeaderName
+ * @return \MailSo\Mime\Header | false
+ */
+ public function &GetByName($sHeaderName)
+ {
+ $oResult = $oHeader = null;
+
+ $sHeaderNameLower = \strtolower($sHeaderName);
+ $aHeaders =& $this->GetAsArray();
+ foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader)
+ {
+ if ($sHeaderNameLower === \strtolower($oHeader->Name()))
+ {
+ $oResult =& $oHeader;
+ break;
+ }
+ }
+
+ return $oResult;
+ }
+
+ /**
+ * @param array $aList
+ * @return \MailSo\Mime\HeaderCollection
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetAsArray($aList)
+ {
+ parent::SetAsArray($aList);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sParentCharset
+ * @return \MailSo\Mime\HeaderCollection
+ */
+ public function SetParentCharset($sParentCharset)
+ {
+ if (0 < \strlen($sParentCharset))
+ {
+ if ($this->sParentCharset !== $sParentCharset)
+ {
+ $oHeader = null;
+ $aHeaders =& $this->GetAsArray();
+
+ foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader)
+ {
+ $oHeader->SetParentCharset($sParentCharset);
+ }
+
+ $this->sParentCharset = $sParentCharset;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return void
+ */
+ public function Clear()
+ {
+ parent::Clear();
+
+ $this->sRawHeaders = '';
+ }
+
+ /**
+ * @param string $sRawHeaders
+ * @param bool $bStoreRawHeaders = false
+ * @param string $sParentCharset = ''
+ *
+ * @return \MailSo\Mime\HeaderCollection
+ */
+ public function Parse($sRawHeaders, $bStoreRawHeaders = false, $sParentCharset = '')
+ {
+ $this->Clear();
+
+ if ($bStoreRawHeaders)
+ {
+ $this->sRawHeaders = $sRawHeaders;
+ }
+
+ if (0 === \strlen($this->sParentCharset))
+ {
+ $this->sParentCharset = $sParentCharset;
+ }
+
+ $aHeaders = \explode("\n", \str_replace("\r", '', $sRawHeaders));
+
+ $sName = null;
+ $sValue = null;
+ foreach ($aHeaders as $sHeadersValue)
+ {
+ if (0 === strlen($sHeadersValue))
+ {
+ continue;
+ }
+
+ $sFirstChar = \substr($sHeadersValue, 0, 1);
+ if ($sFirstChar !== ' ' && $sFirstChar !== "\t" && false === \strpos($sHeadersValue, ':'))
+ {
+ continue;
+ }
+ else if (null !== $sName && ($sFirstChar === ' ' || $sFirstChar === "\t"))
+ {
+ $sValue = \is_null($sValue) ? '' : $sValue;
+
+ if ('?=' === \substr(\rtrim($sHeadersValue), -2))
+ {
+ $sHeadersValue = \rtrim($sHeadersValue);
+ }
+
+ if ('=?' === \substr(\ltrim($sHeadersValue), 0, 2))
+ {
+ $sHeadersValue = \ltrim($sHeadersValue);
+ }
+
+ if ('=?' === \substr($sHeadersValue, 0, 2))
+ {
+ $sValue .= $sHeadersValue;
+ }
+ else
+ {
+ $sValue .= "\n".$sHeadersValue;
+ }
+ }
+ else
+ {
+ if (null !== $sName)
+ {
+ $oHeader = Header::NewInstanceFromEncodedString($sName.': '.$sValue, $this->sParentCharset);
+ if ($oHeader)
+ {
+ $this->Add($oHeader);
+ }
+
+ $sName = null;
+ $sValue = null;
+ }
+
+ $aHeaderParts = \explode(':', $sHeadersValue, 2);
+ $sName = $aHeaderParts[0];
+ $sValue = isset($aHeaderParts[1]) ? $aHeaderParts[1] : '';
+
+ if ('?=' === \substr(\rtrim($sValue), -2))
+ {
+ $sValue = \rtrim($sValue);
+ }
+ }
+ }
+
+ if (null !== $sName)
+ {
+ $oHeader = Header::NewInstanceFromEncodedString($sName.': '.$sValue, $this->sParentCharset);
+ if ($oHeader)
+ {
+ $this->Add($oHeader);
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function DkimStatuses()
+ {
+ $aResult = array();
+
+ $aHeaders = $this->ValuesByName(\MailSo\Mime\Enumerations\Header::AUTHENTICATION_RESULTS);
+ if (\is_array($aHeaders) && 0 < \count($aHeaders))
+ {
+ foreach ($aHeaders as $sHeaderValue)
+ {
+ $sStatus = '';
+ $sHeader = '';
+ $sDkimLine = '';
+
+ $aMatch = array();
+
+ $sHeaderValue = \preg_replace('/[\r\n\t\s]+/', ' ', $sHeaderValue);
+
+ if (\preg_match('/dkim=[^;]+/i', $sHeaderValue, $aMatch) && !empty($aMatch[0]))
+ {
+ $sDkimLine = $aMatch[0];
+
+ $aMatch = array();
+ if (\preg_match('/dkim=([a-zA-Z0-9]+)/i', $sDkimLine, $aMatch) && !empty($aMatch[1]))
+ {
+ $sStatus = $aMatch[1];
+ }
+
+ $aMatch = array();
+ if (\preg_match('/header\.(d|i|from)=([^\s;]+)/i', $sDkimLine, $aMatch) && !empty($aMatch[2]))
+ {
+ $sHeader = \trim($aMatch[2]);
+ }
+
+ if (!empty($sStatus) && !empty($sHeader))
+ {
+ $aResult[] = array($sStatus, $sHeader, $sDkimLine);
+ }
+ }
+ }
+ }
+ else
+ {
+ // X-DKIM-Authentication-Results: signer="hostinger.com" status="pass"
+ $aHeaders = $this->ValuesByName(\MailSo\Mime\Enumerations\Header::X_DKIM_AUTHENTICATION_RESULTS);
+ if (\is_array($aHeaders) && 0 < \count($aHeaders))
+ {
+ foreach ($aHeaders as $sHeaderValue)
+ {
+ $sStatus = '';
+ $sHeader = '';
+
+ $aMatch = array();
+
+ $sHeaderValue = \preg_replace('/[\r\n\t\s]+/', ' ', $sHeaderValue);
+
+ if (\preg_match('/status[\s]?=[\s]?"([a-zA-Z0-9]+)"/i', $sHeaderValue, $aMatch) && !empty($aMatch[1]))
+ {
+ $sStatus = $aMatch[1];
+ }
+
+ if (\preg_match('/signer[\s]?=[\s]?"([^";]+)"/i', $sHeaderValue, $aMatch) && !empty($aMatch[1]))
+ {
+ $sHeader = \trim($aMatch[1]);
+ }
+
+ if (!empty($sStatus) && !empty($sHeader))
+ {
+ $aResult[] = array($sStatus, $sHeader, $sHeaderValue);
+ }
+ }
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @return int
+ */
+ public function PopulateEmailColectionByDkim($oEmails)
+ {
+ if ($oEmails && $oEmails instanceof \MailSo\Mime\EmailCollection)
+ {
+ $aDkimStatuses = $this->DkimStatuses();
+ if (\is_array($aDkimStatuses) && 0 < \count($aDkimStatuses))
+ {
+ $oEmails->ForeachList(function (/* @var $oItem \MailSo\Mime\Email */ $oItem) use ($aDkimStatuses) {
+ if ($oItem && $oItem instanceof \MailSo\Mime\Email)
+ {
+ $sEmail = $oItem->GetEmail();
+ foreach ($aDkimStatuses as $aDkimData)
+ {
+ if (isset($aDkimData[0], $aDkimData[1]) &&
+ $aDkimData[1] === \strstr($sEmail, $aDkimData[1]))
+ {
+ $oItem->SetDkimStatusAndValue($aDkimData[0], empty($aDkimData[2]) ? '' : $aDkimData[2]);
+ }
+ }
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function ToEncodedString()
+ {
+ $aResult = array();
+ $aHeaders =& $this->GetAsArray();
+ foreach ($aHeaders as /* @var $oHeader \MailSo\Mime\Header */ &$oHeader)
+ {
+ $aResult[] = $oHeader->EncodedValue();
+ }
+
+ return \implode(\MailSo\Mime\Enumerations\Constants::CRLF, $aResult);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Message.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Message.php
new file mode 100644
index 0000000..44dfa80
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Message.php
@@ -0,0 +1,937 @@
+aHeadersValue = array();
+ $this->aAlternativeParts = array();
+ $this->oAttachmentCollection = AttachmentCollection::NewInstance();
+ $this->bAddEmptyTextPart = true;
+ $this->bAddDefaultXMailer = true;
+ }
+
+ /**
+ * @return \MailSo\Mime\Message
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @return \MailSo\Mime\Message
+ */
+ public function DoesNotCreateEmptyTextPart()
+ {
+ $this->bAddEmptyTextPart = false;
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Mime\Message
+ */
+ public function DoesNotAddDefaultXMailer()
+ {
+ $this->bAddDefaultXMailer = false;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function MessageId()
+ {
+ $sResult = '';
+ if (!empty($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::MESSAGE_ID]))
+ {
+ $sResult = $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::MESSAGE_ID];
+ }
+ return $sResult;
+ }
+
+ /**
+ * @param string $sMessageId
+ *
+ * @return void
+ */
+ public function SetMessageId($sMessageId)
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::MESSAGE_ID] = $sMessageId;
+ }
+
+ /**
+ * @param string $sHostName = ''
+ *
+ * @return void
+ */
+ public function RegenerateMessageId($sHostName = '')
+ {
+ $this->SetMessageId($this->generateNewMessageId($sHostName));
+ }
+
+ /**
+ * @return \MailSo\Mime\AttachmentCollection
+ */
+ public function Attachments()
+ {
+ return $this->oAttachmentCollection;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetSubject()
+ {
+ return isset($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::SUBJECT]) ?
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::SUBJECT] : '';
+ }
+
+ /**
+ * @return \MailSo\Mime\Email|null
+ */
+ public function GetFrom()
+ {
+ $oResult = null;
+
+ if (isset($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::FROM_]) &&
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::FROM_] instanceof \MailSo\Mime\Email)
+ {
+ $oResult = $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::FROM_];
+ }
+
+ return $oResult;
+ }
+
+ /**
+ * @return \MailSo\Mime\EmailCollection
+ */
+ public function GetTo()
+ {
+ $oResult = \MailSo\Mime\EmailCollection::NewInstance();
+
+ if (isset($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::TO_]) &&
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::TO_] instanceof \MailSo\Mime\EmailCollection)
+ {
+ $oResult->MergeWithOtherCollection($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::TO_]);
+ }
+
+ return $oResult->Unique();
+ }
+
+ /**
+ * @return \MailSo\Mime\EmailCollection|null
+ */
+ public function GetBcc()
+ {
+ $oResult = null;
+
+ if (isset($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::BCC]) &&
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::BCC] instanceof \MailSo\Mime\EmailCollection)
+ {
+ $oResult = $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::BCC];
+ }
+
+ return $oResult ? $oResult->Unique() : null;
+ }
+
+ /**
+ * @return \MailSo\Mime\EmailCollection
+ */
+ public function GetRcpt()
+ {
+ $oResult = \MailSo\Mime\EmailCollection::NewInstance();
+
+ if (isset($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::TO_]) &&
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::TO_] instanceof \MailSo\Mime\EmailCollection)
+ {
+ $oResult->MergeWithOtherCollection($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::TO_]);
+ }
+
+ if (isset($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::CC]) &&
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::CC] instanceof \MailSo\Mime\EmailCollection)
+ {
+ $oResult->MergeWithOtherCollection($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::CC]);
+ }
+
+ if (isset($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::BCC]) &&
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::BCC] instanceof \MailSo\Mime\EmailCollection)
+ {
+ $oResult->MergeWithOtherCollection($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::BCC]);
+ }
+
+ return $oResult->Unique();
+ }
+
+ /**
+ * @param string $sHeaderName
+ * @param string $sValue
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetCustomHeader($sHeaderName, $sValue)
+ {
+ $sHeaderName = \trim($sHeaderName);
+ if (0 < \strlen($sHeaderName))
+ {
+ $this->aHeadersValue[$sHeaderName] = $sValue;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sSubject
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetSubject($sSubject)
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::SUBJECT] = $sSubject;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sInReplyTo
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetInReplyTo($sInReplyTo)
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::IN_REPLY_TO] = $sInReplyTo;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sReferences
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetReferences($sReferences)
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::REFERENCES] =
+ \MailSo\Base\Utils::StripSpaces($sReferences);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sEmail
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetReadReceipt($sEmail)
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::DISPOSITION_NOTIFICATION_TO] = $sEmail;
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::X_CONFIRM_READING_TO] = $sEmail;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sEmail
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetReadConfirmation($sEmail)
+ {
+ return $this->SetReadReceipt($sEmail);
+ }
+
+ /**
+ * @param int $iValue
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetPriority($iValue)
+ {
+ $sResult = '';
+ switch ($iValue)
+ {
+ case \MailSo\Mime\Enumerations\MessagePriority::HIGH:
+ $sResult = \MailSo\Mime\Enumerations\MessagePriority::HIGH.' (Highest)';
+ break;
+ case \MailSo\Mime\Enumerations\MessagePriority::NORMAL:
+ $sResult = \MailSo\Mime\Enumerations\MessagePriority::NORMAL.' (Normal)';
+ break;
+ case \MailSo\Mime\Enumerations\MessagePriority::LOW:
+ $sResult = \MailSo\Mime\Enumerations\MessagePriority::LOW.' (Lowest)';
+ break;
+ }
+
+ if (0 < \strlen($sResult))
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::X_PRIORITY] = $sResult;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param int $iValue
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetSensitivity($iValue)
+ {
+ $sResult = '';
+ switch ($iValue)
+ {
+ case \MailSo\Mime\Enumerations\Sensitivity::CONFIDENTIAL:
+ $sResult = 'Company-Confidential';
+ break;
+ case \MailSo\Mime\Enumerations\Sensitivity::PERSONAL:
+ $sResult = 'Personal';
+ break;
+ case \MailSo\Mime\Enumerations\Sensitivity::PRIVATE_:
+ $sResult = 'Private';
+ break;
+ }
+
+ if (0 < \strlen($sResult))
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::SENSITIVITY] = $sResult;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sXMailer
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetXMailer($sXMailer)
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::X_MAILER] = $sXMailer;
+
+ return $this;
+ }
+
+ /**
+ * @param \MailSo\Mime\Email $oEmail
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetFrom(\MailSo\Mime\Email $oEmail)
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::FROM_] = $oEmail;
+
+ return $this;
+ }
+
+ /**
+ * @param \MailSo\Mime\EmailCollection $oEmails
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetTo(\MailSo\Mime\EmailCollection $oEmails)
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::TO_] = $oEmails;
+
+ return $this;
+ }
+
+ /**
+ * @param int $iDateTime
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetDate($iDateTime)
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::DATE] = gmdate('r', $iDateTime);
+
+ return $this;
+ }
+
+ /**
+ * @param \MailSo\Mime\EmailCollection $oEmails
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetReplyTo(\MailSo\Mime\EmailCollection $oEmails)
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::REPLY_TO] = $oEmails;
+
+ return $this;
+ }
+
+ /**
+ * @param \MailSo\Mime\EmailCollection $oEmails
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetCc(\MailSo\Mime\EmailCollection $oEmails)
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::CC] = $oEmails;
+
+ return $this;
+ }
+
+ /**
+ * @param \MailSo\Mime\EmailCollection $oEmails
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetBcc(\MailSo\Mime\EmailCollection $oEmails)
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::BCC] = $oEmails;
+
+ return $this;
+ }
+
+ /**
+ * @param \MailSo\Mime\EmailCollection $oEmails
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetSender(\MailSo\Mime\EmailCollection $oEmails)
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::SENDER] = $oEmails;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sType
+ * @param string $sUid
+ * @param string $sFolder
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function SetDraftInfo($sType, $sUid, $sFolder)
+ {
+ $this->aHeadersValue[\MailSo\Mime\Enumerations\Header::X_DRAFT_INFO] = \MailSo\Mime\ParameterCollection::NewInstance()
+ ->Add(\MailSo\Mime\Parameter::NewInstance('type', $sType))
+ ->Add(\MailSo\Mime\Parameter::NewInstance('uid', $sUid))
+ ->Add(\MailSo\Mime\Parameter::NewInstance('folder', base64_encode($sFolder)))
+ ;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sPlain
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function AddPlain($sPlain)
+ {
+ return $this->AddAlternative(
+ \MailSo\Mime\Enumerations\MimeType::TEXT_PLAIN, trim($sPlain),
+ \MailSo\Base\Enumerations\Encoding::QUOTED_PRINTABLE_LOWER);
+ }
+ /**
+ * @param string $sHtml
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function AddHtml($sHtml)
+ {
+ return $this->AddAlternative(
+ \MailSo\Mime\Enumerations\MimeType::TEXT_HTML, trim($sHtml),
+ \MailSo\Base\Enumerations\Encoding::QUOTED_PRINTABLE_LOWER);
+ }
+
+ /**
+ * @param string $sHtmlOrPlainText
+ * @param bool $bIsHtml = false
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function AddText($sHtmlOrPlainText, $bIsHtml = false)
+ {
+ return $bIsHtml ? $this->AddHtml($sHtmlOrPlainText) : $this->AddPlain($sHtmlOrPlainText);
+ }
+
+ /**
+ * @param string $sContentType
+ * @param string|resource $mData
+ * @param string $sContentTransferEncoding = ''
+ * @param array $aCustomContentTypeParams = array()
+ *
+ * @return \MailSo\Mime\Message
+ */
+ public function AddAlternative($sContentType, $mData, $sContentTransferEncoding = '', $aCustomContentTypeParams = array())
+ {
+ $this->aAlternativeParts[] = array($sContentType, $mData, $sContentTransferEncoding, $aCustomContentTypeParams);
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ private function generateNewBoundary()
+ {
+ return '--='.\MailSo\Config::$BoundaryPrefix.
+ \rand(100, 999).'_'.rand(100000000, 999999999).'.'.\time();
+ }
+
+ /**
+ * @param string $sHostName = ''
+ *
+ * @return string
+ */
+ private function generateNewMessageId($sHostName = '')
+ {
+ if (0 === \strlen($sHostName))
+ {
+ $sHostName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '';
+ }
+
+ if (empty($sHostName) && \MailSo\Base\Utils::FunctionExistsAndEnabled('php_uname'))
+ {
+ $sHostName = \php_uname('n');
+ }
+
+ if (empty($sHostName))
+ {
+ $sHostName = 'localhost';
+ }
+
+ return '<'.
+ \MailSo\Base\Utils::Md5Rand($sHostName.
+ (\MailSo\Base\Utils::FunctionExistsAndEnabled('getmypid') ? @\getmypid() : '')).'@'.$sHostName.'>';
+ }
+
+ /**
+ * @param \MailSo\Mime\Attachment $oAttachment
+ *
+ * @return \MailSo\Mime\Part
+ */
+ private function createNewMessageAttachmentBody($oAttachment)
+ {
+ $oAttachmentPart = Part::NewInstance();
+
+ $sFileName = $oAttachment->FileName();
+ $sCID = $oAttachment->CID();
+ $sContentLocation = $oAttachment->ContentLocation();
+
+ $oContentTypeParameters = null;
+ $oContentDispositionParameters = null;
+
+ if (0 < strlen(trim($sFileName)))
+ {
+ $oContentTypeParameters =
+ ParameterCollection::NewInstance()->Add(Parameter::NewInstance(
+ \MailSo\Mime\Enumerations\Parameter::NAME, $sFileName));
+
+ $oContentDispositionParameters =
+ ParameterCollection::NewInstance()->Add(Parameter::NewInstance(
+ \MailSo\Mime\Enumerations\Parameter::FILENAME, $sFileName));
+ }
+
+ $oAttachmentPart->Headers->Add(
+ Header::NewInstance(\MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ $oAttachment->ContentType().';'.
+ (($oContentTypeParameters) ? ' '.$oContentTypeParameters->ToString() : '')
+ )
+ );
+
+ $oAttachmentPart->Headers->Add(
+ Header::NewInstance(\MailSo\Mime\Enumerations\Header::CONTENT_DISPOSITION,
+ ($oAttachment->IsInline() ? 'inline' : 'attachment').';'.
+ (($oContentDispositionParameters) ? ' '.$oContentDispositionParameters->ToString() : '')
+ )
+ );
+
+ if (0 < strlen($sCID))
+ {
+ $oAttachmentPart->Headers->Add(
+ Header::NewInstance(\MailSo\Mime\Enumerations\Header::CONTENT_ID, $sCID)
+ );
+ }
+
+ if (0 < strlen($sContentLocation))
+ {
+ $oAttachmentPart->Headers->Add(
+ Header::NewInstance(\MailSo\Mime\Enumerations\Header::CONTENT_LOCATION, $sContentLocation)
+ );
+ }
+
+ $oAttachmentPart->Body = $oAttachment->Resource();
+
+ if ('message/rfc822' !== strtolower($oAttachment->ContentType()))
+ {
+ $oAttachmentPart->Headers->Add(
+ Header::NewInstance(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TRANSFER_ENCODING,
+ \MailSo\Base\Enumerations\Encoding::BASE64_LOWER
+ )
+ );
+
+ if (is_resource($oAttachmentPart->Body))
+ {
+ if (!\MailSo\Base\StreamWrappers\Binary::IsStreamRemembed($oAttachmentPart->Body))
+ {
+ $oAttachmentPart->Body =
+ \MailSo\Base\StreamWrappers\Binary::CreateStream($oAttachmentPart->Body,
+ \MailSo\Base\StreamWrappers\Binary::GetInlineDecodeOrEncodeFunctionName(
+ \MailSo\Base\Enumerations\Encoding::BASE64, false));
+
+ \MailSo\Base\StreamWrappers\Binary::RememberStream($oAttachmentPart->Body);
+ }
+ }
+ }
+
+ return $oAttachmentPart;
+ }
+
+ /**
+ * @param array $aAlternativeData
+ *
+ * @return \MailSo\Mime\Part
+ */
+ private function createNewMessageAlternativePartBody($aAlternativeData)
+ {
+ $oAlternativePart = null;
+
+ if (is_array($aAlternativeData) && isset($aAlternativeData[0]))
+ {
+ $oAlternativePart = Part::NewInstance();
+ $oParameters = ParameterCollection::NewInstance();
+ $oParameters->Add(
+ Parameter::NewInstance(
+ \MailSo\Mime\Enumerations\Parameter::CHARSET,
+ \MailSo\Base\Enumerations\Charset::UTF_8)
+ );
+
+ if (isset($aAlternativeData[3]) && \is_array($aAlternativeData[3]) && 0 < \count($aAlternativeData[3]))
+ {
+ foreach ($aAlternativeData[3] as $sName => $sValue)
+ {
+ $oParameters->Add(Parameter::NewInstance($sName, $sValue));
+ }
+ }
+
+ $oAlternativePart->Headers->Add(
+ Header::NewInstance(\MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ $aAlternativeData[0].'; '.$oParameters->ToString())
+ );
+
+ $oAlternativePart->Body = null;
+ if (isset($aAlternativeData[1]))
+ {
+ if (is_resource($aAlternativeData[1]))
+ {
+ $oAlternativePart->Body = $aAlternativeData[1];
+ }
+ else if (is_string($aAlternativeData[1]) && 0 < strlen($aAlternativeData[1]))
+ {
+ $oAlternativePart->Body =
+ \MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString($aAlternativeData[1]);
+ }
+ }
+
+ if (isset($aAlternativeData[2]) && 0 < strlen($aAlternativeData[2]))
+ {
+ $oAlternativePart->Headers->Add(
+ Header::NewInstance(\MailSo\Mime\Enumerations\Header::CONTENT_TRANSFER_ENCODING,
+ $aAlternativeData[2]
+ )
+ );
+
+ if (is_resource($oAlternativePart->Body))
+ {
+ if (!\MailSo\Base\StreamWrappers\Binary::IsStreamRemembed($oAlternativePart->Body))
+ {
+ $oAlternativePart->Body =
+ \MailSo\Base\StreamWrappers\Binary::CreateStream($oAlternativePart->Body,
+ \MailSo\Base\StreamWrappers\Binary::GetInlineDecodeOrEncodeFunctionName(
+ $aAlternativeData[2], false));
+
+ \MailSo\Base\StreamWrappers\Binary::RememberStream($oAlternativePart->Body);
+ }
+ }
+ }
+
+ if (!is_resource($oAlternativePart->Body))
+ {
+ $oAlternativePart->Body =
+ \MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString('');
+ }
+ }
+
+ return $oAlternativePart;
+ }
+
+ /**
+ * @param \MailSo\Mime\Part $oPlainPart
+ * @param \MailSo\Mime\Part $oHtmlPart
+ *
+ * @return \MailSo\Mime\Part
+ */
+ private function createNewMessageSimpleOrAlternativeBody()
+ {
+ $oResultPart = null;
+ if (1 < count($this->aAlternativeParts))
+ {
+ $oResultPart = Part::NewInstance();
+
+ $oResultPart->Headers->Add(
+ Header::NewInstance(\MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ \MailSo\Mime\Enumerations\MimeType::MULTIPART_ALTERNATIVE.'; '.
+ ParameterCollection::NewInstance()->Add(
+ Parameter::NewInstance(
+ \MailSo\Mime\Enumerations\Parameter::BOUNDARY,
+ $this->generateNewBoundary())
+ )->ToString()
+ )
+ );
+
+ foreach ($this->aAlternativeParts as $aAlternativeData)
+ {
+ $oAlternativePart = $this->createNewMessageAlternativePartBody($aAlternativeData);
+ if ($oAlternativePart)
+ {
+ $oResultPart->SubParts->Add($oAlternativePart);
+ }
+
+ unset($oAlternativePart);
+ }
+
+ }
+ else if (1 === count($this->aAlternativeParts))
+ {
+ $oAlternativePart = $this->createNewMessageAlternativePartBody($this->aAlternativeParts[0]);
+ if ($oAlternativePart)
+ {
+ $oResultPart = $oAlternativePart;
+ }
+ }
+
+ if (!$oResultPart)
+ {
+ if ($this->bAddEmptyTextPart)
+ {
+ $oResultPart = $this->createNewMessageAlternativePartBody(array(
+ \MailSo\Mime\Enumerations\MimeType::TEXT_PLAIN, null
+ ));
+ }
+ else
+ {
+ $aAttachments = $this->oAttachmentCollection->CloneAsArray();
+ if (\is_array($aAttachments) && 1 === count($aAttachments) && isset($aAttachments[0]))
+ {
+ $this->oAttachmentCollection->Clear();
+
+ $oResultPart = $this->createNewMessageAlternativePartBody(array(
+ $aAttachments[0]->ContentType(), $aAttachments[0]->Resource(),
+ '', $aAttachments[0]->CustomContentTypeParams()
+ ));
+ }
+ }
+ }
+
+ return $oResultPart;
+ }
+
+ /**
+ * @param \MailSo\Mime\Part $oIncPart
+ *
+ * @return \MailSo\Mime\Part
+ */
+ private function createNewMessageRelatedBody($oIncPart)
+ {
+ $oResultPart = null;
+
+ $aAttachments = $this->oAttachmentCollection->LinkedAttachments();
+ if (0 < count($aAttachments))
+ {
+ $oResultPart = Part::NewInstance();
+
+ $oResultPart->Headers->Add(
+ Header::NewInstance(\MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ \MailSo\Mime\Enumerations\MimeType::MULTIPART_RELATED.'; '.
+ ParameterCollection::NewInstance()->Add(
+ Parameter::NewInstance(
+ \MailSo\Mime\Enumerations\Parameter::BOUNDARY,
+ $this->generateNewBoundary())
+ )->ToString()
+ )
+ );
+
+ $oResultPart->SubParts->Add($oIncPart);
+
+ foreach ($aAttachments as $oAttachment)
+ {
+ $oResultPart->SubParts->Add($this->createNewMessageAttachmentBody($oAttachment));
+ }
+ }
+ else
+ {
+ $oResultPart = $oIncPart;
+ }
+
+ return $oResultPart;
+ }
+
+ /**
+ * @param \MailSo\Mime\Part $oIncPart
+ *
+ * @return \MailSo\Mime\Part
+ */
+ private function createNewMessageMixedBody($oIncPart)
+ {
+ $oResultPart = null;
+
+ $aAttachments = $this->oAttachmentCollection->UnlinkedAttachments();
+ if (0 < count($aAttachments))
+ {
+ $oResultPart = Part::NewInstance();
+
+ $oResultPart->Headers->AddByName(\MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ \MailSo\Mime\Enumerations\MimeType::MULTIPART_MIXED.'; '.
+ ParameterCollection::NewInstance()->Add(
+ Parameter::NewInstance(
+ \MailSo\Mime\Enumerations\Parameter::BOUNDARY,
+ $this->generateNewBoundary())
+ )->ToString()
+ );
+
+ $oResultPart->SubParts->Add($oIncPart);
+
+ foreach ($aAttachments as $oAttachment)
+ {
+ $oResultPart->SubParts->Add($this->createNewMessageAttachmentBody($oAttachment));
+ }
+ }
+ else
+ {
+ $oResultPart = $oIncPart;
+ }
+
+ return $oResultPart;
+ }
+
+ /**
+ * @param \MailSo\Mime\Part $oIncPart
+ * @param bool $bWithoutBcc = false
+ *
+ * @return \MailSo\Mime\Part
+ */
+ private function setDefaultHeaders($oIncPart, $bWithoutBcc = false)
+ {
+ if (!isset($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::DATE]))
+ {
+ $oIncPart->Headers->SetByName(\MailSo\Mime\Enumerations\Header::DATE, \gmdate('r'), true);
+ }
+
+ if (!isset($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::MESSAGE_ID]))
+ {
+ $oIncPart->Headers->SetByName(\MailSo\Mime\Enumerations\Header::MESSAGE_ID, $this->generateNewMessageId(), true);
+ }
+
+ if (!isset($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::X_MAILER]) && $this->bAddDefaultXMailer)
+ {
+ $oIncPart->Headers->SetByName(\MailSo\Mime\Enumerations\Header::X_MAILER, \MailSo\Version::XMailer(), true);
+ }
+
+ if (!isset($this->aHeadersValue[\MailSo\Mime\Enumerations\Header::MIME_VERSION]))
+ {
+ $oIncPart->Headers->SetByName(\MailSo\Mime\Enumerations\Header::MIME_VERSION, '1.0', true);
+ }
+
+ foreach ($this->aHeadersValue as $sName => $mValue)
+ {
+ if (\is_object($mValue))
+ {
+ if ($mValue instanceof \MailSo\Mime\EmailCollection || $mValue instanceof \MailSo\Mime\Email ||
+ $mValue instanceof \MailSo\Mime\ParameterCollection)
+ {
+ $mValue = $mValue->ToString();
+ }
+ }
+
+ if (!($bWithoutBcc && \strtolower(\MailSo\Mime\Enumerations\Header::BCC) === \strtolower($sName)))
+ {
+ $oIncPart->Headers->SetByName($sName, (string) $mValue);
+ }
+ }
+
+ return $oIncPart;
+ }
+
+ /**
+ * @param bool $bWithoutBcc = false
+ *
+ * @return \MailSo\Mime\Part
+ */
+ public function ToPart($bWithoutBcc = false)
+ {
+ $oPart = $this->createNewMessageSimpleOrAlternativeBody();
+ $oPart = $this->createNewMessageRelatedBody($oPart);
+ $oPart = $this->createNewMessageMixedBody($oPart);
+ $oPart = $this->setDefaultHeaders($oPart, $bWithoutBcc);
+
+ return $oPart;
+ }
+
+ /**
+ * @param bool $bWithoutBcc = false
+ *
+ * @return resource
+ */
+ public function ToStream($bWithoutBcc = false)
+ {
+ return $this->ToPart($bWithoutBcc)->ToStream();
+ }
+
+ /**
+ * @param bool $bWithoutBcc = false
+ *
+ * @return string
+ */
+ public function ToString($bWithoutBcc = false)
+ {
+ return \stream_get_contents($this->ToStream($bWithoutBcc));
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Parameter.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Parameter.php
new file mode 100644
index 0000000..487a256
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Parameter.php
@@ -0,0 +1,141 @@
+sName = $sName;
+ $this->sValue = $sValue;
+ }
+
+ /**
+ * @param string $sName
+ * @param string $sValue = ''
+ *
+ * @return \MailSo\Mime\Parameter
+ */
+ public static function NewInstance($sName, $sValue = '')
+ {
+ return new self($sName, $sValue);
+ }
+
+ /**
+ * @param string $sName
+ * @param string $sValue = ''
+ *
+ * @return \MailSo\Mime\Parameter
+ */
+ public static function CreateFromParameterLine($sRawParam)
+ {
+ $oParameter = self::NewInstance('');
+ return $oParameter->Parse($sRawParam);
+ }
+
+ /**
+ * @return \MailSo\Mime\Parameter
+ */
+ public function Reset()
+ {
+ $this->sName = '';
+ $this->sValue = '';
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function Name()
+ {
+ return $this->sName;
+ }
+
+ /**
+ * @return string
+ */
+ public function Value()
+ {
+ return $this->sValue;
+ }
+
+ /**
+ * @param string $sRawParam
+ * @param string $sSeparator = '='
+ *
+ * @return \MailSo\Mime\Parameter
+ */
+ public function Parse($sRawParam, $sSeparator = '=')
+ {
+ $this->Reset();
+
+ $aParts = explode($sSeparator, $sRawParam, 2);
+
+ $this->sName = trim(trim($aParts[0]), '"\'');
+ if (2 === count($aParts))
+ {
+ $this->sValue = trim(trim($aParts[1]), '"\'');
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param bool $bConvertSpecialsName = false
+ *
+ * @return string
+ */
+ public function ToString($bConvertSpecialsName = false)
+ {
+ $sResult = '';
+ if (0 < strlen($this->sName))
+ {
+ $sResult = $this->sName.'=';
+ if ($bConvertSpecialsName && in_array(strtolower($this->sName), array(
+ strtolower(\MailSo\Mime\Enumerations\Parameter::NAME),
+ strtolower(\MailSo\Mime\Enumerations\Parameter::FILENAME)
+ )))
+ {
+ $sResult .= '"'.\MailSo\Base\Utils::EncodeUnencodedValue(
+ \MailSo\Base\Enumerations\Encoding::BASE64_SHORT,
+ $this->sValue).'"';
+ }
+ else
+ {
+ $sResult .= '"'.$this->sValue.'"';
+ }
+ }
+
+ return $sResult;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/ParameterCollection.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/ParameterCollection.php
new file mode 100644
index 0000000..52b7dd3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/ParameterCollection.php
@@ -0,0 +1,213 @@
+Parse($sRawParams);
+ }
+ }
+
+ /**
+ * @param string $sRawParams = ''
+ *
+ * @return \MailSo\Mime\ParameterCollection
+ */
+ public static function NewInstance($sRawParams = '')
+ {
+ return new self($sRawParams);
+ }
+
+ /**
+ * @return \MailSo\Mime\Parameter|null
+ */
+ public function &GetByIndex($iIndex)
+ {
+ $mResult = null;
+ $mResult =& parent::GetByIndex($iIndex);
+ return $mResult;
+ }
+
+ /**
+ * @param array $aList
+ *
+ * @return \MailSo\Mime\ParameterCollection
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetAsArray($aList)
+ {
+ parent::SetAsArray($aList);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sName
+ *
+ * @return string
+ */
+ public function ParameterValueByName($sName)
+ {
+ $sResult = '';
+ $sName = \trim($sName);
+
+ $aParams =& $this->GetAsArray();
+ foreach ($aParams as /* @var $oParam \MailSo\Mime\ParameterCollection */ $oParam)
+ {
+ if (\strtolower($sName) === \strtolower($oParam->Name()))
+ {
+ $sResult = $oParam->Value();
+ break;
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sRawParams
+ *
+ * @return \MailSo\Mime\ParameterCollection
+ */
+ public function Parse($sRawParams)
+ {
+ $this->Clear();
+
+ $aDataToParse = \explode(';', $sRawParams);
+
+ foreach ($aDataToParse as $sParam)
+ {
+ $this->Add(Parameter::CreateFromParameterLine($sParam));
+ }
+
+ $this->reParseParameters();
+
+ return $this;
+ }
+
+ /**
+ * @param bool $bConvertSpecialsName = false
+ *
+ * @return string
+ */
+ public function ToString($bConvertSpecialsName = false)
+ {
+ $aResult = array();
+ $aParams =& $this->GetAsArray();
+ foreach ($aParams as /* @var $oParam \MailSo\Mime\Parameter */ $oParam)
+ {
+ $sLine = $oParam->ToString($bConvertSpecialsName);
+ if (0 < \strlen($sLine))
+ {
+ $aResult[] = $sLine;
+ }
+ }
+
+ return 0 < \count($aResult) ? \implode('; ', $aResult) : '';
+ }
+
+ /**
+ * @return void
+ */
+ private function reParseParameters()
+ {
+ $aDataToReParse = $this->CloneAsArray();
+ $sCharset = \MailSo\Base\Enumerations\Charset::UTF_8;
+
+ $this->Clear();
+
+ $aPreParams = array();
+ foreach ($aDataToReParse as /* @var $oParam \MailSo\Mime\Parameter */ $oParam)
+ {
+ $aMatch = array();
+ $sParamName = $oParam->Name();
+
+ if (\preg_match('/([^\*]+)\*([\d]{1,2})\*/', $sParamName, $aMatch) && isset($aMatch[1], $aMatch[2])
+ && 0 < \strlen($aMatch[1]) && \is_numeric($aMatch[2]))
+ {
+ if (!isset($aPreParams[$aMatch[1]]))
+ {
+ $aPreParams[$aMatch[1]] = array();
+ }
+
+ $sValue = $oParam->Value();
+
+ if (false !== \strpos($sValue, "''"))
+ {
+ $aValueParts = \explode("''", $sValue, 2);
+ if (\is_array($aValueParts) && 2 === \count($aValueParts) && 0 < \strlen($aValueParts[1]))
+ {
+ $sCharset = $aValueParts[0];
+ $sValue = $aValueParts[1];
+ }
+ }
+
+ $aPreParams[$aMatch[1]][(int) $aMatch[2]] = $sValue;
+ }
+ else if (\preg_match('/([^\*]+)\*/', $sParamName, $aMatch) && isset($aMatch[1]))
+ {
+ if (!isset($aPreParams[$aMatch[1]]))
+ {
+ $aPreParams[$aMatch[1]] = array();
+ }
+
+ $sValue = $oParam->Value();
+ if (false !== \strpos($sValue, "''"))
+ {
+ $aValueParts = \explode("''", $sValue, 2);
+ if (\is_array($aValueParts) && 2 === \count($aValueParts) && 0 < \strlen($aValueParts[1]))
+ {
+ $sCharset = $aValueParts[0];
+ $sValue = $aValueParts[1];
+ }
+ }
+
+ $aPreParams[$aMatch[1]][0] = $sValue;
+ }
+ else
+ {
+ $this->Add($oParam);
+ }
+ }
+
+ foreach ($aPreParams as $sName => $aValues)
+ {
+ ksort($aValues);
+ $sResult = \implode(\array_values($aValues));
+ $sResult = \urldecode($sResult);
+
+ if (0 < \strlen($sCharset))
+ {
+ $sResult = \MailSo\Base\Utils::ConvertEncoding($sResult,
+ $sCharset, \MailSo\Base\Enumerations\Charset::UTF_8);
+ }
+
+ $this->Add(Parameter::NewInstance($sName, $sResult));
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Parser/ParserEmpty.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Parser/ParserEmpty.php
new file mode 100644
index 0000000..2349ade
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Parser/ParserEmpty.php
@@ -0,0 +1,81 @@
+oCurrentMime = $oPart;
+ }
+
+ /**
+ * @param string $sBuffer
+ *
+ * @return void
+ */
+ public function WriteBody($sBuffer)
+ {
+ if (null === $this->oCurrentMime->Body)
+ {
+ $this->oCurrentMime->Body = \MailSo\Base\ResourceRegistry::CreateMemoryResource();
+ }
+
+ if (\is_resource($this->oCurrentMime->Body))
+ {
+ \fwrite($this->oCurrentMime->Body, $sBuffer);
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Part.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Part.php
new file mode 100644
index 0000000..2e19af0
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/Part.php
@@ -0,0 +1,665 @@
+iParseBuffer = \MailSo\Mime\Part::DEFAUL_BUFFER;
+ $this->Reset();
+ }
+
+ /**
+ * @return \MailSo\Mime\Part
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @return \MailSo\Mime\Part
+ */
+ public function Reset()
+ {
+ \MailSo\Base\ResourceRegistry::CloseMemoryResource($this->Body);
+ $this->Body = null;
+
+ $this->Headers = HeaderCollection::NewInstance();
+ $this->SubParts = PartCollection::NewInstance();
+ $this->LineParts = array();
+ $this->sBoundary = '';
+ $this->sParentCharset = \MailSo\Base\Enumerations\Charset::ISO_8859_1;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function Boundary()
+ {
+ return $this->sBoundary;
+ }
+
+ /**
+ * @return string
+ */
+ public function ParentCharset()
+ {
+ return (0 < \strlen($this->sCharset)) ? $this->sParentCharset : self::$DefaultCharset;
+ }
+
+ /**
+ * @param string $sParentCharset
+ * @return \MailSo\Mime\Part
+ */
+ public function SetParentCharset($sParentCharset)
+ {
+ $this->sParentCharset = $sParentCharset;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sBoundary
+ * @return \MailSo\Mime\Part
+ */
+ public function SetBoundary($sBoundary)
+ {
+ $this->sBoundary = $sBoundary;
+
+ return $this;
+ }
+
+ /**
+ * @param int $iParseBuffer
+ * @return \MailSo\Mime\Part
+ */
+ public function SetParseBuffer($iParseBuffer)
+ {
+ $this->iParseBuffer = $iParseBuffer;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function HeaderCharset()
+ {
+ return ($this->Headers) ? trim(strtolower($this->Headers->ParameterValue(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ \MailSo\Mime\Enumerations\Parameter::CHARSET))) : '';
+ }
+
+ /**
+ * @return string
+ */
+ public function HeaderBoundary()
+ {
+ return ($this->Headers) ? trim($this->Headers->ParameterValue(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ \MailSo\Mime\Enumerations\Parameter::BOUNDARY)) : '';
+ }
+
+ /**
+ * @return string
+ */
+ public function ContentType()
+ {
+ return ($this->Headers) ?
+ trim(strtolower($this->Headers->ValueByName(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE))) : '';
+ }
+
+ /**
+ * @return string
+ */
+ public function ContentTransferEncoding()
+ {
+ return ($this->Headers) ?
+ trim(strtolower($this->Headers->ValueByName(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TRANSFER_ENCODING))) : '';
+ }
+
+ /**
+ * @return string
+ */
+ public function ContentID()
+ {
+ return ($this->Headers) ? trim($this->Headers->ValueByName(
+ \MailSo\Mime\Enumerations\Header::CONTENT_ID)) : '';
+ }
+
+ /**
+ * @return string
+ */
+ public function ContentLocation()
+ {
+ return ($this->Headers) ? trim($this->Headers->ValueByName(
+ \MailSo\Mime\Enumerations\Header::CONTENT_LOCATION)) : '';
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsFlowedFormat()
+ {
+ $bResult = false;
+ if ($this->Headers)
+ {
+ $bResult = 'flowed' === \trim(\strtolower($this->Headers->ParameterValue(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ \MailSo\Mime\Enumerations\Parameter::FORMAT)));
+
+ if ($bResult && \in_array(\strtolower($this->MailEncodingName()), array('base64', 'quoted-printable')))
+ {
+ $bResult = false;
+ }
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function FileName()
+ {
+ $sResult = '';
+ if ($this->Headers)
+ {
+ $sResult = trim($this->Headers->ParameterValue(
+ \MailSo\Mime\Enumerations\Header::CONTENT_DISPOSITION,
+ \MailSo\Mime\Enumerations\Parameter::FILENAME));
+
+ if (0 === strlen($sResult))
+ {
+ $sResult = trim($this->Headers->ParameterValue(
+ \MailSo\Mime\Enumerations\Header::CONTENT_TYPE,
+ \MailSo\Mime\Enumerations\Parameter::NAME));
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sFileName
+ * @return \MailSo\Mime\Part
+ */
+ public function ParseFromFile($sFileName)
+ {
+ $rStreamHandle = (@file_exists($sFileName)) ? @fopen($sFileName, 'rb') : false;
+ if (is_resource($rStreamHandle))
+ {
+ $this->ParseFromStream($rStreamHandle);
+
+ if (is_resource($rStreamHandle))
+ {
+ fclose($rStreamHandle);
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sRawMessage
+ * @return \MailSo\Mime\Part
+ */
+ public function ParseFromString($sRawMessage)
+ {
+ $rStreamHandle = (0 < strlen($sRawMessage)) ?
+ \MailSo\Base\ResourceRegistry::CreateMemoryResource() : false;
+
+ if (is_resource($rStreamHandle))
+ {
+ fwrite($rStreamHandle, $sRawMessage);
+ unset($sRawMessage);
+ fseek($rStreamHandle, 0);
+
+ $this->ParseFromStream($rStreamHandle);
+
+ \MailSo\Base\ResourceRegistry::CloseMemoryResource($rStreamHandle);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param resource $rStreamHandle
+ * @return \MailSo\Mime\Part
+ */
+ public function ParseFromStream($rStreamHandle)
+ {
+ $this->Reset();
+
+ $oParserClass = new \MailSo\Mime\Parser\ParserMemory();
+
+ $oMimePart = null;
+ $bIsOef = false;
+ $iOffset = 0;
+ $sBuffer = '';
+ $sPrevBuffer = '';
+ $aBoundaryStack = array();
+
+
+ $oParserClass->StartParse($this);
+
+ $this->LineParts[] =& $this;
+ $this->ParseFromStreamRecursion($rStreamHandle, $oParserClass, $iOffset,
+ $sPrevBuffer, $sBuffer, $aBoundaryStack, $bIsOef);
+
+ $sFirstNotNullCharset = null;
+ foreach ($this->LineParts as /* @var $oMimePart \MailSo\Mime\Part */ &$oMimePart)
+ {
+ $sCharset = $oMimePart->HeaderCharset();
+ if (0 < strlen($sCharset))
+ {
+ $sFirstNotNullCharset = $sCharset;
+ break;
+ }
+ }
+
+ $sForceCharset = self::$ForceCharset;
+ if (0 < strlen($sForceCharset))
+ {
+ foreach ($this->LineParts as /* @var $oMimePart \MailSo\Mime\Part */ &$oMimePart)
+ {
+ $oMimePart->SetParentCharset($sForceCharset);
+ $oMimePart->Headers->SetParentCharset($sForceCharset);
+ }
+ }
+ else
+ {
+ $sFirstNotNullCharset = (null !== $sFirstNotNullCharset)
+ ? $sFirstNotNullCharset : self::$DefaultCharset;
+
+ foreach ($this->LineParts as /* @var $oMimePart \MailSo\Mime\Part */ &$oMimePart)
+ {
+ $sHeaderCharset = $oMimePart->HeaderCharset();
+ $oMimePart->SetParentCharset((0 < strlen($sHeaderCharset)) ? $sHeaderCharset : $sFirstNotNullCharset);
+ $oMimePart->Headers->SetParentCharset($sHeaderCharset);
+ }
+ }
+
+ $oParserClass->EndParse($this);
+
+ return $this;
+ }
+
+ /**
+ * @param resource $rStreamHandle
+ * @return \MailSo\Mime\Part
+ */
+ public function ParseFromStreamRecursion($rStreamHandle, &$oCallbackClass, &$iOffset,
+ &$sPrevBuffer, &$sBuffer, &$aBoundaryStack, &$bIsOef, $bNotFirstRead = false)
+ {
+ $oCallbackClass->StartParseMimePart($this);
+
+ $iPos = 0;
+ $iParsePosition = self::POS_HEADERS;
+ $sCurrentBoundary = '';
+ $bIsBoundaryCheck = false;
+ $aHeadersLines = array();
+ while (true)
+ {
+ if (!$bNotFirstRead)
+ {
+ $sPrevBuffer = $sBuffer;
+ $sBuffer = '';
+ }
+
+ if (!$bIsOef && !feof($rStreamHandle))
+ {
+ if (!$bNotFirstRead)
+ {
+ $sBuffer = @fread($rStreamHandle, $this->iParseBuffer);
+ if (false === $sBuffer)
+ {
+ break;
+ }
+
+ $oCallbackClass->ReadBuffer($sBuffer);
+ }
+ else
+ {
+ $bNotFirstRead = false;
+ }
+ }
+ else if ($bIsOef && 0 === strlen($sBuffer))
+ {
+ break;
+ }
+ else
+ {
+ $bIsOef = true;
+ }
+
+ while (true)
+ {
+ $sCurrentLine = $sPrevBuffer.$sBuffer;
+ if (self::POS_HEADERS === $iParsePosition)
+ {
+ $iEndLen = 4;
+ $iPos = strpos($sCurrentLine, "\r\n\r\n", $iOffset);
+ if (false === $iPos)
+ {
+ $iEndLen = 2;
+ $iPos = strpos($sCurrentLine, "\n\n", $iOffset);
+ }
+
+ if (false !== $iPos)
+ {
+ $aHeadersLines[] = substr($sCurrentLine, $iOffset, $iPos + $iEndLen - $iOffset);
+
+ $this->Headers->Parse(implode($aHeadersLines))->SetParentCharset($this->HeaderCharset());
+ $aHeadersLines = array();
+
+ $oCallbackClass->InitMimePartHeader();
+
+ $sBoundary = $this->HeaderBoundary();
+ if (0 < strlen($sBoundary))
+ {
+ $sBoundary = '--'.$sBoundary;
+ $sCurrentBoundary = $sBoundary;
+ array_unshift($aBoundaryStack, $sBoundary);
+ }
+
+ $iOffset = $iPos + $iEndLen;
+ $iParsePosition = self::POS_BODY;
+ continue;
+ }
+ else
+ {
+ $iBufferLen = strlen($sPrevBuffer);
+ if ($iBufferLen > $iOffset)
+ {
+ $aHeadersLines[] = substr($sPrevBuffer, $iOffset);
+ $iOffset = 0;
+ }
+ else
+ {
+ $iOffset -= $iBufferLen;
+ }
+ break;
+ }
+ }
+ else if (self::POS_BODY === $iParsePosition)
+ {
+ $iPos = false;
+ $sBoundaryLen = 0;
+ $bIsBoundaryEnd = false;
+ $bCurrentPartBody = false;
+ $bIsBoundaryCheck = 0 < count($aBoundaryStack);
+
+ foreach ($aBoundaryStack as $sKey => $sBoundary)
+ {
+ if (false !== ($iPos = strpos($sCurrentLine, $sBoundary, $iOffset)))
+ {
+ if ($sCurrentBoundary === $sBoundary)
+ {
+ $bCurrentPartBody = true;
+ }
+
+ $sBoundaryLen = strlen($sBoundary);
+ if ('--' === substr($sCurrentLine, $iPos + $sBoundaryLen, 2))
+ {
+ $sBoundaryLen += 2;
+ $bIsBoundaryEnd = true;
+ unset($aBoundaryStack[$sKey]);
+ $sCurrentBoundary = (isset($aBoundaryStack[$sKey + 1]))
+ ? $aBoundaryStack[$sKey + 1] : '';
+ }
+
+ break;
+ }
+ }
+
+ if (false !== $iPos)
+ {
+ $oCallbackClass->WriteBody(substr($sCurrentLine, $iOffset, $iPos - $iOffset));
+ $iOffset = $iPos;
+
+ if ($bCurrentPartBody)
+ {
+ $iParsePosition = self::POS_SUBPARTS;
+ continue;
+ }
+
+ $oCallbackClass->EndParseMimePart($this);
+ return true;
+ }
+ else
+ {
+ $iBufferLen = strlen($sPrevBuffer);
+ if ($iBufferLen > $iOffset)
+ {
+ $oCallbackClass->WriteBody(substr($sPrevBuffer, $iOffset));
+ $iOffset = 0;
+ }
+ else
+ {
+ $iOffset -= $iBufferLen;
+ }
+ break;
+ }
+ }
+ else if (self::POS_SUBPARTS === $iParsePosition)
+ {
+ $iPos = false;
+ $sBoundaryLen = 0;
+ $bIsBoundaryEnd = false;
+ $bCurrentPartBody = false;
+ $bIsBoundaryCheck = 0 < count($aBoundaryStack);
+
+ foreach ($aBoundaryStack as $sKey => $sBoundary)
+ {
+ if (false !== ($iPos = strpos($sCurrentLine, $sBoundary, $iOffset)))
+ {
+ if ($sCurrentBoundary === $sBoundary)
+ {
+ $bCurrentPartBody = true;
+ }
+
+ $sBoundaryLen = strlen($sBoundary);
+ if ('--' === substr($sCurrentLine, $iPos + $sBoundaryLen, 2))
+ {
+ $sBoundaryLen += 2;
+ $bIsBoundaryEnd = true;
+ unset($aBoundaryStack[$sKey]);
+ $sCurrentBoundary = (isset($aBoundaryStack[$sKey + 1]))
+ ? $aBoundaryStack[$sKey + 1] : '';
+ }
+ break;
+ }
+ }
+
+ if (false !== $iPos && $bCurrentPartBody)
+ {
+ $iOffset = $iPos + $sBoundaryLen;
+
+ $oSubPart = self::NewInstance();
+
+ $oSubPart
+ ->SetParseBuffer($this->iParseBuffer)
+ ->ParseFromStreamRecursion($rStreamHandle, $oCallbackClass,
+ $iOffset, $sPrevBuffer, $sBuffer, $aBoundaryStack, $bIsOef, true);
+
+ $this->SubParts->Add($oSubPart);
+ $this->LineParts[] =& $oSubPart;
+ //$iParsePosition = self::POS_HEADERS;
+ unset($oSubPart);
+ }
+ else
+ {
+ $oCallbackClass->EndParseMimePart($this);
+ return true;
+ }
+ }
+ }
+ }
+
+ if (0 < strlen($sPrevBuffer))
+ {
+ if (self::POS_HEADERS === $iParsePosition)
+ {
+ $aHeadersLines[] = ($iOffset < strlen($sPrevBuffer))
+ ? substr($sPrevBuffer, $iOffset)
+ : $sPrevBuffer;
+
+ $this->Headers->Parse(implode($aHeadersLines))->SetParentCharset($this->HeaderCharset());
+ $aHeadersLines = array();
+
+ $oCallbackClass->InitMimePartHeader();
+ }
+ else if (self::POS_BODY === $iParsePosition)
+ {
+ if (!$bIsBoundaryCheck)
+ {
+ $oCallbackClass->WriteBody(($iOffset < strlen($sPrevBuffer))
+ ? substr($sPrevBuffer, $iOffset) : $sPrevBuffer);
+ }
+ }
+ }
+ else
+ {
+ if (self::POS_HEADERS === $iParsePosition && 0 < count($aHeadersLines))
+ {
+ $this->Headers->Parse(implode($aHeadersLines))->SetParentCharset($this->HeaderCharset());
+ $aHeadersLines = array();
+
+ $oCallbackClass->InitMimePartHeader();
+ }
+ }
+
+ $oCallbackClass->EndParseMimePart($this);
+
+ return $this;
+ }
+
+ /**
+ * @return resorce
+ */
+ public function Rewind()
+ {
+ if ($this->Body && \is_resource($this->Body))
+ {
+ $aMeta = \stream_get_meta_data($this->Body);
+ if (isset($aMeta['seekable']) && $aMeta['seekable'])
+ {
+ \rewind($this->Body);
+ }
+ }
+ }
+
+ /**
+ * @return resorce
+ */
+ public function ToStream()
+ {
+ $this->Rewind();
+
+ $aSubStreams = array(
+
+ $this->Headers->ToEncodedString().
+ \MailSo\Mime\Enumerations\Constants::CRLF.
+ \MailSo\Mime\Enumerations\Constants::CRLF,
+
+ null === $this->Body ? '' : $this->Body,
+
+ \MailSo\Mime\Enumerations\Constants::CRLF
+ );
+
+ if (0 < $this->SubParts->Count())
+ {
+ $sBoundary = $this->HeaderBoundary();
+ if (0 < strlen($sBoundary))
+ {
+ $aSubStreams[] = '--'.$sBoundary.\MailSo\Mime\Enumerations\Constants::CRLF;
+
+ $rSubPartsStream = $this->SubParts->ToStream($sBoundary);
+ if (is_resource($rSubPartsStream))
+ {
+ $aSubStreams[] = $rSubPartsStream;
+ }
+
+ $aSubStreams[] = \MailSo\Mime\Enumerations\Constants::CRLF.
+ '--'.$sBoundary.'--'.\MailSo\Mime\Enumerations\Constants::CRLF;
+ }
+ }
+
+ return \MailSo\Base\StreamWrappers\SubStreams::CreateStream($aSubStreams);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/PartCollection.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/PartCollection.php
new file mode 100644
index 0000000..d3c53ca
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Mime/PartCollection.php
@@ -0,0 +1,65 @@
+GetAsArray();
+ foreach ($aParts as /* @var $oPart \MailSo\Mime\Part */ &$oPart)
+ {
+ if (0 < count($aResult))
+ {
+ $aResult[] = \MailSo\Mime\Enumerations\Constants::CRLF.
+ '--'.$sBoundary.\MailSo\Mime\Enumerations\Constants::CRLF;
+ }
+
+ $aResult[] = $oPart->ToStream();
+ }
+
+ return \MailSo\Base\StreamWrappers\SubStreams::CreateStream($aResult);
+ }
+
+ return $rResult;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Net/Enumerations/ConnectionSecurityType.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Net/Enumerations/ConnectionSecurityType.php
new file mode 100644
index 0000000..fed485d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Net/Enumerations/ConnectionSecurityType.php
@@ -0,0 +1,70 @@
+sSocketMessage = $sSocketMessage;
+ $this->iSocketCode = $iSocketCode;
+ }
+
+ /**
+ * @return string
+ */
+ public function getSocketMessage()
+ {
+ return $this->sSocketMessage;
+ }
+
+ /**
+ * @return int
+ */
+ public function getSocketCode()
+ {
+ return $this->iSocketCode;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Net/Exceptions/SocketConnectionDoesNotAvailableException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Net/Exceptions/SocketConnectionDoesNotAvailableException.php
new file mode 100644
index 0000000..b406b3d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Net/Exceptions/SocketConnectionDoesNotAvailableException.php
@@ -0,0 +1,19 @@
+rConnect = null;
+ $this->bUnreadBuffer = false;
+ $this->bRunningCallback = false;
+ $this->oLogger = null;
+
+ $this->__AUTOLOGOUT__ = true;
+
+ $this->sResponseBuffer = '';
+
+ $this->iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::NONE;
+ $this->sConnectedHost = '';
+ $this->iConnectedPort = 0;
+
+ $this->bSecure = false;
+
+ $this->iConnectTimeOut = 10;
+ $this->iSocketTimeOut = 10;
+
+ $this->Clear();
+ }
+
+ /**
+ * @return void
+ */
+ public function __destruct()
+ {
+ try
+ {
+ if ($this->__AUTOLOGOUT__)
+ {
+ $this->LogoutAndDisconnect();
+ }
+ else
+ {
+ $this->Disconnect();
+ }
+ }
+ catch (\Exception $oException) {}
+ }
+
+ /**
+ * @return void
+ */
+ public function Clear()
+ {
+ $this->sResponseBuffer = '';
+
+ $this->sConnectedHost = '';
+ $this->iConnectedPort = 0;
+
+ $this->iStartConnectTime = 0;
+ $this->bSecure = false;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetConnectedHost()
+ {
+ return $this->sConnectedHost;
+ }
+
+ /**
+ * @return int
+ */
+ public function GetConnectedPort()
+ {
+ return $this->iConnectedPort;
+ }
+
+ /**
+ * @param int $iConnectTimeOut = 10
+ * @param int $iSocketTimeOut = 10
+ *
+ * @return void
+ */
+ public function SetTimeOuts($iConnectTimeOut = 10, $iSocketTimeOut = 10)
+ {
+ $this->iConnectTimeOut = 5 < $iConnectTimeOut ? $iConnectTimeOut : 5;
+ $this->iSocketTimeOut = 5 < $iSocketTimeOut ? $iSocketTimeOut : 5;
+ }
+
+ /**
+ * @return resource|null
+ */
+ public function ConnectionResource()
+ {
+ return $this->rConnect;
+ }
+
+ /**
+ * @param int $iErrNo
+ * @param string $sErrStr
+ * @param string $sErrFile
+ * @param int $iErrLine
+ *
+ * @return bool
+ */
+ public function capturePhpErrorWithException($iErrNo, $sErrStr, $sErrFile, $iErrLine)
+ {
+ throw new \MailSo\Base\Exceptions\Exception($sErrStr, $iErrNo);
+ }
+
+ /**
+ * @param string $sServerName
+ * @param int $iPort
+ * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
+ * @param bool $bVerifySsl = false
+ * @param bool $bAllowSelfSigned = true
+ *
+ * @return void
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\SocketAlreadyConnectedException
+ * @throws \MailSo\Net\Exceptions\SocketCanNotConnectToHostException
+ */
+ public function Connect($sServerName, $iPort,
+ $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT,
+ $bVerifySsl = false, $bAllowSelfSigned = true)
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sServerName, true) || !\MailSo\Base\Validator::PortInt($iPort))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ if ($this->IsConnected())
+ {
+ $this->writeLogException(
+ new Exceptions\SocketAlreadyConnectedException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $sServerName = \trim($sServerName);
+
+ $sErrorStr = '';
+ $iErrorNo = 0;
+
+ $this->sConnectedHost = $sServerName;
+ $this->iConnectedPort = $iPort;
+ $this->iSecurityType = $iSecurityType;
+ $this->bSecure = \MailSo\Net\Enumerations\ConnectionSecurityType::UseSSL(
+ $this->iConnectedPort, $this->iSecurityType);
+
+ if (!\preg_match('/^[a-z0-9._]{2,8}:\/\//i', $this->sConnectedHost))
+ {
+ $this->sConnectedHost = ($this->bSecure ? 'ssl://' : 'tcp://').$this->sConnectedHost;
+// $this->sConnectedHost = ($this->bSecure ? 'ssl://' : '').$this->sConnectedHost;
+ }
+
+ if (!$this->bSecure && \MailSo\Net\Enumerations\ConnectionSecurityType::SSL === $this->iSecurityType)
+ {
+ $this->writeLogException(
+ new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('SSL isn\'t supported: ('.\implode(', ', \stream_get_transports()).')'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->iStartConnectTime = \microtime(true);
+ $this->writeLog('Start connection to "'.$this->sConnectedHost.':'.$this->iConnectedPort.'"',
+ \MailSo\Log\Enumerations\Type::NOTE);
+
+// $this->rConnect = @\fsockopen($this->sConnectedHost, $this->iConnectedPort,
+// $iErrorNo, $sErrorStr, $this->iConnectTimeOut);
+
+ $bVerifySsl = !!$bVerifySsl;
+ $bAllowSelfSigned = $bVerifySsl ? !!$bAllowSelfSigned : true;
+
+ $aStreamContextSettings = array(
+ 'ssl' => array(
+ 'verify_host' => $bVerifySsl,
+ 'verify_peer' => $bVerifySsl,
+ 'verify_peer_name' => $bVerifySsl,
+ 'allow_self_signed' => $bAllowSelfSigned
+ )
+ );
+
+ \MailSo\Hooks::Run('Net.NetClient.StreamContextSettings/Filter', array(&$aStreamContextSettings));
+
+ $rStreamContext = \stream_context_create($aStreamContextSettings);
+
+ \set_error_handler(array(&$this, 'capturePhpErrorWithException'));
+
+ try
+ {
+ $this->rConnect = \stream_socket_client($this->sConnectedHost.':'.$this->iConnectedPort,
+ $iErrorNo, $sErrorStr, $this->iConnectTimeOut, STREAM_CLIENT_CONNECT, $rStreamContext);
+ }
+ catch (\Exception $oExc)
+ {
+ $sErrorStr = $oExc->getMessage();
+ $iErrorNo = $oExc->getCode();
+ }
+
+ \restore_error_handler();
+
+ $this->writeLog('Connected ('.(\is_resource($this->rConnect) ? 'success' : 'unsuccess').')',
+ \MailSo\Log\Enumerations\Type::NOTE);
+
+ if (!\is_resource($this->rConnect))
+ {
+ $this->writeLogException(
+ new Exceptions\SocketCanNotConnectToHostException(
+ \MailSo\Base\Utils::ConvertSystemString($sErrorStr), (int) $iErrorNo,
+ 'Can\'t connect to host "'.$this->sConnectedHost.':'.$this->iConnectedPort.'"'
+ ), \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+
+ $this->writeLog((\microtime(true) - $this->iStartConnectTime).' (raw connection)',
+ \MailSo\Log\Enumerations\Type::TIME);
+
+ if ($this->rConnect)
+ {
+ if (\MailSo\Base\Utils::FunctionExistsAndEnabled('stream_set_timeout'))
+ {
+ @\stream_set_timeout($this->rConnect, $this->iSocketTimeOut);
+ }
+ }
+ }
+
+ public function EnableCrypto()
+ {
+ $bError = true;
+ if (\is_resource($this->rConnect) &&
+ \MailSo\Base\Utils::FunctionExistsAndEnabled('stream_socket_enable_crypto'))
+ {
+ switch (true)
+ {
+ case defined('STREAM_CRYPTO_METHOD_ANY_CLIENT') &&
+ @\stream_socket_enable_crypto($this->rConnect, true, STREAM_CRYPTO_METHOD_ANY_CLIENT):
+ case @\stream_socket_enable_crypto($this->rConnect, true, STREAM_CRYPTO_METHOD_TLS_CLIENT):
+ case @\stream_socket_enable_crypto($this->rConnect, true, STREAM_CRYPTO_METHOD_SSLv23_CLIENT):
+ $bError = false;
+ break;
+ }
+ }
+
+ if ($bError)
+ {
+ $this->writeLogException(
+ new \MailSo\Net\Exceptions\Exception('Cannot enable STARTTLS.'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+ }
+
+ /**
+ * @return void
+ */
+ public function Disconnect()
+ {
+ if (\is_resource($this->rConnect))
+ {
+ $bResult = \fclose($this->rConnect);
+
+ $this->writeLog('Disconnected from "'.$this->sConnectedHost.':'.$this->iConnectedPort.'" ('.
+ (($bResult) ? 'success' : 'unsuccess').')', \MailSo\Log\Enumerations\Type::NOTE);
+
+ if (0 !== $this->iStartConnectTime)
+ {
+ $this->writeLog((\microtime(true) - $this->iStartConnectTime).' (net session)',
+ \MailSo\Log\Enumerations\Type::TIME);
+
+ $this->iStartConnectTime = 0;
+ }
+
+ $this->rConnect = null;
+ }
+ }
+
+ /**
+ * @retun void
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ public function LogoutAndDisconnect()
+ {
+ if (\method_exists($this, 'Logout') && !$this->bUnreadBuffer && !$this->bRunningCallback)
+ {
+ $this->Logout();
+ }
+
+ $this->Disconnect();
+ }
+
+ /**
+ * @param bool $bThrowExceptionOnFalse = false
+ *
+ * @return bool
+ */
+ public function IsConnected($bThrowExceptionOnFalse = false)
+ {
+ $bResult = \is_resource($this->rConnect);
+ if (!$bResult && $bThrowExceptionOnFalse)
+ {
+ $this->writeLogException(
+ new Exceptions\SocketConnectionDoesNotAvailableException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @return void
+ *
+ * @throws \MailSo\Net\Exceptions\SocketConnectionDoesNotAvailableException
+ */
+ public function IsConnectedWithException()
+ {
+ $this->IsConnected(true);
+ }
+
+ /**
+ * @return array|bool
+ */
+ public function StreamContextParams()
+ {
+ return \is_resource($this->rConnect) && \MailSo\Base\Utils::FunctionExistsAndEnabled('stream_context_get_options')
+ ? \stream_context_get_params($this->rConnect) : false;
+ }
+
+ /**
+ * @param string $sRaw
+ * @param bool $bWriteToLog = true
+ * @param string $sFakeRaw = ''
+ *
+ * @return void
+ *
+ * @throws \MailSo\Net\Exceptions\SocketConnectionDoesNotAvailableException
+ * @throws \MailSo\Net\Exceptions\SocketWriteException
+ */
+ protected function sendRaw($sRaw, $bWriteToLog = true, $sFakeRaw = '')
+ {
+ if ($this->bUnreadBuffer)
+ {
+ $this->writeLogException(
+ new Exceptions\SocketUnreadBufferException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $bFake = 0 < \strlen($sFakeRaw);
+ $sRaw .= "\r\n";
+
+ if ($this->oLogger && $this->oLogger->IsShowSecter())
+ {
+ $bFake = false;
+ }
+
+ if ($bFake)
+ {
+ $sFakeRaw .= "\r\n";
+ }
+
+ $mResult = @\fwrite($this->rConnect, $sRaw);
+ if (false === $mResult)
+ {
+ $this->IsConnected(true);
+
+ $this->writeLogException(
+ new Exceptions\SocketWriteException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+ else
+ {
+ \MailSo\Base\Loader::IncStatistic('NetWrite', $mResult);
+
+ if ($bWriteToLog)
+ {
+ $this->writeLogWithCrlf('> '.($bFake ? $sFakeRaw : $sRaw), //.' ['.$iWriteSize.']',
+ $bFake ? \MailSo\Log\Enumerations\Type::SECURE : \MailSo\Log\Enumerations\Type::INFO);
+ }
+ }
+ }
+
+ /**
+ * @param mixed $mReadLen = null
+ * @param bool $bForceLogin = false
+ *
+ * @return void
+ *
+ * @throws \MailSo\Net\Exceptions\SocketConnectionDoesNotAvailableException
+ * @throws \MailSo\Net\Exceptions\SocketReadException
+ */
+ protected function getNextBuffer($mReadLen = null, $bForceLogin = false)
+ {
+ if (null === $mReadLen)
+ {
+ $this->sResponseBuffer = @\fgets($this->rConnect);
+ }
+ else
+ {
+ $this->sResponseBuffer = '';
+ $iRead = $mReadLen;
+ while (0 < $iRead)
+ {
+ $sAddRead = @\fread($this->rConnect, $iRead);
+ if (false === $sAddRead)
+ {
+ $this->sResponseBuffer = false;
+ break;
+ }
+
+ $this->sResponseBuffer .= $sAddRead;
+ $iRead -= \strlen($sAddRead);
+ }
+ }
+
+ if (false === $this->sResponseBuffer)
+ {
+ $this->IsConnected(true);
+ $this->bUnreadBuffer = true;
+
+ $aSocketStatus = @\stream_get_meta_data($this->rConnect);
+ if (isset($aSocketStatus['timed_out']) && $aSocketStatus['timed_out'])
+ {
+ $this->writeLogException(
+ new Exceptions\SocketReadTimeoutException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+ else
+ {
+ $this->writeLog('Stream Meta: '.
+ \print_r($aSocketStatus, true), \MailSo\Log\Enumerations\Type::ERROR);
+
+ $this->writeLogException(
+ new Exceptions\SocketReadException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+ }
+ else
+ {
+ $iReadedLen = \strlen($this->sResponseBuffer);
+ if (null === $mReadLen || $bForceLogin)
+ {
+ $iLimit = 5000; // 5KB
+ if ($iLimit < $iReadedLen)
+ {
+ $this->writeLogWithCrlf('[cutted:'.$iReadedLen.'] < '.\substr($this->sResponseBuffer, 0, $iLimit).'...',
+ \MailSo\Log\Enumerations\Type::INFO);
+ }
+ else
+ {
+ $this->writeLogWithCrlf('< '.$this->sResponseBuffer, //.' ['.$iReadedLen.']',
+ \MailSo\Log\Enumerations\Type::INFO);
+ }
+ }
+ else
+ {
+ $this->writeLog('Received '.$iReadedLen.'/'.$mReadLen.' bytes.',
+ \MailSo\Log\Enumerations\Type::INFO);
+ }
+
+ \MailSo\Base\Loader::IncStatistic('NetRead', $iReadedLen);
+ }
+ }
+
+ /**
+ * @return string
+ */
+ protected function getLogName()
+ {
+ return 'NET';
+ }
+
+ /**
+ * @param string $sDesc
+ * @param int $iDescType = \MailSo\Log\Enumerations\Type::INFO
+ *
+ * @return void
+ */
+ protected function writeLog($sDesc, $iDescType = \MailSo\Log\Enumerations\Type::INFO, $bDiplayCrLf = false)
+ {
+ if ($this->oLogger)
+ {
+ $this->oLogger->Write($sDesc, $iDescType, $this->getLogName(), true, $bDiplayCrLf);
+ }
+ }
+
+ /**
+ * @param string $sDesc
+ * @param int $iDescType = \MailSo\Log\Enumerations\Type::INFO
+ *
+ * @return void
+ */
+ protected function writeLogWithCrlf($sDesc, $iDescType = \MailSo\Log\Enumerations\Type::INFO)
+ {
+ $this->writeLog($sDesc, $iDescType, true);
+ }
+
+ /**
+ * @param \Exception $oException
+ * @param int $iDescType = \MailSo\Log\Enumerations\Type::NOTICE
+ * @param bool $bThrowException = false
+ *
+ * @return void
+ */
+ protected function writeLogException($oException,
+ $iDescType = \MailSo\Log\Enumerations\Type::NOTICE, $bThrowException = false)
+ {
+ if ($this->oLogger)
+ {
+ if ($oException instanceof Exceptions\SocketCanNotConnectToHostException)
+ {
+ $this->oLogger->Write('Socket: ['.$oException->getSocketCode().'] '.$oException->getSocketMessage(), $iDescType, $this->getLogName());
+ }
+
+ $this->oLogger->WriteException($oException, $iDescType, $this->getLogName());
+ }
+
+ if ($bThrowException)
+ {
+ throw $oException;
+ }
+ }
+
+ /**
+ * @param \MailSo\Log\Logger $oLogger
+ *
+ * @return void
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetLogger($oLogger)
+ {
+ if (!($oLogger instanceof \MailSo\Log\Logger))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $this->oLogger = $oLogger;
+ }
+
+ /**
+ * @return \MailSo\Log\Logger|null
+ */
+ public function Logger()
+ {
+ return $this->oLogger;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Pop3/Exceptions/Exception.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Pop3/Exceptions/Exception.php
new file mode 100644
index 0000000..0cc582d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Pop3/Exceptions/Exception.php
@@ -0,0 +1,19 @@
+aResponses = $aResponses;
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function GetResponses()
+ {
+ return $this->aResponses;
+ }
+
+ /**
+ * @return \MailSo\Pop3\Response | null
+ */
+ public function GetLastResponse()
+ {
+ return 0 < count($this->aResponses) ? $this->aResponses[count($this->aResponses) - 1] : null;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Pop3/Exceptions/RuntimeException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Pop3/Exceptions/RuntimeException.php
new file mode 100644
index 0000000..047c32a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Pop3/Exceptions/RuntimeException.php
@@ -0,0 +1,19 @@
+bIsLoggined = false;
+ $this->iRequestTime = 0;
+ $this->aCapa = null;
+ $this->sLastMessage = '';
+ }
+
+ /**
+ * @return \MailSo\Pop3\Pop3Client
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @param string $sServerName
+ * @param int $iPort = 110
+ * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
+ * @param bool $bVerifySsl = false
+ * @param bool $bAllowSelfSigned = null
+ *
+ * @return \MailSo\Pop3\Pop3Client
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Pop3\Exceptions\ResponseException
+ */
+ public function Connect($sServerName, $iPort = 110,
+ $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT,
+ $bVerifySsl = false, $bAllowSelfSigned = null)
+ {
+ $this->iRequestTime = microtime(true);
+
+ parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned);
+
+ $this->validateResponse();
+
+ if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS(
+ in_array('STLS', $this->Capa()), $this->iSecurityType))
+ {
+ $this->sendRequestWithCheck('STLS');
+ $this->EnableCrypto();
+
+ $this->aCapa = null;
+ }
+ else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType)
+ {
+ $this->writeLogException(
+ new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sLogin = ''
+ * @param string $sPassword = ''
+ *
+ * @return \MailSo\Pop3\Pop3Client
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Pop3\Exceptions\ResponseException
+ */
+ public function Login($sLogin, $sPassword)
+ {
+ if ($this->bIsLoggined)
+ {
+ $this->writeLogException(
+ new Exceptions\RuntimeException('Already authenticated for this session'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $sLogin = trim($sLogin);
+ $sPassword = $sPassword;
+
+ try
+ {
+ $this->sendRequestWithCheck('USER', $sLogin);
+ $this->sendRequestWithCheck('PASS', $sPassword);
+ }
+ catch (\MailSo\Pop3\Exceptions\NegativeResponseException $oException)
+ {
+ $this->writeLogException(
+ new \MailSo\Pop3\Exceptions\LoginBadCredentialsException(
+ $oException->GetResponses(), '', 0, $oException),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+
+ $this->bIsLoggined = true;
+ $this->aCapa = null;
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsLoggined()
+ {
+ return $this->IsConnected() && $this->bIsLoggined;
+ }
+
+ /**
+ * @return \MailSo\Pop3\Pop3Client
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Pop3\Exceptions\Exception
+ */
+ public function Noop()
+ {
+ $this->sendRequestWithCheck('NOOP');
+ return $this;
+ }
+
+ /**
+ * @return array [MessagesCount, Size]
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Pop3\Exceptions\Exception
+ */
+ public function Status()
+ {
+ $this->sendRequestWithCheck('STAT');
+
+ $iMessageCount = $iSize = 0;
+ sscanf($this->sLastMessage, '%d %d', $iMessageCount, $iSize);
+
+ return array((int) $iMessageCount, (int) $iSize);
+ }
+
+ /**
+ * @return \MailSo\Pop3\Pop3Client
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Pop3\Exceptions\Exception
+ */
+ public function Capa()
+ {
+ if (null === $this->aCapa)
+ {
+ $this->sendRequestWithCheck('CAPA');
+
+ $this->aCapa = array_filter(explode("\n", $this->readMultilineResponse()), function (&$sCapa) {
+ return 0 < strlen(trim($sCapa));
+ });
+
+ $this->aCapa = array_map('trim', $this->aCapa);
+ }
+
+ return $this->aCapa;
+ }
+
+ /**
+ * @return \MailSo\Pop3\Pop3Client
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Pop3\Exceptions\Exception
+ */
+ public function Logout()
+ {
+ if ($this->bIsLoggined)
+ {
+ $this->sendRequestWithCheck('QUIT');
+ }
+
+ $this->bIsLoggined = false;
+ return $this;
+ }
+
+ /**
+ * @param string $sCommand
+ * @param string $sAddToCommand = ''
+ *
+ * @return \MailSo\Pop3\Pop3Client
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ protected function sendRequest($sCommand, $sAddToCommand = '')
+ {
+ if (0 === strlen(trim($sCommand)))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->IsConnected(true);
+
+ $sCommand = trim($sCommand);
+ $sRealCommand = $sCommand.(0 === strlen($sAddToCommand) ? '' : ' '.$sAddToCommand);
+
+ $sFakeCommand = '';
+ $sFakeAddToCommand = $this->secureRequestParams($sCommand, $sAddToCommand);
+ if (0 < strlen($sFakeAddToCommand))
+ {
+ $sFakeCommand = $sCommand.' '.$sFakeAddToCommand;
+ }
+
+ $this->iRequestTime = microtime(true);
+ $this->sendRaw($sRealCommand, true, $sFakeCommand);
+ return $this;
+ }
+
+ /**
+ * @param string $sCommand
+ * @param string $sAddToCommand
+ *
+ * @return string
+ */
+ private function secureRequestParams($sCommand, $sAddToCommand)
+ {
+ $sResult = null;
+ if (0 < strlen($sAddToCommand))
+ {
+ switch ($sCommand)
+ {
+ case 'PASS':
+ $sResult = '********';
+ break;
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sCommand
+ * @param string $sAddToCommand = ''
+ *
+ * @return \MailSo\Pop3\Pop3Client
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Pop3\Exceptions\Exception
+ */
+ private function sendRequestWithCheck($sCommand, $sAddToCommand = '')
+ {
+ $this->sendRequest($sCommand, $sAddToCommand);
+ return $this->validateResponse();
+ }
+
+ /**
+ * @return string
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Pop3\Exceptions\ResponseException
+ */
+ private function validateResponse()
+ {
+ $this->getNextBuffer();
+
+ $this->sLastMessage = '';
+ $sStatus = $sMessage = '';
+ $sBuffer = trim($this->sResponseBuffer);
+ $sStatus = $sBuffer;
+ if (false !== strpos($sBuffer, ' '))
+ {
+ list($sStatus, $sMessage) = explode(' ', $sBuffer, 2);
+ }
+
+ $this->sLastMessage = $sMessage;
+
+ if ($sStatus != '+OK')
+ {
+ $this->writeLogException(
+ new Exceptions\NegativeResponseException(),
+ \MailSo\Log\Enumerations\Type::WARNING, true);
+ }
+
+ $this->writeLog((microtime(true) - $this->iRequestTime),
+ \MailSo\Log\Enumerations\Type::TIME);
+ }
+
+ /**
+ * @return string
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ private function readMultilineResponse()
+ {
+ $this->iRequestTime = microtime(true);
+
+ $sResult = '';
+ do
+ {
+ $this->getNextBuffer();
+ if (0 === strpos($this->sResponseBuffer, '.'))
+ {
+ $sResult .= substr($this->sResponseBuffer, 1);
+ }
+ else
+ {
+ $sResult .= $this->sResponseBuffer;
+ }
+ }
+ while ('.' !== rtrim($this->sResponseBuffer, "\r\n"));
+
+ $this->writeLog((microtime(true) - $this->iRequestTime),
+ \MailSo\Log\Enumerations\Type::TIME);
+
+ return $sResult;
+ }
+
+ /**
+ * @return string
+ */
+ protected function getLogName()
+ {
+ return 'POP3';
+ }
+
+ /**
+ * @param \MailSo\Log\Logger $oLogger
+ * @return \MailSo\Pop3\Pop3Client
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetLogger($oLogger)
+ {
+ parent::SetLogger($oLogger);
+
+ return $this;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Poppassd/Exceptions/Exception.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Poppassd/Exceptions/Exception.php
new file mode 100644
index 0000000..76097ff
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Poppassd/Exceptions/Exception.php
@@ -0,0 +1,19 @@
+aResponses = $aResponses;
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function GetResponses()
+ {
+ return $this->aResponses;
+ }
+
+ /**
+ * @return \MailSo\Poppassd\Response | null
+ */
+ public function GetLastResponse()
+ {
+ return 0 < \count($this->aResponses) ? $this->aResponses[count($this->aResponses) - 1] : null;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Poppassd/Exceptions/RuntimeException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Poppassd/Exceptions/RuntimeException.php
new file mode 100644
index 0000000..5b94cb3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Poppassd/Exceptions/RuntimeException.php
@@ -0,0 +1,19 @@
+bIsLoggined = false;
+ $this->iRequestTime = 0;
+
+ parent::__construct();
+ }
+
+ /**
+ * @return \MailSo\Poppassd\PoppassdClient
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @param string $sServerName
+ * @param int $iPort = 106
+ * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
+ * @param bool $bVerifySsl = false
+ * @param bool $bAllowSelfSigned = true
+ *
+ * @return \MailSo\Poppassd\PoppassdClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Poppassd\Exceptions\ResponseException
+ */
+ public function Connect($sServerName, $iPort = 106,
+ $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT,
+ $bVerifySsl = false, $bAllowSelfSigned = true)
+ {
+ $this->iRequestTime = \microtime(true);
+
+ parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned);
+
+ $this->validateResponse();
+
+ return $this;
+ }
+
+ /**
+ * @param string $sLogin = ''
+ * @param string $sPassword = ''
+ *
+ * @return \MailSo\Poppassd\PoppassdClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Poppassd\Exceptions\ResponseException
+ */
+ public function Login($sLogin, $sPassword)
+ {
+ if ($this->bIsLoggined)
+ {
+ $this->writeLogException(
+ new Exceptions\RuntimeException('Already authenticated for this session'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $sLogin = \trim($sLogin);
+ $sPassword = $sPassword;
+
+ try
+ {
+ $this->sendRequestWithCheck('user', $sLogin, true);
+ $this->sendRequestWithCheck('pass', $sPassword, true);
+ }
+ catch (\MailSo\Poppassd\Exceptions\NegativeResponseException $oException)
+ {
+ $this->writeLogException(
+ new \MailSo\Poppassd\Exceptions\LoginBadCredentialsException(
+ $oException->GetResponses(), '', 0, $oException),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+
+ $this->bIsLoggined = true;
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Poppassd\PoppassdClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Poppassd\Exceptions\Exception
+ */
+ public function Logout()
+ {
+ if ($this->bIsLoggined)
+ {
+ $this->sendRequestWithCheck('quit');
+ }
+
+ $this->bIsLoggined = false;
+ return $this;
+ }
+
+ /**
+ * @param string $sNewPassword
+ *
+ * @return \MailSo\Poppassd\PoppassdClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Poppassd\Exceptions\Exception
+ */
+ public function NewPass($sNewPassword)
+ {
+ if ($this->bIsLoggined)
+ {
+ $this->sendRequestWithCheck('newpass', $sNewPassword);
+ }
+ else
+ {
+ $this->writeLogException(
+ new \MailSo\Poppassd\Exceptions\RuntimeException('Required login'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sCommand
+ * @param string $sAddToCommand
+ *
+ * @return string
+ */
+ private function secureRequestParams($sCommand, $sAddToCommand)
+ {
+ $sResult = null;
+ if (0 < \strlen($sAddToCommand))
+ {
+ switch (\strtolower($sCommand))
+ {
+ case 'pass':
+ case 'newpass':
+ $sResult = '********';
+ break;
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sCommand
+ * @param string $sAddToCommand = ''
+ *
+ * @return \MailSo\Poppassd\PoppassdClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ private function sendRequest($sCommand, $sAddToCommand = '')
+ {
+ if (0 === \strlen(\trim($sCommand)))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->IsConnected(true);
+
+ $sCommand = \trim($sCommand);
+ $sRealCommand = $sCommand.(0 === \strlen($sAddToCommand) ? '' : ' '.$sAddToCommand);
+
+ $sFakeCommand = '';
+ $sFakeAddToCommand = $this->secureRequestParams($sCommand, $sAddToCommand);
+ if (0 < \strlen($sFakeAddToCommand))
+ {
+ $sFakeCommand = $sCommand.' '.$sFakeAddToCommand;
+ }
+
+ $this->iRequestTime = \microtime(true);
+ $this->sendRaw($sRealCommand, true, $sFakeCommand);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sCommand
+ * @param string $sAddToCommand = ''
+ * @param bool $bAuthRequestValidate = false
+ *
+ * @return \MailSo\Poppassd\PoppassdClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Poppassd\Exceptions\Exception
+ */
+ private function sendRequestWithCheck($sCommand, $sAddToCommand = '', $bAuthRequestValidate = false)
+ {
+ $this->sendRequest($sCommand, $sAddToCommand);
+ $this->validateResponse($bAuthRequestValidate);
+
+ return $this;
+ }
+
+ /**
+ * @param bool $bAuthRequestValidate = false
+ *
+ * @return \MailSo\Poppassd\PoppassdClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Poppassd\Exceptions\ResponseException
+ */
+ private function validateResponse($bAuthRequestValidate = false)
+ {
+ $this->getNextBuffer();
+
+ $bResult = false;
+ if ($bAuthRequestValidate)
+ {
+ $bResult = (bool) \preg_match('/^[23]\d\d/', trim($this->sResponseBuffer));
+ }
+ else
+ {
+ $bResult = (bool) \preg_match('/^2\d\d/', \trim($this->sResponseBuffer));
+ }
+
+ if (!$bResult)
+ {
+ // POP3 validation hack
+ $bResult = '+OK ' === \substr(\trim($this->sResponseBuffer), 0, 4);
+ }
+
+ if (!$bResult)
+ {
+ $this->writeLogException(
+ new Exceptions\NegativeResponseException(),
+ \MailSo\Log\Enumerations\Type::WARNING, true);
+ }
+
+ $this->writeLog((\microtime(true) - $this->iRequestTime),
+ \MailSo\Log\Enumerations\Type::TIME);
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ protected function getLogName()
+ {
+ return 'POPPASSD';
+ }
+
+ /**
+ * @param \MailSo\Log\Logger $oLogger
+ *
+ * @return \MailSo\Poppassd\PoppassdClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetLogger($oLogger)
+ {
+ parent::SetLogger($oLogger);
+
+ return $this;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Sieve/Exceptions/Exception.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Sieve/Exceptions/Exception.php
new file mode 100644
index 0000000..0740485
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Sieve/Exceptions/Exception.php
@@ -0,0 +1,19 @@
+aResponses = $aResponses;
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function GetResponses()
+ {
+ return $this->aResponses;
+ }
+
+ /**
+ * @return \MailSo\Sieve\Response | null
+ */
+ public function GetLastResponse()
+ {
+ return 0 < count($this->aResponses) ? $this->aResponses[count($this->aResponses) - 1] : null;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Sieve/Exceptions/RuntimeException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Sieve/Exceptions/RuntimeException.php
new file mode 100644
index 0000000..8704e46
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Sieve/Exceptions/RuntimeException.php
@@ -0,0 +1,19 @@
+bIsLoggined = false;
+ $this->iRequestTime = 0;
+ $this->aCapa = array();
+ $this->aModules = array();
+ }
+
+ /**
+ * @return \MailSo\Sieve\ManageSieveClient
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @param string $sCapa
+ *
+ * @return bool
+ */
+ public function IsSupported($sCapa)
+ {
+ return isset($this->aCapa[\strtoupper($sCapa)]);
+ }
+
+ /**
+ * @param string $sModule
+ *
+ * @return bool
+ */
+ public function IsModuleSupported($sModule)
+ {
+ return $this->IsSupported('SIEVE') && \in_array(\strtolower(\trim($sModule)), $this->aModules);
+ }
+
+ /**
+ * @return array
+ */
+ public function Modules()
+ {
+ return $this->aModules;
+ }
+
+ /**
+ * @param string $sAuth
+ *
+ * @return bool
+ */
+ public function IsAuthSupported($sAuth)
+ {
+ return $this->IsSupported('SASL') && \in_array(\strtoupper($sAuth), $this->aAuth);
+ }
+
+ /**
+ * @param string $sServerName
+ * @param int $iPort
+ * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
+ * @param bool $bVerifySsl = false
+ * @param bool $bAllowSelfSigned = true
+ *
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Sieve\Exceptions\ResponseException
+ */
+ public function Connect($sServerName, $iPort,
+ $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT,
+ $bVerifySsl = false, $bAllowSelfSigned = true)
+ {
+ $this->iRequestTime = \microtime(true);
+
+ parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned);
+
+ $mResponse = $this->parseResponse();
+ $this->validateResponse($mResponse);
+ $this->parseStartupResponse($mResponse);
+
+ if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS(
+ $this->IsSupported('STARTTLS'), $this->iSecurityType))
+ {
+ $this->sendRequestWithCheck('STARTTLS');
+ $this->EnableCrypto();
+
+ $mResponse = $this->parseResponse();
+ $this->validateResponse($mResponse);
+ $this->parseStartupResponse($mResponse);
+ }
+ else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType)
+ {
+ $this->writeLogException(
+ new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sLogin
+ * @param string $sPassword
+ * @param string $sLoginAuthKey = ''
+ *
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Sieve\Exceptions\LoginException
+ */
+ public function Login($sLogin, $sPassword, $sLoginAuthKey = '')
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sLogin, true) ||
+ !\MailSo\Base\Validator::NotEmptyString($sPassword, true))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ if ($this->IsSupported('SASL'))
+ {
+ $bAuth = false;
+ try
+ {
+ if ($this->IsAuthSupported('PLAIN'))
+ {
+ $sAuth = \base64_encode($sLoginAuthKey."\0".$sLogin."\0".$sPassword);
+
+ $this->sendRequest('AUTHENTICATE "PLAIN" {'.\strlen($sAuth).'+}');
+ $this->sendRequest($sAuth);
+
+ $mResponse = $this->parseResponse();
+ $this->validateResponse($mResponse);
+ $this->parseStartupResponse($mResponse);
+ $bAuth = true;
+ }
+ else if ($this->IsAuthSupported('LOGIN'))
+ {
+ $sLogin = \base64_encode($sLogin);
+ $sPassword = \base64_encode($sPassword);
+
+ $this->sendRequest('AUTHENTICATE "LOGIN"');
+ $this->sendRequest('{'.\strlen($sLogin).'+}');
+ $this->sendRequest($sLogin);
+ $this->sendRequest('{'.\strlen($sPassword).'+}');
+ $this->sendRequest($sPassword);
+
+ $mResponse = $this->parseResponse();
+ $this->validateResponse($mResponse);
+ $this->parseStartupResponse($mResponse);
+ $bAuth = true;
+ }
+ }
+ catch (\MailSo\Sieve\Exceptions\NegativeResponseException $oException)
+ {
+ $this->writeLogException(
+ new \MailSo\Sieve\Exceptions\LoginBadCredentialsException(
+ $oException->GetResponses(), '', 0, $oException),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ if (!$bAuth)
+ {
+ $this->writeLogException(
+ new \MailSo\Sieve\Exceptions\LoginBadMethodException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+ }
+ else
+ {
+ $this->writeLogException(
+ new \MailSo\Sieve\Exceptions\LoginException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->bIsLoggined = true;
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function Logout()
+ {
+ if ($this->bIsLoggined)
+ {
+ $this->sendRequestWithCheck('LOGOUT');
+ $this->bIsLoggined = false;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function ListScripts()
+ {
+ $this->sendRequest('LISTSCRIPTS');
+ $mResponse = $this->parseResponse();
+ $this->validateResponse($mResponse);
+
+ $aResult = array();
+ if (\is_array($mResponse))
+ {
+ foreach ($mResponse as $sLine)
+ {
+ $aTokens = $this->parseLine($sLine);
+ if (false === $aTokens)
+ {
+ continue;
+ }
+
+ $aResult[$aTokens[0]] = 'ACTIVE' === substr($sLine, -6);
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function Capability()
+ {
+ $this->sendRequest('CAPABILITY');
+ $mResponse = $this->parseResponse();
+ $this->validateResponse($mResponse);
+ $this->parseStartupResponse($mResponse);
+
+ return $this->aCapa;
+ }
+
+ /**
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function Noop()
+ {
+ $this->sendRequestWithCheck('NOOP');
+
+ return $this;
+ }
+
+ /**
+ * @param string $sScriptName
+ *
+ * @return string
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function GetScript($sScriptName)
+ {
+ $this->sendRequest('GETSCRIPT "'.$sScriptName.'"');
+ $mResponse = $this->parseResponse();
+ $this->validateResponse($mResponse);
+
+ $sScript = '';
+ if (\is_array($mResponse) && 0 < \count($mResponse))
+ {
+ if ('{' === $mResponse[0]{0})
+ {
+ \array_shift($mResponse);
+ }
+
+ if (\in_array(\substr($mResponse[\count($mResponse) - 1], 0, 2), array('OK', 'NO')))
+ {
+ \array_pop($mResponse);
+ }
+
+ $sScript = \implode("\n", $mResponse);
+ }
+
+ return $sScript;
+ }
+
+ /**
+ * @param string $sScriptName
+ * @param string $sScriptSource
+ *
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function PutScript($sScriptName, $sScriptSource)
+ {
+ $this->sendRequest('PUTSCRIPT "'.$sScriptName.'" {'.\strlen($sScriptSource).'+}');
+ $this->sendRequestWithCheck($sScriptSource);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sScriptSource
+ *
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function CheckScript($sScriptSource)
+ {
+ $this->sendRequest('CHECKSCRIPT {'.\strlen($sScriptSource).'+}');
+ $this->sendRequestWithCheck($sScriptSource);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sScriptName
+ *
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function SetActiveScript($sScriptName)
+ {
+ $this->sendRequestWithCheck('SETACTIVE "'.$sScriptName.'"');
+
+ return $this;
+ }
+
+ /**
+ * @param string $sScriptName
+ *
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function DeleteScript($sScriptName)
+ {
+ $this->sendRequestWithCheck('DELETESCRIPT "'.$sScriptName.'"');
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function GetActiveScriptName()
+ {
+ $aList = $this->ListScripts();
+ if (\is_array($aList) && 0 < \count($aList))
+ {
+ foreach ($aList as $sName => $bIsActive)
+ {
+ if ($bIsActive)
+ {
+ return $sName;
+ }
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * @param string $sScriptName
+ *
+ * @return bool
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ public function IsActiveScript($sScriptName)
+ {
+ return $sScriptName === $this->GetActiveScriptName();
+ }
+
+ /**
+ * @param string $sLine
+ * @return array|false
+ */
+ private function parseLine($sLine)
+ {
+ if (false === $sLine || null === $sLine || \in_array(\substr($sLine, 0, 2), array('OK', 'NO')))
+ {
+ return false;
+ }
+
+ $iStart = -1;
+ $iIndex = 0;
+ $aResult = false;
+
+ for ($iPos = 0; $iPos < \strlen($sLine); $iPos++)
+ {
+ if ('"' === $sLine[$iPos] && '\\' !== $sLine[$iPos])
+ {
+ if (-1 === $iStart)
+ {
+ $iStart = $iPos;
+ }
+ else
+ {
+ $aResult = \is_array($aResult) ? $aResult : array();
+ $aResult[$iIndex++] = \substr($sLine, $iStart + 1, $iPos - $iStart - 1);
+ $iStart = -1;
+ }
+ }
+ }
+
+ return \is_array($aResult) && isset($aResult[0]) ? $aResult : false;
+ }
+
+ /**
+ * @param string $mResponse
+ *
+ * @return void
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ private function parseStartupResponse($mResponse)
+ {
+ foreach ($mResponse as $sLine)
+ {
+ $aTokens = $this->parseLine($sLine);
+
+ if (false === $aTokens || !isset($aTokens[0]) ||
+ \in_array(\substr($sLine, 0, 2), array('OK', 'NO')))
+ {
+ continue;
+ }
+
+ $sToken = \strtoupper($aTokens[0]);
+ $this->aCapa[$sToken] = isset($aTokens[1]) ? $aTokens[1] : '';
+
+ if (isset($aTokens[1]))
+ {
+ switch ($sToken) {
+ case 'SASL':
+ $this->aAuth = \explode(' ', \strtoupper($aTokens[1]));
+ break;
+ case 'SIEVE':
+ $this->aModules = \explode(' ', \strtolower($aTokens[1]));
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * @param string $sRequest
+ *
+ * @return void
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ private function sendRequest($sRequest)
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sRequest, true))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->IsConnected(true);
+
+ $this->sendRaw($sRequest);
+ }
+
+ /**
+ * @param string $sRequest
+ *
+ * @return void
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ private function sendRequestWithCheck($sRequest)
+ {
+ $this->sendRequest($sRequest);
+ $this->validateResponse($this->parseResponse());
+ }
+
+ /**
+ * @param string $sLine
+ *
+ * @return string
+ */
+ private function convertEndOfLine($sLine)
+ {
+ $sLine = \trim($sLine);
+ if ('}' === \substr($sLine, -1))
+ {
+ $iPos = \strrpos($sLine, '{');
+ if (false !== $iPos)
+ {
+ $sSunLine = \substr($sLine, $iPos + 1, -1);
+ if (\is_numeric($sSunLine) && 0 < (int) $sSunLine)
+ {
+ $iLen = (int) $sSunLine;
+
+ $this->getNextBuffer($iLen, true);
+
+ if (\strlen($this->sResponseBuffer) === $iLen)
+ {
+ $sLine = \trim(\substr_replace($sLine, $this->sResponseBuffer, $iPos));
+ }
+ }
+ }
+ }
+
+ return $sLine;
+ }
+
+ /**
+ * @return array|bool
+ */
+ private function parseResponse()
+ {
+ $this->iRequestTime = \microtime(true);
+
+ $aResult = array();
+ do
+ {
+ $this->getNextBuffer();
+
+ $sLine = $this->sResponseBuffer;
+ if (false === $sLine)
+ {
+ break;
+ }
+ else if (\in_array(\substr($sLine, 0, 2), array('OK', 'NO')))
+ {
+ $aResult[] = $this->convertEndOfLine($sLine);
+ break;
+ }
+ else
+ {
+ $aResult[] = $this->convertEndOfLine($sLine);
+ }
+ }
+ while (true);
+
+ $this->writeLog((\microtime(true) - $this->iRequestTime),
+ \MailSo\Log\Enumerations\Type::TIME);
+
+ return $aResult;
+ }
+
+ /**
+ * @throws \MailSo\Sieve\Exceptions\NegativeResponseException
+ */
+ private function validateResponse($aResponse)
+ {
+ if (!\is_array($aResponse) || 0 === \count($aResponse) ||
+ 'OK' !== \substr($aResponse[\count($aResponse) - 1], 0, 2))
+ {
+ $this->writeLogException(
+ new \MailSo\Sieve\Exceptions\NegativeResponseException($aResponse),
+ \MailSo\Log\Enumerations\Type::WARNING, true);
+ }
+ }
+
+ /**
+ * @return string
+ */
+ protected function getLogName()
+ {
+ return 'SIEVE';
+ }
+
+ /**
+ * @param \MailSo\Log\Logger $oLogger
+ *
+ * @return \MailSo\Sieve\ManageSieveClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetLogger($oLogger)
+ {
+ parent::SetLogger($oLogger);
+
+ return $this;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Smtp/Exceptions/Exception.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Smtp/Exceptions/Exception.php
new file mode 100644
index 0000000..7c18f18
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Smtp/Exceptions/Exception.php
@@ -0,0 +1,19 @@
+aResponses = $aResponses;
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function GetResponses()
+ {
+ return $this->aResponses;
+ }
+
+ /**
+ * @return \MailSo\Smtp\Response | null
+ */
+ public function GetLastResponse()
+ {
+ return 0 < count($this->aResponses) ? $this->aResponses[count($this->aResponses) - 1] : null;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Smtp/Exceptions/RuntimeException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Smtp/Exceptions/RuntimeException.php
new file mode 100644
index 0000000..294b93b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Smtp/Exceptions/RuntimeException.php
@@ -0,0 +1,19 @@
+aAuthTypes = array();
+
+ $this->iRequestTime = 0;
+ $this->iSizeCapaValue = 0;
+ $this->aResults = array();
+ $this->aCapa = array();
+
+ $this->bHelo = false;
+ $this->bRcpt = false;
+ $this->bMail = false;
+ $this->bData = false;
+ }
+
+ /**
+ * @return \MailSo\Smtp\SmtpClient
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsSupported($sCapa)
+ {
+ return in_array(strtoupper($sCapa), $this->aCapa);
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsAuthSupported($sAuth)
+ {
+ return in_array(strtoupper($sAuth), $this->aAuthTypes);
+ }
+
+ /**
+ * @return bool
+ */
+ public function HasSupportedAuth()
+ {
+ return $this->IsAuthSupported('PLAIN') || $this->IsAuthSupported('LOGIN');
+ }
+
+ /**
+ * @return string
+ */
+ public static function EhloHelper()
+ {
+ $sEhloHost = empty($_SERVER['SERVER_NAME']) ? '' : \trim($_SERVER['SERVER_NAME']);
+ if (empty($sEhloHost))
+ {
+ $sEhloHost = empty($_SERVER['HTTP_HOST']) ? '' : \trim($_SERVER['HTTP_HOST']);
+ }
+
+ if (empty($sEhloHost))
+ {
+ $sEhloHost = \function_exists('gethostname') ? \gethostname() : 'localhost';
+ }
+
+ $sEhloHost = \trim(\preg_replace('/:\d+$/', '', \trim($sEhloHost)));
+
+ if (\preg_match('/^\d+\.\d+\.\d+\.\d+$/', $sEhloHost))
+ {
+ $sEhloHost = '['.$sEhloHost.']';
+ }
+
+ return empty($sEhloHost) ? 'localhost' : $sEhloHost;
+ }
+
+ /**
+ * @param string $sServerName
+ * @param int $iPort = 25
+ * @param string $sEhloHost = '[127.0.0.1]'
+ * @param int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT
+ * @param bool $bVerifySsl = false
+ * @param bool $bAllowSelfSigned = true
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\ResponseException
+ */
+ public function Connect($sServerName, $iPort = 25, $sEhloHost = '[127.0.0.1]',
+ $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT,
+ $bVerifySsl = false, $bAllowSelfSigned = true)
+ {
+ $this->iRequestTime = microtime(true);
+
+ parent::Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned);
+
+ $this->validateResponse(220);
+
+ $this->preLoginStartTLSAndEhloProcess($sEhloHost);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sLogin
+ * @param string $sPassword
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function Login($sLogin, $sPassword)
+ {
+ $sLogin = \MailSo\Base\Utils::IdnToAscii(\MailSo\Base\Utils::Trim($sLogin));
+
+ if ($this->IsAuthSupported('LOGIN'))
+ {
+ try
+ {
+ $this->sendRequestWithCheck('AUTH', 334, 'LOGIN');
+ }
+ catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException)
+ {
+ $this->writeLogException(
+ new \MailSo\Smtp\Exceptions\LoginBadMethodException(
+ $oException->GetResponses(), $oException->getMessage(), 0, $oException),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+
+ try
+ {
+ $this->sendRequestWithCheck(\base64_encode($sLogin), 334, '');
+ $this->sendRequestWithCheck(\base64_encode($sPassword), 235, '', true);
+ }
+ catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException)
+ {
+ $this->writeLogException(
+ new \MailSo\Smtp\Exceptions\LoginBadCredentialsException(
+ $oException->GetResponses(), $oException->getMessage(), 0, $oException),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+ }
+ else if ($this->IsAuthSupported('PLAIN'))
+ {
+ if ($this->__USE_SINGLE_LINE_AUTH_PLAIN_COMMAND)
+ {
+ try
+ {
+ $this->sendRequestWithCheck('AUTH', 235, 'PLAIN '.\base64_encode("\0".$sLogin."\0".$sPassword), true);
+ }
+ catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException)
+ {
+ $this->writeLogException(
+ new \MailSo\Smtp\Exceptions\LoginBadCredentialsException(
+ $oException->GetResponses(), $oException->getMessage(), 0, $oException),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+ }
+ else
+ {
+ try
+ {
+ $this->sendRequestWithCheck('AUTH', 334, 'PLAIN');
+ }
+ catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException)
+ {
+ $this->writeLogException(
+ new \MailSo\Smtp\Exceptions\LoginBadMethodException(
+ $oException->GetResponses(), $oException->getMessage(), 0, $oException),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+
+ try
+ {
+ $this->sendRequestWithCheck(\base64_encode("\0".$sLogin."\0".$sPassword), 235, '', true);
+ }
+ catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException)
+ {
+ $this->writeLogException(
+ new \MailSo\Smtp\Exceptions\LoginBadCredentialsException(
+ $oException->GetResponses(), $oException->getMessage(), 0, $oException),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+ }
+ }
+ else
+ {
+ $this->writeLogException(
+ new \MailSo\Smtp\Exceptions\LoginBadMethodException(),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sXOAuth2Token
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function LoginWithXOauth2($sXOAuth2Token)
+ {
+ if ($this->IsAuthSupported('XOAUTH2'))
+ {
+ try
+ {
+ $this->sendRequestWithCheck('AUTH', 235, 'XOAUTH2 '.\trim($sXOAuth2Token));
+ }
+ catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException)
+ {
+ $this->writeLogException(
+ new \MailSo\Smtp\Exceptions\LoginBadCredentialsException(
+ $oException->GetResponses(), $oException->getMessage(), 0, $oException),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+ }
+ else
+ {
+ $this->writeLogException(
+ new \MailSo\Smtp\Exceptions\LoginBadMethodException(),
+ \MailSo\Log\Enumerations\Type::NOTICE, true);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sFrom
+ * @param string $sSizeIfSupported = ''
+ * @param bool $bDsn = false
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function MailFrom($sFrom, $sSizeIfSupported = '', $bDsn = false)
+ {
+ $sFrom = \MailSo\Base\Utils::IdnToAscii(
+ \MailSo\Base\Utils::Trim($sFrom), true);
+
+ $sCmd = 'FROM:<'.$sFrom.'>';
+
+ $sSizeIfSupported = (string) $sSizeIfSupported;
+ if (0 < \strlen($sSizeIfSupported) && \is_numeric($sSizeIfSupported) && $this->IsSupported('SIZE'))
+ {
+ $sCmd .= ' SIZE='.$sSizeIfSupported;
+ }
+
+ if ($bDsn && $this->IsSupported('DSN'))
+ {
+ $sCmd .= ' RET=HDRS';
+ }
+
+ $this->sendRequestWithCheck('MAIL', 250, $sCmd);
+
+ $this->bMail = true;
+ $this->bRcpt = false;
+ $this->bData = false;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sTo
+ * @param bool $bDsn = false
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function Rcpt($sTo, $bDsn = false)
+ {
+ if (!$this->bMail)
+ {
+ $this->writeLogException(
+ new Exceptions\RuntimeException('No sender reverse path has been supplied'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $sTo = \MailSo\Base\Utils::IdnToAscii(
+ \MailSo\Base\Utils::Trim($sTo), true);
+
+ $sCmd = 'TO:<'.$sTo.'>';
+
+ if ($bDsn && $this->IsSupported('DSN'))
+ {
+ $sCmd .= ' NOTIFY=SUCCESS,FAILURE';
+ }
+
+ $this->sendRequestWithCheck('RCPT', array(250, 251), $sCmd);
+
+ $this->bRcpt = true;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sTo
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function MailTo($sTo)
+ {
+ return $this->Rcpt($sTo);
+ }
+
+ /**
+ * @param string $sData
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function Data($sData)
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sData, true))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ $rDataStream = \MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString($sData);
+ unset($sData);
+ $this->DataWithStream($rDataStream);
+ \MailSo\Base\ResourceRegistry::CloseMemoryResource($rDataStream);
+
+ return $this;
+ }
+
+ /**
+ * @param resource $rDataStream
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function DataWithStream($rDataStream)
+ {
+ if (!\is_resource($rDataStream))
+ {
+ throw new \MailSo\Base\Exceptions\InvalidArgumentException();
+ }
+
+ if (!$this->bRcpt)
+ {
+ $this->writeLogException(
+ new Exceptions\RuntimeException('No recipient forward path has been supplied'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->sendRequestWithCheck('DATA', 354);
+
+ $this->writeLog('Message data.', \MailSo\Log\Enumerations\Type::NOTE);
+
+ $this->bRunningCallback = true;
+
+ while (!\feof($rDataStream))
+ {
+ $sBuffer = \fgets($rDataStream);
+ if (false !== $sBuffer)
+ {
+ if (0 === \strpos($sBuffer, '.'))
+ {
+ $sBuffer = '.'.$sBuffer;
+ }
+
+ $this->sendRaw(\rtrim($sBuffer, "\r\n"), false);
+
+ \MailSo\Base\Utils::ResetTimeLimit();
+ continue;
+ }
+ else if (!\feof($rDataStream))
+ {
+ $this->writeLogException(
+ new Exceptions\RuntimeException('Cannot read input resource'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ break;
+ }
+
+ $this->sendRequestWithCheck('.', 250);
+
+ $this->bRunningCallback = false;
+
+ $this->bData = true;
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function Rset()
+ {
+ $this->sendRequestWithCheck('RSET', array(250, 220));
+
+ $this->bMail = false;
+ $this->bRcpt = false;
+ $this->bData = false;
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function Vrfy($sUser)
+ {
+ $sUser = \MailSo\Base\Utils::IdnToAscii(
+ \MailSo\Base\Utils::Trim($sUser));
+
+ $this->sendRequestWithCheck('VRFY', array(250, 251, 252), $sUser);
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function Noop()
+ {
+ $this->sendRequestWithCheck('NOOP', 250);
+
+ return $this;
+ }
+
+ /**
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ public function Logout()
+ {
+ if ($this->IsConnected())
+ {
+ $this->sendRequestWithCheck('QUIT', 221);
+ }
+
+ $this->bHelo = false;
+ $this->bMail = false;
+ $this->bRcpt = false;
+ $this->bData = false;
+
+ return $this;
+ }
+
+ /**
+ * @param string $sEhloHost
+ *
+ * @return void
+ */
+ private function preLoginStartTLSAndEhloProcess($sEhloHost)
+ {
+ if ($this->bHelo)
+ {
+ $this->writeLogException(
+ new Exceptions\RuntimeException('Cannot issue EHLO/HELO to existing session'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->ehloOrHelo($sEhloHost);
+
+ if (\MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS(
+ $this->IsSupported('STARTTLS'), $this->iSecurityType, $this->HasSupportedAuth()))
+ {
+ $this->sendRequestWithCheck('STARTTLS', 220);
+ $this->EnableCrypto();
+
+ $this->ehloOrHelo($sEhloHost);
+ }
+ else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType)
+ {
+ $this->writeLogException(
+ new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->bHelo = true;
+ }
+
+ /**
+ * @param string $sCommand
+ * @param string $sAddToCommand = ''
+ * @param bool $bSecureLog = false
+ *
+ * @return void
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ */
+ private function sendRequest($sCommand, $sAddToCommand = '', $bSecureLog = false)
+ {
+ if (!\MailSo\Base\Validator::NotEmptyString($sCommand, true))
+ {
+ $this->writeLogException(
+ new \MailSo\Base\Exceptions\InvalidArgumentException(),
+ \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->IsConnected(true);
+
+ $sCommand = \trim($sCommand);
+ $sRealCommand = $sCommand.(0 === \strlen($sAddToCommand) ? '' : ' '.$sAddToCommand);
+
+ $sFakeCommand = ($bSecureLog) ? '********' : '';
+
+ $this->iRequestTime = \microtime(true);
+ $this->sendRaw($sRealCommand, true, $sFakeCommand);
+
+ return $this;
+ }
+
+ /**
+ * @param string $sCommand
+ * @param int|array $mExpectCode
+ * @param string $sAddToCommand = ''
+ * @param bool $bSecureLog = false
+ *
+ * @return void
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ private function sendRequestWithCheck($sCommand, $mExpectCode, $sAddToCommand = '', $bSecureLog = false)
+ {
+ $this->sendRequest($sCommand, $sAddToCommand, $bSecureLog);
+ $this->validateResponse($mExpectCode);
+ }
+
+ /**
+ * @param string $sHost
+ *
+ * @return void
+ */
+ private function ehloOrHelo($sHost)
+ {
+ try
+ {
+ $this->ehlo($sHost);
+ }
+ catch (\Exception $oException)
+ {
+ try
+ {
+ $this->helo($sHost);
+ }
+ catch (\Exception $oException)
+ {
+ throw $oException;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $sHost
+ *
+ * @return void
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ private function ehlo($sHost)
+ {
+ $this->sendRequestWithCheck('EHLO', 250, $sHost);
+
+ foreach ($this->aResults as $sLine)
+ {
+ $aMatch = array();
+ if (\preg_match('/[\d]+[ \-](.+)$/', $sLine, $aMatch) && isset($aMatch[1]) && 0 < \strlen($aMatch[1]))
+ {
+ $sLine = \trim($aMatch[1]);
+ $aLine = \preg_split('/[ =]/', $sLine, 2);
+ if (\is_array($aLine) && 0 < \count($aLine) && !empty($aLine[0]))
+ {
+ $sCapa = \strtoupper($aLine[0]);
+ if (('AUTH' === $sCapa || 'SIZE' === $sCapa) && !empty($aLine[1]))
+ {
+ $sSubLine = \trim(\strtoupper($aLine[1]));
+ if (0 < \strlen($sSubLine))
+ {
+ if ('AUTH' === $sCapa)
+ {
+ $this->aAuthTypes = \explode(' ', $sSubLine);
+ }
+ else if ('SIZE' === $sCapa && \is_numeric($sSubLine))
+ {
+ $this->iSizeCapaValue = (int) $sSubLine;
+ }
+ }
+ }
+
+ $this->aCapa[] = $sCapa;
+ }
+ }
+ }
+ }
+
+ /**
+ * @param string $sHost
+ *
+ * @return void
+ *
+ * @throws \MailSo\Net\Exceptions\Exception
+ * @throws \MailSo\Smtp\Exceptions\Exception
+ */
+ private function helo($sHost)
+ {
+ $this->sendRequestWithCheck('HELO', 250, $sHost);
+ $this->aAuthTypes = array();
+ $this->iSizeCapaValue = 0;
+ $this->aCapa = array();
+ }
+
+ /**
+ * @param int|array $mExpectCode
+ *
+ * @return void
+ *
+ * @throws \MailSo\Smtp\Exceptions\ResponseException
+ */
+ private function validateResponse($mExpectCode)
+ {
+ if (!\is_array($mExpectCode))
+ {
+ $mExpectCode = array((int) $mExpectCode);
+ }
+ else
+ {
+ $mExpectCode = \array_map('intval', $mExpectCode);
+ }
+
+ $aParts = array('', '', '');
+ $this->aResults = array();
+ do
+ {
+ $this->getNextBuffer();
+ $aParts = \preg_split('/([\s-]+)/', $this->sResponseBuffer, 2, PREG_SPLIT_DELIM_CAPTURE);
+
+ if (\is_array($aParts) && 3 === \count($aParts) && \is_numeric($aParts[0]))
+ {
+ if ('-' !== trim($aParts[1]) && !\in_array((int) $aParts[0], $mExpectCode))
+ {
+ $this->writeLogException(
+ new Exceptions\NegativeResponseException($this->aResults, \trim(
+ (0 < \count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : '').
+ $this->sResponseBuffer)), \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+ }
+ else
+ {
+ $this->writeLogException(
+ new Exceptions\ResponseException($this->aResults, \trim(
+ (0 < \count($this->aResults) ? \implode("\r\n", $this->aResults)."\r\n" : '').
+ $this->sResponseBuffer)), \MailSo\Log\Enumerations\Type::ERROR, true);
+ }
+
+ $this->aResults[] = $this->sResponseBuffer;
+ }
+ while ('-' === \trim($aParts[1]));
+
+ $this->writeLog((microtime(true) - $this->iRequestTime),
+ \MailSo\Log\Enumerations\Type::TIME);
+ }
+
+ /**
+ * @return string
+ */
+ protected function getLogName()
+ {
+ return 'SMTP';
+ }
+
+ /**
+ * @param \MailSo\Log\Logger $oLogger
+ *
+ * @return \MailSo\Smtp\SmtpClient
+ *
+ * @throws \MailSo\Base\Exceptions\InvalidArgumentException
+ */
+ public function SetLogger($oLogger)
+ {
+ parent::SetLogger($oLogger);
+
+ return $this;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Vendors/Net/IDNA2.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Vendors/Net/IDNA2.php
new file mode 100644
index 0000000..8206834
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Vendors/Net/IDNA2.php
@@ -0,0 +1,3404 @@
+
+ * @author Matthias Sommerfeld
+ * @author Stefan Neufeind
+ * @version $Id: IDNA2.php 305344 2010-11-14 23:52:42Z neufeind $
+ */
+class Net_IDNA2
+{
+ // {{{ npdata
+ /**
+ * These Unicode codepoints are
+ * mapped to nothing, See RFC3454 for details
+ *
+ * @static
+ * @var array
+ * @access private
+ */
+ private static $_np_map_nothing = array(
+ 0xAD,
+ 0x34F,
+ 0x1806,
+ 0x180B,
+ 0x180C,
+ 0x180D,
+ 0x200B,
+ 0x200C,
+ 0x200D,
+ 0x2060,
+ 0xFE00,
+ 0xFE01,
+ 0xFE02,
+ 0xFE03,
+ 0xFE04,
+ 0xFE05,
+ 0xFE06,
+ 0xFE07,
+ 0xFE08,
+ 0xFE09,
+ 0xFE0A,
+ 0xFE0B,
+ 0xFE0C,
+ 0xFE0D,
+ 0xFE0E,
+ 0xFE0F,
+ 0xFEFF
+ );
+
+ /**
+ * Prohibited codepints
+ *
+ * @static
+ * @var array
+ * @access private
+ */
+ private static $_general_prohibited = array(
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 0xA,
+ 0xB,
+ 0xC,
+ 0xD,
+ 0xE,
+ 0xF,
+ 0x10,
+ 0x11,
+ 0x12,
+ 0x13,
+ 0x14,
+ 0x15,
+ 0x16,
+ 0x17,
+ 0x18,
+ 0x19,
+ 0x1A,
+ 0x1B,
+ 0x1C,
+ 0x1D,
+ 0x1E,
+ 0x1F,
+ 0x20,
+ 0x21,
+ 0x22,
+ 0x23,
+ 0x24,
+ 0x25,
+ 0x26,
+ 0x27,
+ 0x28,
+ 0x29,
+ 0x2A,
+ 0x2B,
+ 0x2C,
+ 0x2F,
+ 0x3B,
+ 0x3C,
+ 0x3D,
+ 0x3E,
+ 0x3F,
+ 0x40,
+ 0x5B,
+ 0x5C,
+ 0x5D,
+ 0x5E,
+ 0x5F,
+ 0x60,
+ 0x7B,
+ 0x7C,
+ 0x7D,
+ 0x7E,
+ 0x7F,
+ 0x3002
+ );
+
+ /**
+ * Codepints prohibited by Nameprep
+ * @static
+ * @var array
+ * @access private
+ */
+ private static $_np_prohibit = array(
+ 0xA0,
+ 0x1680,
+ 0x2000,
+ 0x2001,
+ 0x2002,
+ 0x2003,
+ 0x2004,
+ 0x2005,
+ 0x2006,
+ 0x2007,
+ 0x2008,
+ 0x2009,
+ 0x200A,
+ 0x200B,
+ 0x202F,
+ 0x205F,
+ 0x3000,
+ 0x6DD,
+ 0x70F,
+ 0x180E,
+ 0x200C,
+ 0x200D,
+ 0x2028,
+ 0x2029,
+ 0xFEFF,
+ 0xFFF9,
+ 0xFFFA,
+ 0xFFFB,
+ 0xFFFC,
+ 0xFFFE,
+ 0xFFFF,
+ 0x1FFFE,
+ 0x1FFFF,
+ 0x2FFFE,
+ 0x2FFFF,
+ 0x3FFFE,
+ 0x3FFFF,
+ 0x4FFFE,
+ 0x4FFFF,
+ 0x5FFFE,
+ 0x5FFFF,
+ 0x6FFFE,
+ 0x6FFFF,
+ 0x7FFFE,
+ 0x7FFFF,
+ 0x8FFFE,
+ 0x8FFFF,
+ 0x9FFFE,
+ 0x9FFFF,
+ 0xAFFFE,
+ 0xAFFFF,
+ 0xBFFFE,
+ 0xBFFFF,
+ 0xCFFFE,
+ 0xCFFFF,
+ 0xDFFFE,
+ 0xDFFFF,
+ 0xEFFFE,
+ 0xEFFFF,
+ 0xFFFFE,
+ 0xFFFFF,
+ 0x10FFFE,
+ 0x10FFFF,
+ 0xFFF9,
+ 0xFFFA,
+ 0xFFFB,
+ 0xFFFC,
+ 0xFFFD,
+ 0x340,
+ 0x341,
+ 0x200E,
+ 0x200F,
+ 0x202A,
+ 0x202B,
+ 0x202C,
+ 0x202D,
+ 0x202E,
+ 0x206A,
+ 0x206B,
+ 0x206C,
+ 0x206D,
+ 0x206E,
+ 0x206F,
+ 0xE0001
+ );
+
+ /**
+ * Codepoint ranges prohibited by nameprep
+ *
+ * @static
+ * @var array
+ * @access private
+ */
+ private static $_np_prohibit_ranges = array(
+ array(0x80, 0x9F ),
+ array(0x2060, 0x206F ),
+ array(0x1D173, 0x1D17A ),
+ array(0xE000, 0xF8FF ),
+ array(0xF0000, 0xFFFFD ),
+ array(0x100000, 0x10FFFD),
+ array(0xFDD0, 0xFDEF ),
+ array(0xD800, 0xDFFF ),
+ array(0x2FF0, 0x2FFB ),
+ array(0xE0020, 0xE007F )
+ );
+
+ /**
+ * Replacement mappings (casemapping, replacement sequences, ...)
+ *
+ * @static
+ * @var array
+ * @access private
+ */
+ private static $_np_replacemaps = array(
+ 0x41 => array(0x61),
+ 0x42 => array(0x62),
+ 0x43 => array(0x63),
+ 0x44 => array(0x64),
+ 0x45 => array(0x65),
+ 0x46 => array(0x66),
+ 0x47 => array(0x67),
+ 0x48 => array(0x68),
+ 0x49 => array(0x69),
+ 0x4A => array(0x6A),
+ 0x4B => array(0x6B),
+ 0x4C => array(0x6C),
+ 0x4D => array(0x6D),
+ 0x4E => array(0x6E),
+ 0x4F => array(0x6F),
+ 0x50 => array(0x70),
+ 0x51 => array(0x71),
+ 0x52 => array(0x72),
+ 0x53 => array(0x73),
+ 0x54 => array(0x74),
+ 0x55 => array(0x75),
+ 0x56 => array(0x76),
+ 0x57 => array(0x77),
+ 0x58 => array(0x78),
+ 0x59 => array(0x79),
+ 0x5A => array(0x7A),
+ 0xB5 => array(0x3BC),
+ 0xC0 => array(0xE0),
+ 0xC1 => array(0xE1),
+ 0xC2 => array(0xE2),
+ 0xC3 => array(0xE3),
+ 0xC4 => array(0xE4),
+ 0xC5 => array(0xE5),
+ 0xC6 => array(0xE6),
+ 0xC7 => array(0xE7),
+ 0xC8 => array(0xE8),
+ 0xC9 => array(0xE9),
+ 0xCA => array(0xEA),
+ 0xCB => array(0xEB),
+ 0xCC => array(0xEC),
+ 0xCD => array(0xED),
+ 0xCE => array(0xEE),
+ 0xCF => array(0xEF),
+ 0xD0 => array(0xF0),
+ 0xD1 => array(0xF1),
+ 0xD2 => array(0xF2),
+ 0xD3 => array(0xF3),
+ 0xD4 => array(0xF4),
+ 0xD5 => array(0xF5),
+ 0xD6 => array(0xF6),
+ 0xD8 => array(0xF8),
+ 0xD9 => array(0xF9),
+ 0xDA => array(0xFA),
+ 0xDB => array(0xFB),
+ 0xDC => array(0xFC),
+ 0xDD => array(0xFD),
+ 0xDE => array(0xFE),
+ 0xDF => array(0x73, 0x73),
+ 0x100 => array(0x101),
+ 0x102 => array(0x103),
+ 0x104 => array(0x105),
+ 0x106 => array(0x107),
+ 0x108 => array(0x109),
+ 0x10A => array(0x10B),
+ 0x10C => array(0x10D),
+ 0x10E => array(0x10F),
+ 0x110 => array(0x111),
+ 0x112 => array(0x113),
+ 0x114 => array(0x115),
+ 0x116 => array(0x117),
+ 0x118 => array(0x119),
+ 0x11A => array(0x11B),
+ 0x11C => array(0x11D),
+ 0x11E => array(0x11F),
+ 0x120 => array(0x121),
+ 0x122 => array(0x123),
+ 0x124 => array(0x125),
+ 0x126 => array(0x127),
+ 0x128 => array(0x129),
+ 0x12A => array(0x12B),
+ 0x12C => array(0x12D),
+ 0x12E => array(0x12F),
+ 0x130 => array(0x69, 0x307),
+ 0x132 => array(0x133),
+ 0x134 => array(0x135),
+ 0x136 => array(0x137),
+ 0x139 => array(0x13A),
+ 0x13B => array(0x13C),
+ 0x13D => array(0x13E),
+ 0x13F => array(0x140),
+ 0x141 => array(0x142),
+ 0x143 => array(0x144),
+ 0x145 => array(0x146),
+ 0x147 => array(0x148),
+ 0x149 => array(0x2BC, 0x6E),
+ 0x14A => array(0x14B),
+ 0x14C => array(0x14D),
+ 0x14E => array(0x14F),
+ 0x150 => array(0x151),
+ 0x152 => array(0x153),
+ 0x154 => array(0x155),
+ 0x156 => array(0x157),
+ 0x158 => array(0x159),
+ 0x15A => array(0x15B),
+ 0x15C => array(0x15D),
+ 0x15E => array(0x15F),
+ 0x160 => array(0x161),
+ 0x162 => array(0x163),
+ 0x164 => array(0x165),
+ 0x166 => array(0x167),
+ 0x168 => array(0x169),
+ 0x16A => array(0x16B),
+ 0x16C => array(0x16D),
+ 0x16E => array(0x16F),
+ 0x170 => array(0x171),
+ 0x172 => array(0x173),
+ 0x174 => array(0x175),
+ 0x176 => array(0x177),
+ 0x178 => array(0xFF),
+ 0x179 => array(0x17A),
+ 0x17B => array(0x17C),
+ 0x17D => array(0x17E),
+ 0x17F => array(0x73),
+ 0x181 => array(0x253),
+ 0x182 => array(0x183),
+ 0x184 => array(0x185),
+ 0x186 => array(0x254),
+ 0x187 => array(0x188),
+ 0x189 => array(0x256),
+ 0x18A => array(0x257),
+ 0x18B => array(0x18C),
+ 0x18E => array(0x1DD),
+ 0x18F => array(0x259),
+ 0x190 => array(0x25B),
+ 0x191 => array(0x192),
+ 0x193 => array(0x260),
+ 0x194 => array(0x263),
+ 0x196 => array(0x269),
+ 0x197 => array(0x268),
+ 0x198 => array(0x199),
+ 0x19C => array(0x26F),
+ 0x19D => array(0x272),
+ 0x19F => array(0x275),
+ 0x1A0 => array(0x1A1),
+ 0x1A2 => array(0x1A3),
+ 0x1A4 => array(0x1A5),
+ 0x1A6 => array(0x280),
+ 0x1A7 => array(0x1A8),
+ 0x1A9 => array(0x283),
+ 0x1AC => array(0x1AD),
+ 0x1AE => array(0x288),
+ 0x1AF => array(0x1B0),
+ 0x1B1 => array(0x28A),
+ 0x1B2 => array(0x28B),
+ 0x1B3 => array(0x1B4),
+ 0x1B5 => array(0x1B6),
+ 0x1B7 => array(0x292),
+ 0x1B8 => array(0x1B9),
+ 0x1BC => array(0x1BD),
+ 0x1C4 => array(0x1C6),
+ 0x1C5 => array(0x1C6),
+ 0x1C7 => array(0x1C9),
+ 0x1C8 => array(0x1C9),
+ 0x1CA => array(0x1CC),
+ 0x1CB => array(0x1CC),
+ 0x1CD => array(0x1CE),
+ 0x1CF => array(0x1D0),
+ 0x1D1 => array(0x1D2),
+ 0x1D3 => array(0x1D4),
+ 0x1D5 => array(0x1D6),
+ 0x1D7 => array(0x1D8),
+ 0x1D9 => array(0x1DA),
+ 0x1DB => array(0x1DC),
+ 0x1DE => array(0x1DF),
+ 0x1E0 => array(0x1E1),
+ 0x1E2 => array(0x1E3),
+ 0x1E4 => array(0x1E5),
+ 0x1E6 => array(0x1E7),
+ 0x1E8 => array(0x1E9),
+ 0x1EA => array(0x1EB),
+ 0x1EC => array(0x1ED),
+ 0x1EE => array(0x1EF),
+ 0x1F0 => array(0x6A, 0x30C),
+ 0x1F1 => array(0x1F3),
+ 0x1F2 => array(0x1F3),
+ 0x1F4 => array(0x1F5),
+ 0x1F6 => array(0x195),
+ 0x1F7 => array(0x1BF),
+ 0x1F8 => array(0x1F9),
+ 0x1FA => array(0x1FB),
+ 0x1FC => array(0x1FD),
+ 0x1FE => array(0x1FF),
+ 0x200 => array(0x201),
+ 0x202 => array(0x203),
+ 0x204 => array(0x205),
+ 0x206 => array(0x207),
+ 0x208 => array(0x209),
+ 0x20A => array(0x20B),
+ 0x20C => array(0x20D),
+ 0x20E => array(0x20F),
+ 0x210 => array(0x211),
+ 0x212 => array(0x213),
+ 0x214 => array(0x215),
+ 0x216 => array(0x217),
+ 0x218 => array(0x219),
+ 0x21A => array(0x21B),
+ 0x21C => array(0x21D),
+ 0x21E => array(0x21F),
+ 0x220 => array(0x19E),
+ 0x222 => array(0x223),
+ 0x224 => array(0x225),
+ 0x226 => array(0x227),
+ 0x228 => array(0x229),
+ 0x22A => array(0x22B),
+ 0x22C => array(0x22D),
+ 0x22E => array(0x22F),
+ 0x230 => array(0x231),
+ 0x232 => array(0x233),
+ 0x345 => array(0x3B9),
+ 0x37A => array(0x20, 0x3B9),
+ 0x386 => array(0x3AC),
+ 0x388 => array(0x3AD),
+ 0x389 => array(0x3AE),
+ 0x38A => array(0x3AF),
+ 0x38C => array(0x3CC),
+ 0x38E => array(0x3CD),
+ 0x38F => array(0x3CE),
+ 0x390 => array(0x3B9, 0x308, 0x301),
+ 0x391 => array(0x3B1),
+ 0x392 => array(0x3B2),
+ 0x393 => array(0x3B3),
+ 0x394 => array(0x3B4),
+ 0x395 => array(0x3B5),
+ 0x396 => array(0x3B6),
+ 0x397 => array(0x3B7),
+ 0x398 => array(0x3B8),
+ 0x399 => array(0x3B9),
+ 0x39A => array(0x3BA),
+ 0x39B => array(0x3BB),
+ 0x39C => array(0x3BC),
+ 0x39D => array(0x3BD),
+ 0x39E => array(0x3BE),
+ 0x39F => array(0x3BF),
+ 0x3A0 => array(0x3C0),
+ 0x3A1 => array(0x3C1),
+ 0x3A3 => array(0x3C3),
+ 0x3A4 => array(0x3C4),
+ 0x3A5 => array(0x3C5),
+ 0x3A6 => array(0x3C6),
+ 0x3A7 => array(0x3C7),
+ 0x3A8 => array(0x3C8),
+ 0x3A9 => array(0x3C9),
+ 0x3AA => array(0x3CA),
+ 0x3AB => array(0x3CB),
+ 0x3B0 => array(0x3C5, 0x308, 0x301),
+ 0x3C2 => array(0x3C3),
+ 0x3D0 => array(0x3B2),
+ 0x3D1 => array(0x3B8),
+ 0x3D2 => array(0x3C5),
+ 0x3D3 => array(0x3CD),
+ 0x3D4 => array(0x3CB),
+ 0x3D5 => array(0x3C6),
+ 0x3D6 => array(0x3C0),
+ 0x3D8 => array(0x3D9),
+ 0x3DA => array(0x3DB),
+ 0x3DC => array(0x3DD),
+ 0x3DE => array(0x3DF),
+ 0x3E0 => array(0x3E1),
+ 0x3E2 => array(0x3E3),
+ 0x3E4 => array(0x3E5),
+ 0x3E6 => array(0x3E7),
+ 0x3E8 => array(0x3E9),
+ 0x3EA => array(0x3EB),
+ 0x3EC => array(0x3ED),
+ 0x3EE => array(0x3EF),
+ 0x3F0 => array(0x3BA),
+ 0x3F1 => array(0x3C1),
+ 0x3F2 => array(0x3C3),
+ 0x3F4 => array(0x3B8),
+ 0x3F5 => array(0x3B5),
+ 0x400 => array(0x450),
+ 0x401 => array(0x451),
+ 0x402 => array(0x452),
+ 0x403 => array(0x453),
+ 0x404 => array(0x454),
+ 0x405 => array(0x455),
+ 0x406 => array(0x456),
+ 0x407 => array(0x457),
+ 0x408 => array(0x458),
+ 0x409 => array(0x459),
+ 0x40A => array(0x45A),
+ 0x40B => array(0x45B),
+ 0x40C => array(0x45C),
+ 0x40D => array(0x45D),
+ 0x40E => array(0x45E),
+ 0x40F => array(0x45F),
+ 0x410 => array(0x430),
+ 0x411 => array(0x431),
+ 0x412 => array(0x432),
+ 0x413 => array(0x433),
+ 0x414 => array(0x434),
+ 0x415 => array(0x435),
+ 0x416 => array(0x436),
+ 0x417 => array(0x437),
+ 0x418 => array(0x438),
+ 0x419 => array(0x439),
+ 0x41A => array(0x43A),
+ 0x41B => array(0x43B),
+ 0x41C => array(0x43C),
+ 0x41D => array(0x43D),
+ 0x41E => array(0x43E),
+ 0x41F => array(0x43F),
+ 0x420 => array(0x440),
+ 0x421 => array(0x441),
+ 0x422 => array(0x442),
+ 0x423 => array(0x443),
+ 0x424 => array(0x444),
+ 0x425 => array(0x445),
+ 0x426 => array(0x446),
+ 0x427 => array(0x447),
+ 0x428 => array(0x448),
+ 0x429 => array(0x449),
+ 0x42A => array(0x44A),
+ 0x42B => array(0x44B),
+ 0x42C => array(0x44C),
+ 0x42D => array(0x44D),
+ 0x42E => array(0x44E),
+ 0x42F => array(0x44F),
+ 0x460 => array(0x461),
+ 0x462 => array(0x463),
+ 0x464 => array(0x465),
+ 0x466 => array(0x467),
+ 0x468 => array(0x469),
+ 0x46A => array(0x46B),
+ 0x46C => array(0x46D),
+ 0x46E => array(0x46F),
+ 0x470 => array(0x471),
+ 0x472 => array(0x473),
+ 0x474 => array(0x475),
+ 0x476 => array(0x477),
+ 0x478 => array(0x479),
+ 0x47A => array(0x47B),
+ 0x47C => array(0x47D),
+ 0x47E => array(0x47F),
+ 0x480 => array(0x481),
+ 0x48A => array(0x48B),
+ 0x48C => array(0x48D),
+ 0x48E => array(0x48F),
+ 0x490 => array(0x491),
+ 0x492 => array(0x493),
+ 0x494 => array(0x495),
+ 0x496 => array(0x497),
+ 0x498 => array(0x499),
+ 0x49A => array(0x49B),
+ 0x49C => array(0x49D),
+ 0x49E => array(0x49F),
+ 0x4A0 => array(0x4A1),
+ 0x4A2 => array(0x4A3),
+ 0x4A4 => array(0x4A5),
+ 0x4A6 => array(0x4A7),
+ 0x4A8 => array(0x4A9),
+ 0x4AA => array(0x4AB),
+ 0x4AC => array(0x4AD),
+ 0x4AE => array(0x4AF),
+ 0x4B0 => array(0x4B1),
+ 0x4B2 => array(0x4B3),
+ 0x4B4 => array(0x4B5),
+ 0x4B6 => array(0x4B7),
+ 0x4B8 => array(0x4B9),
+ 0x4BA => array(0x4BB),
+ 0x4BC => array(0x4BD),
+ 0x4BE => array(0x4BF),
+ 0x4C1 => array(0x4C2),
+ 0x4C3 => array(0x4C4),
+ 0x4C5 => array(0x4C6),
+ 0x4C7 => array(0x4C8),
+ 0x4C9 => array(0x4CA),
+ 0x4CB => array(0x4CC),
+ 0x4CD => array(0x4CE),
+ 0x4D0 => array(0x4D1),
+ 0x4D2 => array(0x4D3),
+ 0x4D4 => array(0x4D5),
+ 0x4D6 => array(0x4D7),
+ 0x4D8 => array(0x4D9),
+ 0x4DA => array(0x4DB),
+ 0x4DC => array(0x4DD),
+ 0x4DE => array(0x4DF),
+ 0x4E0 => array(0x4E1),
+ 0x4E2 => array(0x4E3),
+ 0x4E4 => array(0x4E5),
+ 0x4E6 => array(0x4E7),
+ 0x4E8 => array(0x4E9),
+ 0x4EA => array(0x4EB),
+ 0x4EC => array(0x4ED),
+ 0x4EE => array(0x4EF),
+ 0x4F0 => array(0x4F1),
+ 0x4F2 => array(0x4F3),
+ 0x4F4 => array(0x4F5),
+ 0x4F8 => array(0x4F9),
+ 0x500 => array(0x501),
+ 0x502 => array(0x503),
+ 0x504 => array(0x505),
+ 0x506 => array(0x507),
+ 0x508 => array(0x509),
+ 0x50A => array(0x50B),
+ 0x50C => array(0x50D),
+ 0x50E => array(0x50F),
+ 0x531 => array(0x561),
+ 0x532 => array(0x562),
+ 0x533 => array(0x563),
+ 0x534 => array(0x564),
+ 0x535 => array(0x565),
+ 0x536 => array(0x566),
+ 0x537 => array(0x567),
+ 0x538 => array(0x568),
+ 0x539 => array(0x569),
+ 0x53A => array(0x56A),
+ 0x53B => array(0x56B),
+ 0x53C => array(0x56C),
+ 0x53D => array(0x56D),
+ 0x53E => array(0x56E),
+ 0x53F => array(0x56F),
+ 0x540 => array(0x570),
+ 0x541 => array(0x571),
+ 0x542 => array(0x572),
+ 0x543 => array(0x573),
+ 0x544 => array(0x574),
+ 0x545 => array(0x575),
+ 0x546 => array(0x576),
+ 0x547 => array(0x577),
+ 0x548 => array(0x578),
+ 0x549 => array(0x579),
+ 0x54A => array(0x57A),
+ 0x54B => array(0x57B),
+ 0x54C => array(0x57C),
+ 0x54D => array(0x57D),
+ 0x54E => array(0x57E),
+ 0x54F => array(0x57F),
+ 0x550 => array(0x580),
+ 0x551 => array(0x581),
+ 0x552 => array(0x582),
+ 0x553 => array(0x583),
+ 0x554 => array(0x584),
+ 0x555 => array(0x585),
+ 0x556 => array(0x586),
+ 0x587 => array(0x565, 0x582),
+ 0x1E00 => array(0x1E01),
+ 0x1E02 => array(0x1E03),
+ 0x1E04 => array(0x1E05),
+ 0x1E06 => array(0x1E07),
+ 0x1E08 => array(0x1E09),
+ 0x1E0A => array(0x1E0B),
+ 0x1E0C => array(0x1E0D),
+ 0x1E0E => array(0x1E0F),
+ 0x1E10 => array(0x1E11),
+ 0x1E12 => array(0x1E13),
+ 0x1E14 => array(0x1E15),
+ 0x1E16 => array(0x1E17),
+ 0x1E18 => array(0x1E19),
+ 0x1E1A => array(0x1E1B),
+ 0x1E1C => array(0x1E1D),
+ 0x1E1E => array(0x1E1F),
+ 0x1E20 => array(0x1E21),
+ 0x1E22 => array(0x1E23),
+ 0x1E24 => array(0x1E25),
+ 0x1E26 => array(0x1E27),
+ 0x1E28 => array(0x1E29),
+ 0x1E2A => array(0x1E2B),
+ 0x1E2C => array(0x1E2D),
+ 0x1E2E => array(0x1E2F),
+ 0x1E30 => array(0x1E31),
+ 0x1E32 => array(0x1E33),
+ 0x1E34 => array(0x1E35),
+ 0x1E36 => array(0x1E37),
+ 0x1E38 => array(0x1E39),
+ 0x1E3A => array(0x1E3B),
+ 0x1E3C => array(0x1E3D),
+ 0x1E3E => array(0x1E3F),
+ 0x1E40 => array(0x1E41),
+ 0x1E42 => array(0x1E43),
+ 0x1E44 => array(0x1E45),
+ 0x1E46 => array(0x1E47),
+ 0x1E48 => array(0x1E49),
+ 0x1E4A => array(0x1E4B),
+ 0x1E4C => array(0x1E4D),
+ 0x1E4E => array(0x1E4F),
+ 0x1E50 => array(0x1E51),
+ 0x1E52 => array(0x1E53),
+ 0x1E54 => array(0x1E55),
+ 0x1E56 => array(0x1E57),
+ 0x1E58 => array(0x1E59),
+ 0x1E5A => array(0x1E5B),
+ 0x1E5C => array(0x1E5D),
+ 0x1E5E => array(0x1E5F),
+ 0x1E60 => array(0x1E61),
+ 0x1E62 => array(0x1E63),
+ 0x1E64 => array(0x1E65),
+ 0x1E66 => array(0x1E67),
+ 0x1E68 => array(0x1E69),
+ 0x1E6A => array(0x1E6B),
+ 0x1E6C => array(0x1E6D),
+ 0x1E6E => array(0x1E6F),
+ 0x1E70 => array(0x1E71),
+ 0x1E72 => array(0x1E73),
+ 0x1E74 => array(0x1E75),
+ 0x1E76 => array(0x1E77),
+ 0x1E78 => array(0x1E79),
+ 0x1E7A => array(0x1E7B),
+ 0x1E7C => array(0x1E7D),
+ 0x1E7E => array(0x1E7F),
+ 0x1E80 => array(0x1E81),
+ 0x1E82 => array(0x1E83),
+ 0x1E84 => array(0x1E85),
+ 0x1E86 => array(0x1E87),
+ 0x1E88 => array(0x1E89),
+ 0x1E8A => array(0x1E8B),
+ 0x1E8C => array(0x1E8D),
+ 0x1E8E => array(0x1E8F),
+ 0x1E90 => array(0x1E91),
+ 0x1E92 => array(0x1E93),
+ 0x1E94 => array(0x1E95),
+ 0x1E96 => array(0x68, 0x331),
+ 0x1E97 => array(0x74, 0x308),
+ 0x1E98 => array(0x77, 0x30A),
+ 0x1E99 => array(0x79, 0x30A),
+ 0x1E9A => array(0x61, 0x2BE),
+ 0x1E9B => array(0x1E61),
+ 0x1EA0 => array(0x1EA1),
+ 0x1EA2 => array(0x1EA3),
+ 0x1EA4 => array(0x1EA5),
+ 0x1EA6 => array(0x1EA7),
+ 0x1EA8 => array(0x1EA9),
+ 0x1EAA => array(0x1EAB),
+ 0x1EAC => array(0x1EAD),
+ 0x1EAE => array(0x1EAF),
+ 0x1EB0 => array(0x1EB1),
+ 0x1EB2 => array(0x1EB3),
+ 0x1EB4 => array(0x1EB5),
+ 0x1EB6 => array(0x1EB7),
+ 0x1EB8 => array(0x1EB9),
+ 0x1EBA => array(0x1EBB),
+ 0x1EBC => array(0x1EBD),
+ 0x1EBE => array(0x1EBF),
+ 0x1EC0 => array(0x1EC1),
+ 0x1EC2 => array(0x1EC3),
+ 0x1EC4 => array(0x1EC5),
+ 0x1EC6 => array(0x1EC7),
+ 0x1EC8 => array(0x1EC9),
+ 0x1ECA => array(0x1ECB),
+ 0x1ECC => array(0x1ECD),
+ 0x1ECE => array(0x1ECF),
+ 0x1ED0 => array(0x1ED1),
+ 0x1ED2 => array(0x1ED3),
+ 0x1ED4 => array(0x1ED5),
+ 0x1ED6 => array(0x1ED7),
+ 0x1ED8 => array(0x1ED9),
+ 0x1EDA => array(0x1EDB),
+ 0x1EDC => array(0x1EDD),
+ 0x1EDE => array(0x1EDF),
+ 0x1EE0 => array(0x1EE1),
+ 0x1EE2 => array(0x1EE3),
+ 0x1EE4 => array(0x1EE5),
+ 0x1EE6 => array(0x1EE7),
+ 0x1EE8 => array(0x1EE9),
+ 0x1EEA => array(0x1EEB),
+ 0x1EEC => array(0x1EED),
+ 0x1EEE => array(0x1EEF),
+ 0x1EF0 => array(0x1EF1),
+ 0x1EF2 => array(0x1EF3),
+ 0x1EF4 => array(0x1EF5),
+ 0x1EF6 => array(0x1EF7),
+ 0x1EF8 => array(0x1EF9),
+ 0x1F08 => array(0x1F00),
+ 0x1F09 => array(0x1F01),
+ 0x1F0A => array(0x1F02),
+ 0x1F0B => array(0x1F03),
+ 0x1F0C => array(0x1F04),
+ 0x1F0D => array(0x1F05),
+ 0x1F0E => array(0x1F06),
+ 0x1F0F => array(0x1F07),
+ 0x1F18 => array(0x1F10),
+ 0x1F19 => array(0x1F11),
+ 0x1F1A => array(0x1F12),
+ 0x1F1B => array(0x1F13),
+ 0x1F1C => array(0x1F14),
+ 0x1F1D => array(0x1F15),
+ 0x1F28 => array(0x1F20),
+ 0x1F29 => array(0x1F21),
+ 0x1F2A => array(0x1F22),
+ 0x1F2B => array(0x1F23),
+ 0x1F2C => array(0x1F24),
+ 0x1F2D => array(0x1F25),
+ 0x1F2E => array(0x1F26),
+ 0x1F2F => array(0x1F27),
+ 0x1F38 => array(0x1F30),
+ 0x1F39 => array(0x1F31),
+ 0x1F3A => array(0x1F32),
+ 0x1F3B => array(0x1F33),
+ 0x1F3C => array(0x1F34),
+ 0x1F3D => array(0x1F35),
+ 0x1F3E => array(0x1F36),
+ 0x1F3F => array(0x1F37),
+ 0x1F48 => array(0x1F40),
+ 0x1F49 => array(0x1F41),
+ 0x1F4A => array(0x1F42),
+ 0x1F4B => array(0x1F43),
+ 0x1F4C => array(0x1F44),
+ 0x1F4D => array(0x1F45),
+ 0x1F50 => array(0x3C5, 0x313),
+ 0x1F52 => array(0x3C5, 0x313, 0x300),
+ 0x1F54 => array(0x3C5, 0x313, 0x301),
+ 0x1F56 => array(0x3C5, 0x313, 0x342),
+ 0x1F59 => array(0x1F51),
+ 0x1F5B => array(0x1F53),
+ 0x1F5D => array(0x1F55),
+ 0x1F5F => array(0x1F57),
+ 0x1F68 => array(0x1F60),
+ 0x1F69 => array(0x1F61),
+ 0x1F6A => array(0x1F62),
+ 0x1F6B => array(0x1F63),
+ 0x1F6C => array(0x1F64),
+ 0x1F6D => array(0x1F65),
+ 0x1F6E => array(0x1F66),
+ 0x1F6F => array(0x1F67),
+ 0x1F80 => array(0x1F00, 0x3B9),
+ 0x1F81 => array(0x1F01, 0x3B9),
+ 0x1F82 => array(0x1F02, 0x3B9),
+ 0x1F83 => array(0x1F03, 0x3B9),
+ 0x1F84 => array(0x1F04, 0x3B9),
+ 0x1F85 => array(0x1F05, 0x3B9),
+ 0x1F86 => array(0x1F06, 0x3B9),
+ 0x1F87 => array(0x1F07, 0x3B9),
+ 0x1F88 => array(0x1F00, 0x3B9),
+ 0x1F89 => array(0x1F01, 0x3B9),
+ 0x1F8A => array(0x1F02, 0x3B9),
+ 0x1F8B => array(0x1F03, 0x3B9),
+ 0x1F8C => array(0x1F04, 0x3B9),
+ 0x1F8D => array(0x1F05, 0x3B9),
+ 0x1F8E => array(0x1F06, 0x3B9),
+ 0x1F8F => array(0x1F07, 0x3B9),
+ 0x1F90 => array(0x1F20, 0x3B9),
+ 0x1F91 => array(0x1F21, 0x3B9),
+ 0x1F92 => array(0x1F22, 0x3B9),
+ 0x1F93 => array(0x1F23, 0x3B9),
+ 0x1F94 => array(0x1F24, 0x3B9),
+ 0x1F95 => array(0x1F25, 0x3B9),
+ 0x1F96 => array(0x1F26, 0x3B9),
+ 0x1F97 => array(0x1F27, 0x3B9),
+ 0x1F98 => array(0x1F20, 0x3B9),
+ 0x1F99 => array(0x1F21, 0x3B9),
+ 0x1F9A => array(0x1F22, 0x3B9),
+ 0x1F9B => array(0x1F23, 0x3B9),
+ 0x1F9C => array(0x1F24, 0x3B9),
+ 0x1F9D => array(0x1F25, 0x3B9),
+ 0x1F9E => array(0x1F26, 0x3B9),
+ 0x1F9F => array(0x1F27, 0x3B9),
+ 0x1FA0 => array(0x1F60, 0x3B9),
+ 0x1FA1 => array(0x1F61, 0x3B9),
+ 0x1FA2 => array(0x1F62, 0x3B9),
+ 0x1FA3 => array(0x1F63, 0x3B9),
+ 0x1FA4 => array(0x1F64, 0x3B9),
+ 0x1FA5 => array(0x1F65, 0x3B9),
+ 0x1FA6 => array(0x1F66, 0x3B9),
+ 0x1FA7 => array(0x1F67, 0x3B9),
+ 0x1FA8 => array(0x1F60, 0x3B9),
+ 0x1FA9 => array(0x1F61, 0x3B9),
+ 0x1FAA => array(0x1F62, 0x3B9),
+ 0x1FAB => array(0x1F63, 0x3B9),
+ 0x1FAC => array(0x1F64, 0x3B9),
+ 0x1FAD => array(0x1F65, 0x3B9),
+ 0x1FAE => array(0x1F66, 0x3B9),
+ 0x1FAF => array(0x1F67, 0x3B9),
+ 0x1FB2 => array(0x1F70, 0x3B9),
+ 0x1FB3 => array(0x3B1, 0x3B9),
+ 0x1FB4 => array(0x3AC, 0x3B9),
+ 0x1FB6 => array(0x3B1, 0x342),
+ 0x1FB7 => array(0x3B1, 0x342, 0x3B9),
+ 0x1FB8 => array(0x1FB0),
+ 0x1FB9 => array(0x1FB1),
+ 0x1FBA => array(0x1F70),
+ 0x1FBB => array(0x1F71),
+ 0x1FBC => array(0x3B1, 0x3B9),
+ 0x1FBE => array(0x3B9),
+ 0x1FC2 => array(0x1F74, 0x3B9),
+ 0x1FC3 => array(0x3B7, 0x3B9),
+ 0x1FC4 => array(0x3AE, 0x3B9),
+ 0x1FC6 => array(0x3B7, 0x342),
+ 0x1FC7 => array(0x3B7, 0x342, 0x3B9),
+ 0x1FC8 => array(0x1F72),
+ 0x1FC9 => array(0x1F73),
+ 0x1FCA => array(0x1F74),
+ 0x1FCB => array(0x1F75),
+ 0x1FCC => array(0x3B7, 0x3B9),
+ 0x1FD2 => array(0x3B9, 0x308, 0x300),
+ 0x1FD3 => array(0x3B9, 0x308, 0x301),
+ 0x1FD6 => array(0x3B9, 0x342),
+ 0x1FD7 => array(0x3B9, 0x308, 0x342),
+ 0x1FD8 => array(0x1FD0),
+ 0x1FD9 => array(0x1FD1),
+ 0x1FDA => array(0x1F76),
+ 0x1FDB => array(0x1F77),
+ 0x1FE2 => array(0x3C5, 0x308, 0x300),
+ 0x1FE3 => array(0x3C5, 0x308, 0x301),
+ 0x1FE4 => array(0x3C1, 0x313),
+ 0x1FE6 => array(0x3C5, 0x342),
+ 0x1FE7 => array(0x3C5, 0x308, 0x342),
+ 0x1FE8 => array(0x1FE0),
+ 0x1FE9 => array(0x1FE1),
+ 0x1FEA => array(0x1F7A),
+ 0x1FEB => array(0x1F7B),
+ 0x1FEC => array(0x1FE5),
+ 0x1FF2 => array(0x1F7C, 0x3B9),
+ 0x1FF3 => array(0x3C9, 0x3B9),
+ 0x1FF4 => array(0x3CE, 0x3B9),
+ 0x1FF6 => array(0x3C9, 0x342),
+ 0x1FF7 => array(0x3C9, 0x342, 0x3B9),
+ 0x1FF8 => array(0x1F78),
+ 0x1FF9 => array(0x1F79),
+ 0x1FFA => array(0x1F7C),
+ 0x1FFB => array(0x1F7D),
+ 0x1FFC => array(0x3C9, 0x3B9),
+ 0x20A8 => array(0x72, 0x73),
+ 0x2102 => array(0x63),
+ 0x2103 => array(0xB0, 0x63),
+ 0x2107 => array(0x25B),
+ 0x2109 => array(0xB0, 0x66),
+ 0x210B => array(0x68),
+ 0x210C => array(0x68),
+ 0x210D => array(0x68),
+ 0x2110 => array(0x69),
+ 0x2111 => array(0x69),
+ 0x2112 => array(0x6C),
+ 0x2115 => array(0x6E),
+ 0x2116 => array(0x6E, 0x6F),
+ 0x2119 => array(0x70),
+ 0x211A => array(0x71),
+ 0x211B => array(0x72),
+ 0x211C => array(0x72),
+ 0x211D => array(0x72),
+ 0x2120 => array(0x73, 0x6D),
+ 0x2121 => array(0x74, 0x65, 0x6C),
+ 0x2122 => array(0x74, 0x6D),
+ 0x2124 => array(0x7A),
+ 0x2126 => array(0x3C9),
+ 0x2128 => array(0x7A),
+ 0x212A => array(0x6B),
+ 0x212B => array(0xE5),
+ 0x212C => array(0x62),
+ 0x212D => array(0x63),
+ 0x2130 => array(0x65),
+ 0x2131 => array(0x66),
+ 0x2133 => array(0x6D),
+ 0x213E => array(0x3B3),
+ 0x213F => array(0x3C0),
+ 0x2145 => array(0x64),
+ 0x2160 => array(0x2170),
+ 0x2161 => array(0x2171),
+ 0x2162 => array(0x2172),
+ 0x2163 => array(0x2173),
+ 0x2164 => array(0x2174),
+ 0x2165 => array(0x2175),
+ 0x2166 => array(0x2176),
+ 0x2167 => array(0x2177),
+ 0x2168 => array(0x2178),
+ 0x2169 => array(0x2179),
+ 0x216A => array(0x217A),
+ 0x216B => array(0x217B),
+ 0x216C => array(0x217C),
+ 0x216D => array(0x217D),
+ 0x216E => array(0x217E),
+ 0x216F => array(0x217F),
+ 0x24B6 => array(0x24D0),
+ 0x24B7 => array(0x24D1),
+ 0x24B8 => array(0x24D2),
+ 0x24B9 => array(0x24D3),
+ 0x24BA => array(0x24D4),
+ 0x24BB => array(0x24D5),
+ 0x24BC => array(0x24D6),
+ 0x24BD => array(0x24D7),
+ 0x24BE => array(0x24D8),
+ 0x24BF => array(0x24D9),
+ 0x24C0 => array(0x24DA),
+ 0x24C1 => array(0x24DB),
+ 0x24C2 => array(0x24DC),
+ 0x24C3 => array(0x24DD),
+ 0x24C4 => array(0x24DE),
+ 0x24C5 => array(0x24DF),
+ 0x24C6 => array(0x24E0),
+ 0x24C7 => array(0x24E1),
+ 0x24C8 => array(0x24E2),
+ 0x24C9 => array(0x24E3),
+ 0x24CA => array(0x24E4),
+ 0x24CB => array(0x24E5),
+ 0x24CC => array(0x24E6),
+ 0x24CD => array(0x24E7),
+ 0x24CE => array(0x24E8),
+ 0x24CF => array(0x24E9),
+ 0x3371 => array(0x68, 0x70, 0x61),
+ 0x3373 => array(0x61, 0x75),
+ 0x3375 => array(0x6F, 0x76),
+ 0x3380 => array(0x70, 0x61),
+ 0x3381 => array(0x6E, 0x61),
+ 0x3382 => array(0x3BC, 0x61),
+ 0x3383 => array(0x6D, 0x61),
+ 0x3384 => array(0x6B, 0x61),
+ 0x3385 => array(0x6B, 0x62),
+ 0x3386 => array(0x6D, 0x62),
+ 0x3387 => array(0x67, 0x62),
+ 0x338A => array(0x70, 0x66),
+ 0x338B => array(0x6E, 0x66),
+ 0x338C => array(0x3BC, 0x66),
+ 0x3390 => array(0x68, 0x7A),
+ 0x3391 => array(0x6B, 0x68, 0x7A),
+ 0x3392 => array(0x6D, 0x68, 0x7A),
+ 0x3393 => array(0x67, 0x68, 0x7A),
+ 0x3394 => array(0x74, 0x68, 0x7A),
+ 0x33A9 => array(0x70, 0x61),
+ 0x33AA => array(0x6B, 0x70, 0x61),
+ 0x33AB => array(0x6D, 0x70, 0x61),
+ 0x33AC => array(0x67, 0x70, 0x61),
+ 0x33B4 => array(0x70, 0x76),
+ 0x33B5 => array(0x6E, 0x76),
+ 0x33B6 => array(0x3BC, 0x76),
+ 0x33B7 => array(0x6D, 0x76),
+ 0x33B8 => array(0x6B, 0x76),
+ 0x33B9 => array(0x6D, 0x76),
+ 0x33BA => array(0x70, 0x77),
+ 0x33BB => array(0x6E, 0x77),
+ 0x33BC => array(0x3BC, 0x77),
+ 0x33BD => array(0x6D, 0x77),
+ 0x33BE => array(0x6B, 0x77),
+ 0x33BF => array(0x6D, 0x77),
+ 0x33C0 => array(0x6B, 0x3C9),
+ 0x33C1 => array(0x6D, 0x3C9),
+ /* 0x33C2 => array(0x61, 0x2E, 0x6D, 0x2E), */
+ 0x33C3 => array(0x62, 0x71),
+ 0x33C6 => array(0x63, 0x2215, 0x6B, 0x67),
+ 0x33C7 => array(0x63, 0x6F, 0x2E),
+ 0x33C8 => array(0x64, 0x62),
+ 0x33C9 => array(0x67, 0x79),
+ 0x33CB => array(0x68, 0x70),
+ 0x33CD => array(0x6B, 0x6B),
+ 0x33CE => array(0x6B, 0x6D),
+ 0x33D7 => array(0x70, 0x68),
+ 0x33D9 => array(0x70, 0x70, 0x6D),
+ 0x33DA => array(0x70, 0x72),
+ 0x33DC => array(0x73, 0x76),
+ 0x33DD => array(0x77, 0x62),
+ 0xFB00 => array(0x66, 0x66),
+ 0xFB01 => array(0x66, 0x69),
+ 0xFB02 => array(0x66, 0x6C),
+ 0xFB03 => array(0x66, 0x66, 0x69),
+ 0xFB04 => array(0x66, 0x66, 0x6C),
+ 0xFB05 => array(0x73, 0x74),
+ 0xFB06 => array(0x73, 0x74),
+ 0xFB13 => array(0x574, 0x576),
+ 0xFB14 => array(0x574, 0x565),
+ 0xFB15 => array(0x574, 0x56B),
+ 0xFB16 => array(0x57E, 0x576),
+ 0xFB17 => array(0x574, 0x56D),
+ 0xFF21 => array(0xFF41),
+ 0xFF22 => array(0xFF42),
+ 0xFF23 => array(0xFF43),
+ 0xFF24 => array(0xFF44),
+ 0xFF25 => array(0xFF45),
+ 0xFF26 => array(0xFF46),
+ 0xFF27 => array(0xFF47),
+ 0xFF28 => array(0xFF48),
+ 0xFF29 => array(0xFF49),
+ 0xFF2A => array(0xFF4A),
+ 0xFF2B => array(0xFF4B),
+ 0xFF2C => array(0xFF4C),
+ 0xFF2D => array(0xFF4D),
+ 0xFF2E => array(0xFF4E),
+ 0xFF2F => array(0xFF4F),
+ 0xFF30 => array(0xFF50),
+ 0xFF31 => array(0xFF51),
+ 0xFF32 => array(0xFF52),
+ 0xFF33 => array(0xFF53),
+ 0xFF34 => array(0xFF54),
+ 0xFF35 => array(0xFF55),
+ 0xFF36 => array(0xFF56),
+ 0xFF37 => array(0xFF57),
+ 0xFF38 => array(0xFF58),
+ 0xFF39 => array(0xFF59),
+ 0xFF3A => array(0xFF5A),
+ 0x10400 => array(0x10428),
+ 0x10401 => array(0x10429),
+ 0x10402 => array(0x1042A),
+ 0x10403 => array(0x1042B),
+ 0x10404 => array(0x1042C),
+ 0x10405 => array(0x1042D),
+ 0x10406 => array(0x1042E),
+ 0x10407 => array(0x1042F),
+ 0x10408 => array(0x10430),
+ 0x10409 => array(0x10431),
+ 0x1040A => array(0x10432),
+ 0x1040B => array(0x10433),
+ 0x1040C => array(0x10434),
+ 0x1040D => array(0x10435),
+ 0x1040E => array(0x10436),
+ 0x1040F => array(0x10437),
+ 0x10410 => array(0x10438),
+ 0x10411 => array(0x10439),
+ 0x10412 => array(0x1043A),
+ 0x10413 => array(0x1043B),
+ 0x10414 => array(0x1043C),
+ 0x10415 => array(0x1043D),
+ 0x10416 => array(0x1043E),
+ 0x10417 => array(0x1043F),
+ 0x10418 => array(0x10440),
+ 0x10419 => array(0x10441),
+ 0x1041A => array(0x10442),
+ 0x1041B => array(0x10443),
+ 0x1041C => array(0x10444),
+ 0x1041D => array(0x10445),
+ 0x1041E => array(0x10446),
+ 0x1041F => array(0x10447),
+ 0x10420 => array(0x10448),
+ 0x10421 => array(0x10449),
+ 0x10422 => array(0x1044A),
+ 0x10423 => array(0x1044B),
+ 0x10424 => array(0x1044C),
+ 0x10425 => array(0x1044D),
+ 0x1D400 => array(0x61),
+ 0x1D401 => array(0x62),
+ 0x1D402 => array(0x63),
+ 0x1D403 => array(0x64),
+ 0x1D404 => array(0x65),
+ 0x1D405 => array(0x66),
+ 0x1D406 => array(0x67),
+ 0x1D407 => array(0x68),
+ 0x1D408 => array(0x69),
+ 0x1D409 => array(0x6A),
+ 0x1D40A => array(0x6B),
+ 0x1D40B => array(0x6C),
+ 0x1D40C => array(0x6D),
+ 0x1D40D => array(0x6E),
+ 0x1D40E => array(0x6F),
+ 0x1D40F => array(0x70),
+ 0x1D410 => array(0x71),
+ 0x1D411 => array(0x72),
+ 0x1D412 => array(0x73),
+ 0x1D413 => array(0x74),
+ 0x1D414 => array(0x75),
+ 0x1D415 => array(0x76),
+ 0x1D416 => array(0x77),
+ 0x1D417 => array(0x78),
+ 0x1D418 => array(0x79),
+ 0x1D419 => array(0x7A),
+ 0x1D434 => array(0x61),
+ 0x1D435 => array(0x62),
+ 0x1D436 => array(0x63),
+ 0x1D437 => array(0x64),
+ 0x1D438 => array(0x65),
+ 0x1D439 => array(0x66),
+ 0x1D43A => array(0x67),
+ 0x1D43B => array(0x68),
+ 0x1D43C => array(0x69),
+ 0x1D43D => array(0x6A),
+ 0x1D43E => array(0x6B),
+ 0x1D43F => array(0x6C),
+ 0x1D440 => array(0x6D),
+ 0x1D441 => array(0x6E),
+ 0x1D442 => array(0x6F),
+ 0x1D443 => array(0x70),
+ 0x1D444 => array(0x71),
+ 0x1D445 => array(0x72),
+ 0x1D446 => array(0x73),
+ 0x1D447 => array(0x74),
+ 0x1D448 => array(0x75),
+ 0x1D449 => array(0x76),
+ 0x1D44A => array(0x77),
+ 0x1D44B => array(0x78),
+ 0x1D44C => array(0x79),
+ 0x1D44D => array(0x7A),
+ 0x1D468 => array(0x61),
+ 0x1D469 => array(0x62),
+ 0x1D46A => array(0x63),
+ 0x1D46B => array(0x64),
+ 0x1D46C => array(0x65),
+ 0x1D46D => array(0x66),
+ 0x1D46E => array(0x67),
+ 0x1D46F => array(0x68),
+ 0x1D470 => array(0x69),
+ 0x1D471 => array(0x6A),
+ 0x1D472 => array(0x6B),
+ 0x1D473 => array(0x6C),
+ 0x1D474 => array(0x6D),
+ 0x1D475 => array(0x6E),
+ 0x1D476 => array(0x6F),
+ 0x1D477 => array(0x70),
+ 0x1D478 => array(0x71),
+ 0x1D479 => array(0x72),
+ 0x1D47A => array(0x73),
+ 0x1D47B => array(0x74),
+ 0x1D47C => array(0x75),
+ 0x1D47D => array(0x76),
+ 0x1D47E => array(0x77),
+ 0x1D47F => array(0x78),
+ 0x1D480 => array(0x79),
+ 0x1D481 => array(0x7A),
+ 0x1D49C => array(0x61),
+ 0x1D49E => array(0x63),
+ 0x1D49F => array(0x64),
+ 0x1D4A2 => array(0x67),
+ 0x1D4A5 => array(0x6A),
+ 0x1D4A6 => array(0x6B),
+ 0x1D4A9 => array(0x6E),
+ 0x1D4AA => array(0x6F),
+ 0x1D4AB => array(0x70),
+ 0x1D4AC => array(0x71),
+ 0x1D4AE => array(0x73),
+ 0x1D4AF => array(0x74),
+ 0x1D4B0 => array(0x75),
+ 0x1D4B1 => array(0x76),
+ 0x1D4B2 => array(0x77),
+ 0x1D4B3 => array(0x78),
+ 0x1D4B4 => array(0x79),
+ 0x1D4B5 => array(0x7A),
+ 0x1D4D0 => array(0x61),
+ 0x1D4D1 => array(0x62),
+ 0x1D4D2 => array(0x63),
+ 0x1D4D3 => array(0x64),
+ 0x1D4D4 => array(0x65),
+ 0x1D4D5 => array(0x66),
+ 0x1D4D6 => array(0x67),
+ 0x1D4D7 => array(0x68),
+ 0x1D4D8 => array(0x69),
+ 0x1D4D9 => array(0x6A),
+ 0x1D4DA => array(0x6B),
+ 0x1D4DB => array(0x6C),
+ 0x1D4DC => array(0x6D),
+ 0x1D4DD => array(0x6E),
+ 0x1D4DE => array(0x6F),
+ 0x1D4DF => array(0x70),
+ 0x1D4E0 => array(0x71),
+ 0x1D4E1 => array(0x72),
+ 0x1D4E2 => array(0x73),
+ 0x1D4E3 => array(0x74),
+ 0x1D4E4 => array(0x75),
+ 0x1D4E5 => array(0x76),
+ 0x1D4E6 => array(0x77),
+ 0x1D4E7 => array(0x78),
+ 0x1D4E8 => array(0x79),
+ 0x1D4E9 => array(0x7A),
+ 0x1D504 => array(0x61),
+ 0x1D505 => array(0x62),
+ 0x1D507 => array(0x64),
+ 0x1D508 => array(0x65),
+ 0x1D509 => array(0x66),
+ 0x1D50A => array(0x67),
+ 0x1D50D => array(0x6A),
+ 0x1D50E => array(0x6B),
+ 0x1D50F => array(0x6C),
+ 0x1D510 => array(0x6D),
+ 0x1D511 => array(0x6E),
+ 0x1D512 => array(0x6F),
+ 0x1D513 => array(0x70),
+ 0x1D514 => array(0x71),
+ 0x1D516 => array(0x73),
+ 0x1D517 => array(0x74),
+ 0x1D518 => array(0x75),
+ 0x1D519 => array(0x76),
+ 0x1D51A => array(0x77),
+ 0x1D51B => array(0x78),
+ 0x1D51C => array(0x79),
+ 0x1D538 => array(0x61),
+ 0x1D539 => array(0x62),
+ 0x1D53B => array(0x64),
+ 0x1D53C => array(0x65),
+ 0x1D53D => array(0x66),
+ 0x1D53E => array(0x67),
+ 0x1D540 => array(0x69),
+ 0x1D541 => array(0x6A),
+ 0x1D542 => array(0x6B),
+ 0x1D543 => array(0x6C),
+ 0x1D544 => array(0x6D),
+ 0x1D546 => array(0x6F),
+ 0x1D54A => array(0x73),
+ 0x1D54B => array(0x74),
+ 0x1D54C => array(0x75),
+ 0x1D54D => array(0x76),
+ 0x1D54E => array(0x77),
+ 0x1D54F => array(0x78),
+ 0x1D550 => array(0x79),
+ 0x1D56C => array(0x61),
+ 0x1D56D => array(0x62),
+ 0x1D56E => array(0x63),
+ 0x1D56F => array(0x64),
+ 0x1D570 => array(0x65),
+ 0x1D571 => array(0x66),
+ 0x1D572 => array(0x67),
+ 0x1D573 => array(0x68),
+ 0x1D574 => array(0x69),
+ 0x1D575 => array(0x6A),
+ 0x1D576 => array(0x6B),
+ 0x1D577 => array(0x6C),
+ 0x1D578 => array(0x6D),
+ 0x1D579 => array(0x6E),
+ 0x1D57A => array(0x6F),
+ 0x1D57B => array(0x70),
+ 0x1D57C => array(0x71),
+ 0x1D57D => array(0x72),
+ 0x1D57E => array(0x73),
+ 0x1D57F => array(0x74),
+ 0x1D580 => array(0x75),
+ 0x1D581 => array(0x76),
+ 0x1D582 => array(0x77),
+ 0x1D583 => array(0x78),
+ 0x1D584 => array(0x79),
+ 0x1D585 => array(0x7A),
+ 0x1D5A0 => array(0x61),
+ 0x1D5A1 => array(0x62),
+ 0x1D5A2 => array(0x63),
+ 0x1D5A3 => array(0x64),
+ 0x1D5A4 => array(0x65),
+ 0x1D5A5 => array(0x66),
+ 0x1D5A6 => array(0x67),
+ 0x1D5A7 => array(0x68),
+ 0x1D5A8 => array(0x69),
+ 0x1D5A9 => array(0x6A),
+ 0x1D5AA => array(0x6B),
+ 0x1D5AB => array(0x6C),
+ 0x1D5AC => array(0x6D),
+ 0x1D5AD => array(0x6E),
+ 0x1D5AE => array(0x6F),
+ 0x1D5AF => array(0x70),
+ 0x1D5B0 => array(0x71),
+ 0x1D5B1 => array(0x72),
+ 0x1D5B2 => array(0x73),
+ 0x1D5B3 => array(0x74),
+ 0x1D5B4 => array(0x75),
+ 0x1D5B5 => array(0x76),
+ 0x1D5B6 => array(0x77),
+ 0x1D5B7 => array(0x78),
+ 0x1D5B8 => array(0x79),
+ 0x1D5B9 => array(0x7A),
+ 0x1D5D4 => array(0x61),
+ 0x1D5D5 => array(0x62),
+ 0x1D5D6 => array(0x63),
+ 0x1D5D7 => array(0x64),
+ 0x1D5D8 => array(0x65),
+ 0x1D5D9 => array(0x66),
+ 0x1D5DA => array(0x67),
+ 0x1D5DB => array(0x68),
+ 0x1D5DC => array(0x69),
+ 0x1D5DD => array(0x6A),
+ 0x1D5DE => array(0x6B),
+ 0x1D5DF => array(0x6C),
+ 0x1D5E0 => array(0x6D),
+ 0x1D5E1 => array(0x6E),
+ 0x1D5E2 => array(0x6F),
+ 0x1D5E3 => array(0x70),
+ 0x1D5E4 => array(0x71),
+ 0x1D5E5 => array(0x72),
+ 0x1D5E6 => array(0x73),
+ 0x1D5E7 => array(0x74),
+ 0x1D5E8 => array(0x75),
+ 0x1D5E9 => array(0x76),
+ 0x1D5EA => array(0x77),
+ 0x1D5EB => array(0x78),
+ 0x1D5EC => array(0x79),
+ 0x1D5ED => array(0x7A),
+ 0x1D608 => array(0x61),
+ 0x1D609 => array(0x62),
+ 0x1D60A => array(0x63),
+ 0x1D60B => array(0x64),
+ 0x1D60C => array(0x65),
+ 0x1D60D => array(0x66),
+ 0x1D60E => array(0x67),
+ 0x1D60F => array(0x68),
+ 0x1D610 => array(0x69),
+ 0x1D611 => array(0x6A),
+ 0x1D612 => array(0x6B),
+ 0x1D613 => array(0x6C),
+ 0x1D614 => array(0x6D),
+ 0x1D615 => array(0x6E),
+ 0x1D616 => array(0x6F),
+ 0x1D617 => array(0x70),
+ 0x1D618 => array(0x71),
+ 0x1D619 => array(0x72),
+ 0x1D61A => array(0x73),
+ 0x1D61B => array(0x74),
+ 0x1D61C => array(0x75),
+ 0x1D61D => array(0x76),
+ 0x1D61E => array(0x77),
+ 0x1D61F => array(0x78),
+ 0x1D620 => array(0x79),
+ 0x1D621 => array(0x7A),
+ 0x1D63C => array(0x61),
+ 0x1D63D => array(0x62),
+ 0x1D63E => array(0x63),
+ 0x1D63F => array(0x64),
+ 0x1D640 => array(0x65),
+ 0x1D641 => array(0x66),
+ 0x1D642 => array(0x67),
+ 0x1D643 => array(0x68),
+ 0x1D644 => array(0x69),
+ 0x1D645 => array(0x6A),
+ 0x1D646 => array(0x6B),
+ 0x1D647 => array(0x6C),
+ 0x1D648 => array(0x6D),
+ 0x1D649 => array(0x6E),
+ 0x1D64A => array(0x6F),
+ 0x1D64B => array(0x70),
+ 0x1D64C => array(0x71),
+ 0x1D64D => array(0x72),
+ 0x1D64E => array(0x73),
+ 0x1D64F => array(0x74),
+ 0x1D650 => array(0x75),
+ 0x1D651 => array(0x76),
+ 0x1D652 => array(0x77),
+ 0x1D653 => array(0x78),
+ 0x1D654 => array(0x79),
+ 0x1D655 => array(0x7A),
+ 0x1D670 => array(0x61),
+ 0x1D671 => array(0x62),
+ 0x1D672 => array(0x63),
+ 0x1D673 => array(0x64),
+ 0x1D674 => array(0x65),
+ 0x1D675 => array(0x66),
+ 0x1D676 => array(0x67),
+ 0x1D677 => array(0x68),
+ 0x1D678 => array(0x69),
+ 0x1D679 => array(0x6A),
+ 0x1D67A => array(0x6B),
+ 0x1D67B => array(0x6C),
+ 0x1D67C => array(0x6D),
+ 0x1D67D => array(0x6E),
+ 0x1D67E => array(0x6F),
+ 0x1D67F => array(0x70),
+ 0x1D680 => array(0x71),
+ 0x1D681 => array(0x72),
+ 0x1D682 => array(0x73),
+ 0x1D683 => array(0x74),
+ 0x1D684 => array(0x75),
+ 0x1D685 => array(0x76),
+ 0x1D686 => array(0x77),
+ 0x1D687 => array(0x78),
+ 0x1D688 => array(0x79),
+ 0x1D689 => array(0x7A),
+ 0x1D6A8 => array(0x3B1),
+ 0x1D6A9 => array(0x3B2),
+ 0x1D6AA => array(0x3B3),
+ 0x1D6AB => array(0x3B4),
+ 0x1D6AC => array(0x3B5),
+ 0x1D6AD => array(0x3B6),
+ 0x1D6AE => array(0x3B7),
+ 0x1D6AF => array(0x3B8),
+ 0x1D6B0 => array(0x3B9),
+ 0x1D6B1 => array(0x3BA),
+ 0x1D6B2 => array(0x3BB),
+ 0x1D6B3 => array(0x3BC),
+ 0x1D6B4 => array(0x3BD),
+ 0x1D6B5 => array(0x3BE),
+ 0x1D6B6 => array(0x3BF),
+ 0x1D6B7 => array(0x3C0),
+ 0x1D6B8 => array(0x3C1),
+ 0x1D6B9 => array(0x3B8),
+ 0x1D6BA => array(0x3C3),
+ 0x1D6BB => array(0x3C4),
+ 0x1D6BC => array(0x3C5),
+ 0x1D6BD => array(0x3C6),
+ 0x1D6BE => array(0x3C7),
+ 0x1D6BF => array(0x3C8),
+ 0x1D6C0 => array(0x3C9),
+ 0x1D6D3 => array(0x3C3),
+ 0x1D6E2 => array(0x3B1),
+ 0x1D6E3 => array(0x3B2),
+ 0x1D6E4 => array(0x3B3),
+ 0x1D6E5 => array(0x3B4),
+ 0x1D6E6 => array(0x3B5),
+ 0x1D6E7 => array(0x3B6),
+ 0x1D6E8 => array(0x3B7),
+ 0x1D6E9 => array(0x3B8),
+ 0x1D6EA => array(0x3B9),
+ 0x1D6EB => array(0x3BA),
+ 0x1D6EC => array(0x3BB),
+ 0x1D6ED => array(0x3BC),
+ 0x1D6EE => array(0x3BD),
+ 0x1D6EF => array(0x3BE),
+ 0x1D6F0 => array(0x3BF),
+ 0x1D6F1 => array(0x3C0),
+ 0x1D6F2 => array(0x3C1),
+ 0x1D6F3 => array(0x3B8),
+ 0x1D6F4 => array(0x3C3),
+ 0x1D6F5 => array(0x3C4),
+ 0x1D6F6 => array(0x3C5),
+ 0x1D6F7 => array(0x3C6),
+ 0x1D6F8 => array(0x3C7),
+ 0x1D6F9 => array(0x3C8),
+ 0x1D6FA => array(0x3C9),
+ 0x1D70D => array(0x3C3),
+ 0x1D71C => array(0x3B1),
+ 0x1D71D => array(0x3B2),
+ 0x1D71E => array(0x3B3),
+ 0x1D71F => array(0x3B4),
+ 0x1D720 => array(0x3B5),
+ 0x1D721 => array(0x3B6),
+ 0x1D722 => array(0x3B7),
+ 0x1D723 => array(0x3B8),
+ 0x1D724 => array(0x3B9),
+ 0x1D725 => array(0x3BA),
+ 0x1D726 => array(0x3BB),
+ 0x1D727 => array(0x3BC),
+ 0x1D728 => array(0x3BD),
+ 0x1D729 => array(0x3BE),
+ 0x1D72A => array(0x3BF),
+ 0x1D72B => array(0x3C0),
+ 0x1D72C => array(0x3C1),
+ 0x1D72D => array(0x3B8),
+ 0x1D72E => array(0x3C3),
+ 0x1D72F => array(0x3C4),
+ 0x1D730 => array(0x3C5),
+ 0x1D731 => array(0x3C6),
+ 0x1D732 => array(0x3C7),
+ 0x1D733 => array(0x3C8),
+ 0x1D734 => array(0x3C9),
+ 0x1D747 => array(0x3C3),
+ 0x1D756 => array(0x3B1),
+ 0x1D757 => array(0x3B2),
+ 0x1D758 => array(0x3B3),
+ 0x1D759 => array(0x3B4),
+ 0x1D75A => array(0x3B5),
+ 0x1D75B => array(0x3B6),
+ 0x1D75C => array(0x3B7),
+ 0x1D75D => array(0x3B8),
+ 0x1D75E => array(0x3B9),
+ 0x1D75F => array(0x3BA),
+ 0x1D760 => array(0x3BB),
+ 0x1D761 => array(0x3BC),
+ 0x1D762 => array(0x3BD),
+ 0x1D763 => array(0x3BE),
+ 0x1D764 => array(0x3BF),
+ 0x1D765 => array(0x3C0),
+ 0x1D766 => array(0x3C1),
+ 0x1D767 => array(0x3B8),
+ 0x1D768 => array(0x3C3),
+ 0x1D769 => array(0x3C4),
+ 0x1D76A => array(0x3C5),
+ 0x1D76B => array(0x3C6),
+ 0x1D76C => array(0x3C7),
+ 0x1D76D => array(0x3C8),
+ 0x1D76E => array(0x3C9),
+ 0x1D781 => array(0x3C3),
+ 0x1D790 => array(0x3B1),
+ 0x1D791 => array(0x3B2),
+ 0x1D792 => array(0x3B3),
+ 0x1D793 => array(0x3B4),
+ 0x1D794 => array(0x3B5),
+ 0x1D795 => array(0x3B6),
+ 0x1D796 => array(0x3B7),
+ 0x1D797 => array(0x3B8),
+ 0x1D798 => array(0x3B9),
+ 0x1D799 => array(0x3BA),
+ 0x1D79A => array(0x3BB),
+ 0x1D79B => array(0x3BC),
+ 0x1D79C => array(0x3BD),
+ 0x1D79D => array(0x3BE),
+ 0x1D79E => array(0x3BF),
+ 0x1D79F => array(0x3C0),
+ 0x1D7A0 => array(0x3C1),
+ 0x1D7A1 => array(0x3B8),
+ 0x1D7A2 => array(0x3C3),
+ 0x1D7A3 => array(0x3C4),
+ 0x1D7A4 => array(0x3C5),
+ 0x1D7A5 => array(0x3C6),
+ 0x1D7A6 => array(0x3C7),
+ 0x1D7A7 => array(0x3C8),
+ 0x1D7A8 => array(0x3C9),
+ 0x1D7BB => array(0x3C3),
+ 0x3F9 => array(0x3C3),
+ 0x1D2C => array(0x61),
+ 0x1D2D => array(0xE6),
+ 0x1D2E => array(0x62),
+ 0x1D30 => array(0x64),
+ 0x1D31 => array(0x65),
+ 0x1D32 => array(0x1DD),
+ 0x1D33 => array(0x67),
+ 0x1D34 => array(0x68),
+ 0x1D35 => array(0x69),
+ 0x1D36 => array(0x6A),
+ 0x1D37 => array(0x6B),
+ 0x1D38 => array(0x6C),
+ 0x1D39 => array(0x6D),
+ 0x1D3A => array(0x6E),
+ 0x1D3C => array(0x6F),
+ 0x1D3D => array(0x223),
+ 0x1D3E => array(0x70),
+ 0x1D3F => array(0x72),
+ 0x1D40 => array(0x74),
+ 0x1D41 => array(0x75),
+ 0x1D42 => array(0x77),
+ 0x213B => array(0x66, 0x61, 0x78),
+ 0x3250 => array(0x70, 0x74, 0x65),
+ 0x32CC => array(0x68, 0x67),
+ 0x32CE => array(0x65, 0x76),
+ 0x32CF => array(0x6C, 0x74, 0x64),
+ 0x337A => array(0x69, 0x75),
+ 0x33DE => array(0x76, 0x2215, 0x6D),
+ 0x33DF => array(0x61, 0x2215, 0x6D)
+ );
+
+ /**
+ * Normalization Combining Classes; Code Points not listed
+ * got Combining Class 0.
+ *
+ * @static
+ * @var array
+ * @access private
+ */
+ private static $_np_norm_combcls = array(
+ 0x334 => 1,
+ 0x335 => 1,
+ 0x336 => 1,
+ 0x337 => 1,
+ 0x338 => 1,
+ 0x93C => 7,
+ 0x9BC => 7,
+ 0xA3C => 7,
+ 0xABC => 7,
+ 0xB3C => 7,
+ 0xCBC => 7,
+ 0x1037 => 7,
+ 0x3099 => 8,
+ 0x309A => 8,
+ 0x94D => 9,
+ 0x9CD => 9,
+ 0xA4D => 9,
+ 0xACD => 9,
+ 0xB4D => 9,
+ 0xBCD => 9,
+ 0xC4D => 9,
+ 0xCCD => 9,
+ 0xD4D => 9,
+ 0xDCA => 9,
+ 0xE3A => 9,
+ 0xF84 => 9,
+ 0x1039 => 9,
+ 0x1714 => 9,
+ 0x1734 => 9,
+ 0x17D2 => 9,
+ 0x5B0 => 10,
+ 0x5B1 => 11,
+ 0x5B2 => 12,
+ 0x5B3 => 13,
+ 0x5B4 => 14,
+ 0x5B5 => 15,
+ 0x5B6 => 16,
+ 0x5B7 => 17,
+ 0x5B8 => 18,
+ 0x5B9 => 19,
+ 0x5BB => 20,
+ 0x5Bc => 21,
+ 0x5BD => 22,
+ 0x5BF => 23,
+ 0x5C1 => 24,
+ 0x5C2 => 25,
+ 0xFB1E => 26,
+ 0x64B => 27,
+ 0x64C => 28,
+ 0x64D => 29,
+ 0x64E => 30,
+ 0x64F => 31,
+ 0x650 => 32,
+ 0x651 => 33,
+ 0x652 => 34,
+ 0x670 => 35,
+ 0x711 => 36,
+ 0xC55 => 84,
+ 0xC56 => 91,
+ 0xE38 => 103,
+ 0xE39 => 103,
+ 0xE48 => 107,
+ 0xE49 => 107,
+ 0xE4A => 107,
+ 0xE4B => 107,
+ 0xEB8 => 118,
+ 0xEB9 => 118,
+ 0xEC8 => 122,
+ 0xEC9 => 122,
+ 0xECA => 122,
+ 0xECB => 122,
+ 0xF71 => 129,
+ 0xF72 => 130,
+ 0xF7A => 130,
+ 0xF7B => 130,
+ 0xF7C => 130,
+ 0xF7D => 130,
+ 0xF80 => 130,
+ 0xF74 => 132,
+ 0x321 => 202,
+ 0x322 => 202,
+ 0x327 => 202,
+ 0x328 => 202,
+ 0x31B => 216,
+ 0xF39 => 216,
+ 0x1D165 => 216,
+ 0x1D166 => 216,
+ 0x1D16E => 216,
+ 0x1D16F => 216,
+ 0x1D170 => 216,
+ 0x1D171 => 216,
+ 0x1D172 => 216,
+ 0x302A => 218,
+ 0x316 => 220,
+ 0x317 => 220,
+ 0x318 => 220,
+ 0x319 => 220,
+ 0x31C => 220,
+ 0x31D => 220,
+ 0x31E => 220,
+ 0x31F => 220,
+ 0x320 => 220,
+ 0x323 => 220,
+ 0x324 => 220,
+ 0x325 => 220,
+ 0x326 => 220,
+ 0x329 => 220,
+ 0x32A => 220,
+ 0x32B => 220,
+ 0x32C => 220,
+ 0x32D => 220,
+ 0x32E => 220,
+ 0x32F => 220,
+ 0x330 => 220,
+ 0x331 => 220,
+ 0x332 => 220,
+ 0x333 => 220,
+ 0x339 => 220,
+ 0x33A => 220,
+ 0x33B => 220,
+ 0x33C => 220,
+ 0x347 => 220,
+ 0x348 => 220,
+ 0x349 => 220,
+ 0x34D => 220,
+ 0x34E => 220,
+ 0x353 => 220,
+ 0x354 => 220,
+ 0x355 => 220,
+ 0x356 => 220,
+ 0x591 => 220,
+ 0x596 => 220,
+ 0x59B => 220,
+ 0x5A3 => 220,
+ 0x5A4 => 220,
+ 0x5A5 => 220,
+ 0x5A6 => 220,
+ 0x5A7 => 220,
+ 0x5AA => 220,
+ 0x655 => 220,
+ 0x656 => 220,
+ 0x6E3 => 220,
+ 0x6EA => 220,
+ 0x6ED => 220,
+ 0x731 => 220,
+ 0x734 => 220,
+ 0x737 => 220,
+ 0x738 => 220,
+ 0x739 => 220,
+ 0x73B => 220,
+ 0x73C => 220,
+ 0x73E => 220,
+ 0x742 => 220,
+ 0x744 => 220,
+ 0x746 => 220,
+ 0x748 => 220,
+ 0x952 => 220,
+ 0xF18 => 220,
+ 0xF19 => 220,
+ 0xF35 => 220,
+ 0xF37 => 220,
+ 0xFC6 => 220,
+ 0x193B => 220,
+ 0x20E8 => 220,
+ 0x1D17B => 220,
+ 0x1D17C => 220,
+ 0x1D17D => 220,
+ 0x1D17E => 220,
+ 0x1D17F => 220,
+ 0x1D180 => 220,
+ 0x1D181 => 220,
+ 0x1D182 => 220,
+ 0x1D18A => 220,
+ 0x1D18B => 220,
+ 0x59A => 222,
+ 0x5AD => 222,
+ 0x1929 => 222,
+ 0x302D => 222,
+ 0x302E => 224,
+ 0x302F => 224,
+ 0x1D16D => 226,
+ 0x5AE => 228,
+ 0x18A9 => 228,
+ 0x302B => 228,
+ 0x300 => 230,
+ 0x301 => 230,
+ 0x302 => 230,
+ 0x303 => 230,
+ 0x304 => 230,
+ 0x305 => 230,
+ 0x306 => 230,
+ 0x307 => 230,
+ 0x308 => 230,
+ 0x309 => 230,
+ 0x30A => 230,
+ 0x30B => 230,
+ 0x30C => 230,
+ 0x30D => 230,
+ 0x30E => 230,
+ 0x30F => 230,
+ 0x310 => 230,
+ 0x311 => 230,
+ 0x312 => 230,
+ 0x313 => 230,
+ 0x314 => 230,
+ 0x33D => 230,
+ 0x33E => 230,
+ 0x33F => 230,
+ 0x340 => 230,
+ 0x341 => 230,
+ 0x342 => 230,
+ 0x343 => 230,
+ 0x344 => 230,
+ 0x346 => 230,
+ 0x34A => 230,
+ 0x34B => 230,
+ 0x34C => 230,
+ 0x350 => 230,
+ 0x351 => 230,
+ 0x352 => 230,
+ 0x357 => 230,
+ 0x363 => 230,
+ 0x364 => 230,
+ 0x365 => 230,
+ 0x366 => 230,
+ 0x367 => 230,
+ 0x368 => 230,
+ 0x369 => 230,
+ 0x36A => 230,
+ 0x36B => 230,
+ 0x36C => 230,
+ 0x36D => 230,
+ 0x36E => 230,
+ 0x36F => 230,
+ 0x483 => 230,
+ 0x484 => 230,
+ 0x485 => 230,
+ 0x486 => 230,
+ 0x592 => 230,
+ 0x593 => 230,
+ 0x594 => 230,
+ 0x595 => 230,
+ 0x597 => 230,
+ 0x598 => 230,
+ 0x599 => 230,
+ 0x59C => 230,
+ 0x59D => 230,
+ 0x59E => 230,
+ 0x59F => 230,
+ 0x5A0 => 230,
+ 0x5A1 => 230,
+ 0x5A8 => 230,
+ 0x5A9 => 230,
+ 0x5AB => 230,
+ 0x5AC => 230,
+ 0x5AF => 230,
+ 0x5C4 => 230,
+ 0x610 => 230,
+ 0x611 => 230,
+ 0x612 => 230,
+ 0x613 => 230,
+ 0x614 => 230,
+ 0x615 => 230,
+ 0x653 => 230,
+ 0x654 => 230,
+ 0x657 => 230,
+ 0x658 => 230,
+ 0x6D6 => 230,
+ 0x6D7 => 230,
+ 0x6D8 => 230,
+ 0x6D9 => 230,
+ 0x6DA => 230,
+ 0x6DB => 230,
+ 0x6DC => 230,
+ 0x6DF => 230,
+ 0x6E0 => 230,
+ 0x6E1 => 230,
+ 0x6E2 => 230,
+ 0x6E4 => 230,
+ 0x6E7 => 230,
+ 0x6E8 => 230,
+ 0x6EB => 230,
+ 0x6EC => 230,
+ 0x730 => 230,
+ 0x732 => 230,
+ 0x733 => 230,
+ 0x735 => 230,
+ 0x736 => 230,
+ 0x73A => 230,
+ 0x73D => 230,
+ 0x73F => 230,
+ 0x740 => 230,
+ 0x741 => 230,
+ 0x743 => 230,
+ 0x745 => 230,
+ 0x747 => 230,
+ 0x749 => 230,
+ 0x74A => 230,
+ 0x951 => 230,
+ 0x953 => 230,
+ 0x954 => 230,
+ 0xF82 => 230,
+ 0xF83 => 230,
+ 0xF86 => 230,
+ 0xF87 => 230,
+ 0x170D => 230,
+ 0x193A => 230,
+ 0x20D0 => 230,
+ 0x20D1 => 230,
+ 0x20D4 => 230,
+ 0x20D5 => 230,
+ 0x20D6 => 230,
+ 0x20D7 => 230,
+ 0x20DB => 230,
+ 0x20DC => 230,
+ 0x20E1 => 230,
+ 0x20E7 => 230,
+ 0x20E9 => 230,
+ 0xFE20 => 230,
+ 0xFE21 => 230,
+ 0xFE22 => 230,
+ 0xFE23 => 230,
+ 0x1D185 => 230,
+ 0x1D186 => 230,
+ 0x1D187 => 230,
+ 0x1D189 => 230,
+ 0x1D188 => 230,
+ 0x1D1AA => 230,
+ 0x1D1AB => 230,
+ 0x1D1AC => 230,
+ 0x1D1AD => 230,
+ 0x315 => 232,
+ 0x31A => 232,
+ 0x302C => 232,
+ 0x35F => 233,
+ 0x362 => 233,
+ 0x35D => 234,
+ 0x35E => 234,
+ 0x360 => 234,
+ 0x361 => 234,
+ 0x345 => 240
+ );
+ // }}}
+
+ // {{{ properties
+ /**
+ * @var string
+ * @access private
+ */
+ private $_punycode_prefix = 'xn--';
+
+ /**
+ * @access private
+ */
+ private $_invalid_ucs = 0x80000000;
+
+ /**
+ * @access private
+ */
+ private $_max_ucs = 0x10FFFF;
+
+ /**
+ * @var int
+ * @access private
+ */
+ private $_base = 36;
+
+ /**
+ * @var int
+ * @access private
+ */
+ private $_tmin = 1;
+
+ /**
+ * @var int
+ * @access private
+ */
+ private $_tmax = 26;
+
+ /**
+ * @var int
+ * @access private
+ */
+ private $_skew = 38;
+
+ /**
+ * @var int
+ * @access private
+ */
+ private $_damp = 700;
+
+ /**
+ * @var int
+ * @access private
+ */
+ private $_initial_bias = 72;
+
+ /**
+ * @var int
+ * @access private
+ */
+ private $_initial_n = 0x80;
+
+ /**
+ * @var int
+ * @access private
+ */
+ private $_slast;
+
+ /**
+ * @access private
+ */
+ private $_sbase = 0xAC00;
+
+ /**
+ * @access private
+ */
+ private $_lbase = 0x1100;
+
+ /**
+ * @access private
+ */
+ private $_vbase = 0x1161;
+
+ /**
+ * @access private
+ */
+ private $_tbase = 0x11a7;
+
+ /**
+ * @var int
+ * @access private
+ */
+ private $_lcount = 19;
+
+ /**
+ * @var int
+ * @access private
+ */
+ private $_vcount = 21;
+
+ /**
+ * @var int
+ * @access private
+ */
+ private $_tcount = 28;
+
+ /**
+ * vcount * tcount
+ *
+ * @var int
+ * @access private
+ */
+ private $_ncount = 588;
+
+ /**
+ * lcount * tcount * vcount
+ *
+ * @var int
+ * @access private
+ */
+ private $_scount = 11172;
+
+ /**
+ * Default encoding for encode()'s input and decode()'s output is UTF-8;
+ * Other possible encodings are ucs4_string and ucs4_array
+ * See {@link setParams()} for how to select these
+ *
+ * @var bool
+ * @access private
+ */
+ private $_api_encoding = 'utf8';
+
+ /**
+ * Overlong UTF-8 encodings are forbidden
+ *
+ * @var bool
+ * @access private
+ */
+ private $_allow_overlong = false;
+
+ /**
+ * Behave strict or not
+ *
+ * @var bool
+ * @access private
+ */
+ private $_strict_mode = false;
+
+ /**
+ * IDNA-version to use
+ *
+ * Values are "2003" and "2008".
+ * Defaults to "2003", since that was the original version and for
+ * compatibility with previous versions of this library.
+ * If you need to encode "new" characters like the German "Eszett",
+ * please switch to 2008 first before encoding.
+ *
+ * @var bool
+ * @access private
+ */
+ private $_version = '2003';
+
+ /**
+ * Cached value indicating whether or not mbstring function overloading is
+ * on for strlen
+ *
+ * This is cached for optimal performance.
+ *
+ * @var boolean
+ * @see Net_IDNA2::_byteLength()
+ */
+ private static $_mb_string_overload = null;
+ // }}}
+
+
+ // {{{ constructor
+ /**
+ * Constructor
+ *
+ * @param array $options Options to initialise the object with
+ *
+ * @access public
+ * @see setParams()
+ */
+ public function __construct($options = null)
+ {
+ $this->_slast = $this->_sbase + $this->_lcount * $this->_vcount * $this->_tcount;
+
+ if (is_array($options)) {
+ $this->setParams($options);
+ }
+
+ // populate mbstring overloading cache if not set
+ if (self::$_mb_string_overload === null) {
+ self::$_mb_string_overload = (extension_loaded('mbstring')
+ && (ini_get('mbstring.func_overload') & 0x02) === 0x02);
+ }
+ }
+ // }}}
+
+
+ /**
+ * Sets a new option value. Available options and values:
+ *
+ * [utf8 - Use either UTF-8 or ISO-8859-1 as input (true for UTF-8, false
+ * otherwise); The output is always UTF-8]
+ * [overlong - Unicode does not allow unnecessarily long encodings of chars,
+ * to allow this, set this parameter to true, else to false;
+ * default is false.]
+ * [strict - true: strict mode, good for registration purposes - Causes errors
+ * on failures; false: loose mode, ideal for "wildlife" applications
+ * by silently ignoring errors and returning the original input instead]
+ *
+ * @param mixed $option Parameter to set (string: single parameter; array of Parameter => Value pairs)
+ * @param string $value Value to use (if parameter 1 is a string)
+ *
+ * @return boolean true on success, false otherwise
+ * @access public
+ */
+ public function setParams($option, $value = false)
+ {
+ if (!is_array($option)) {
+ $option = array($option => $value);
+ }
+
+ foreach ($option as $k => $v) {
+ switch ($k) {
+ case 'encoding':
+ switch ($v) {
+ case 'utf8':
+ case 'ucs4_string':
+ case 'ucs4_array':
+ $this->_api_encoding = $v;
+ break;
+
+ default:
+ throw new InvalidArgumentException('Set Parameter: Unknown parameter '.$v.' for option '.$k);
+ }
+
+ break;
+
+ case 'overlong':
+ $this->_allow_overlong = ($v) ? true : false;
+ break;
+
+ case 'strict':
+ $this->_strict_mode = ($v) ? true : false;
+ break;
+
+ case 'version':
+ if (in_array($v, array('2003', '2008'))) {
+ $this->_version = $v;
+ } else {
+ throw new InvalidArgumentException('Set Parameter: Invalid parameter '.$v.' for option '.$k);
+ }
+ break;
+
+ default:
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Encode a given UTF-8 domain name.
+ *
+ * @param string $decoded Domain name (UTF-8 or UCS-4)
+ * @param string $one_time_encoding Desired input encoding, see {@link set_parameter}
+ * If not given will use default-encoding
+ *
+ * @return string Encoded Domain name (ACE string)
+ * @return mixed processed string
+ * @throws Exception
+ * @access public
+ */
+ public function encode($decoded, $one_time_encoding = false)
+ {
+ // Forcing conversion of input to UCS4 array
+ // If one time encoding is given, use this, else the objects property
+ switch (($one_time_encoding) ? $one_time_encoding : $this->_api_encoding) {
+ case 'utf8':
+ $decoded = $this->_utf8_to_ucs4($decoded);
+ break;
+ case 'ucs4_string':
+ $decoded = $this->_ucs4_string_to_ucs4($decoded);
+ case 'ucs4_array': // No break; before this line. Catch case, but do nothing
+ break;
+ default:
+ throw new InvalidArgumentException('Unsupported input format');
+ }
+
+ // No input, no output, what else did you expect?
+ if (empty($decoded)) return '';
+
+ // Anchors for iteration
+ $last_begin = 0;
+ // Output string
+ $output = '';
+
+ foreach ($decoded as $k => $v) {
+ // Make sure to use just the plain dot
+ switch($v) {
+ case 0x3002:
+ case 0xFF0E:
+ case 0xFF61:
+ $decoded[$k] = 0x2E;
+ // It's right, no break here
+ // The codepoints above have to be converted to dots anyway
+
+ // Stumbling across an anchoring character
+ case 0x2E:
+ case 0x2F:
+ case 0x3A:
+ case 0x3F:
+ case 0x40:
+ // Neither email addresses nor URLs allowed in strict mode
+ if ($this->_strict_mode) {
+ throw new InvalidArgumentException('Neither email addresses nor URLs are allowed in strict mode.');
+ }
+ // Skip first char
+ if ($k) {
+ $encoded = '';
+ $encoded = $this->_encode(array_slice($decoded, $last_begin, (($k)-$last_begin)));
+ if ($encoded) {
+ $output .= $encoded;
+ } else {
+ $output .= $this->_ucs4_to_utf8(array_slice($decoded, $last_begin, (($k)-$last_begin)));
+ }
+ $output .= chr($decoded[$k]);
+ }
+ $last_begin = $k + 1;
+ }
+ }
+ // Catch the rest of the string
+ if ($last_begin) {
+ $inp_len = sizeof($decoded);
+ $encoded = '';
+ $encoded = $this->_encode(array_slice($decoded, $last_begin, (($inp_len)-$last_begin)));
+ if ($encoded) {
+ $output .= $encoded;
+ } else {
+ $output .= $this->_ucs4_to_utf8(array_slice($decoded, $last_begin, (($inp_len)-$last_begin)));
+ }
+ return $output;
+ }
+
+ if ($output = $this->_encode($decoded)) {
+ return $output;
+ }
+
+ return $this->_ucs4_to_utf8($decoded);
+ }
+
+ /**
+ * Decode a given ACE domain name.
+ *
+ * @param string $input Domain name (ACE string)
+ * @param string $one_time_encoding Desired output encoding, see {@link set_parameter}
+ *
+ * @return string Decoded Domain name (UTF-8 or UCS-4)
+ * @throws Exception
+ * @access public
+ */
+ public function decode($input, $one_time_encoding = false)
+ {
+ // Optionally set
+ if ($one_time_encoding) {
+ switch ($one_time_encoding) {
+ case 'utf8':
+ case 'ucs4_string':
+ case 'ucs4_array':
+ break;
+ default:
+ throw new InvalidArgumentException('Unknown encoding '.$one_time_encoding);
+ }
+ }
+ // Make sure to drop any newline characters around
+ $input = trim($input);
+
+ // Negotiate input and try to determine, wether it is a plain string,
+ // an email address or something like a complete URL
+ if (strpos($input, '@')) { // Maybe it is an email address
+ // No no in strict mode
+ if ($this->_strict_mode) {
+ throw new InvalidArgumentException('Only simple domain name parts can be handled in strict mode');
+ }
+ list($email_pref, $input) = explode('@', $input, 2);
+ $arr = explode('.', $input);
+ foreach ($arr as $k => $v) {
+ $conv = $this->_decode($v);
+ if ($conv) $arr[$k] = $conv;
+ }
+ $return = $email_pref . '@' . join('.', $arr);
+ } elseif (preg_match('![:\./]!', $input)) { // Or a complete domain name (with or without paths / parameters)
+ // No no in strict mode
+ if ($this->_strict_mode) {
+ throw new InvalidArgumentException('Only simple domain name parts can be handled in strict mode');
+ }
+
+ $parsed = parse_url($input);
+ if (isset($parsed['host'])) {
+ $arr = explode('.', $parsed['host']);
+ foreach ($arr as $k => $v) {
+ $conv = $this->_decode($v);
+ if ($conv) $arr[$k] = $conv;
+ }
+ $parsed['host'] = join('.', $arr);
+ if (isset($parsed['scheme'])) {
+ $parsed['scheme'] .= (strtolower($parsed['scheme']) == 'mailto') ? ':' : '://';
+ }
+ $return = $this->_unparse_url($parsed);
+ } else { // parse_url seems to have failed, try without it
+ $arr = explode('.', $input);
+ foreach ($arr as $k => $v) {
+ $conv = $this->_decode($v);
+ if ($conv) $arr[$k] = $conv;
+ }
+ $return = join('.', $arr);
+ }
+ } else { // Otherwise we consider it being a pure domain name string
+ $return = $this->_decode($input);
+ }
+ // The output is UTF-8 by default, other output formats need conversion here
+ // If one time encoding is given, use this, else the objects property
+ switch (($one_time_encoding) ? $one_time_encoding : $this->_api_encoding) {
+ case 'utf8':
+ return $return;
+ break;
+ case 'ucs4_string':
+ return $this->_ucs4_to_ucs4_string($this->_utf8_to_ucs4($return));
+ break;
+ case 'ucs4_array':
+ return $this->_utf8_to_ucs4($return);
+ break;
+ default:
+ throw new InvalidArgumentException('Unsupported output format');
+ }
+ }
+
+
+ // {{{ private
+ /**
+ * Opposite function to parse_url()
+ *
+ * Inspired by code from comments of php.net-documentation for parse_url()
+ *
+ * @param array $parts_arr parts (strings) as returned by parse_url()
+ *
+ * @return string
+ * @access private
+ */
+ private function _unparse_url($parts_arr)
+ {
+ if (!empty($parts_arr['scheme'])) {
+ $ret_url = $parts_arr['scheme'];
+ }
+ if (!empty($parts_arr['user'])) {
+ $ret_url .= $parts_arr['user'];
+ if (!empty($parts_arr['pass'])) {
+ $ret_url .= ':' . $parts_arr['pass'];
+ }
+ $ret_url .= '@';
+ }
+ $ret_url .= $parts_arr['host'];
+ if (!empty($parts_arr['port'])) {
+ $ret_url .= ':' . $parts_arr['port'];
+ }
+ $ret_url .= $parts_arr['path'];
+ if (!empty($parts_arr['query'])) {
+ $ret_url .= '?' . $parts_arr['query'];
+ }
+ if (!empty($parts_arr['fragment'])) {
+ $ret_url .= '#' . $parts_arr['fragment'];
+ }
+ return $ret_url;
+ }
+
+ /**
+ * The actual encoding algorithm.
+ *
+ * @param string $decoded Decoded string which should be encoded
+ *
+ * @return string Encoded string
+ * @throws Exception
+ * @access private
+ */
+ private function _encode($decoded)
+ {
+ // We cannot encode a domain name containing the Punycode prefix
+ $extract = self::_byteLength($this->_punycode_prefix);
+ $check_pref = $this->_utf8_to_ucs4($this->_punycode_prefix);
+ $check_deco = array_slice($decoded, 0, $extract);
+
+ if ($check_pref == $check_deco) {
+ throw new InvalidArgumentException('This is already a punycode string');
+ }
+
+ // We will not try to encode strings consisting of basic code points only
+ $encodable = false;
+ foreach ($decoded as $k => $v) {
+ if ($v > 0x7a) {
+ $encodable = true;
+ break;
+ }
+ }
+ if (!$encodable) {
+ if ($this->_strict_mode) {
+ throw new InvalidArgumentException('The given string does not contain encodable chars');
+ }
+
+ return false;
+ }
+
+ // Do NAMEPREP
+ $decoded = $this->_nameprep($decoded);
+
+ $deco_len = count($decoded);
+
+ // Empty array
+ if (!$deco_len) {
+ return false;
+ }
+
+ // How many chars have been consumed
+ $codecount = 0;
+
+ // Start with the prefix; copy it to output
+ $encoded = $this->_punycode_prefix;
+
+ $encoded = '';
+ // Copy all basic code points to output
+ for ($i = 0; $i < $deco_len; ++$i) {
+ $test = $decoded[$i];
+ // Will match [0-9a-zA-Z-]
+ if ((0x2F < $test && $test < 0x40)
+ || (0x40 < $test && $test < 0x5B)
+ || (0x60 < $test && $test <= 0x7B)
+ || (0x2D == $test)
+ ) {
+ $encoded .= chr($decoded[$i]);
+ $codecount++;
+ }
+ }
+
+ // All codepoints were basic ones
+ if ($codecount == $deco_len) {
+ return $encoded;
+ }
+
+ // Start with the prefix; copy it to output
+ $encoded = $this->_punycode_prefix . $encoded;
+
+ // If we have basic code points in output, add an hyphen to the end
+ if ($codecount) {
+ $encoded .= '-';
+ }
+
+ // Now find and encode all non-basic code points
+ $is_first = true;
+ $cur_code = $this->_initial_n;
+ $bias = $this->_initial_bias;
+ $delta = 0;
+
+ while ($codecount < $deco_len) {
+ // Find the smallest code point >= the current code point and
+ // remember the last ouccrence of it in the input
+ for ($i = 0, $next_code = $this->_max_ucs; $i < $deco_len; $i++) {
+ if ($decoded[$i] >= $cur_code && $decoded[$i] <= $next_code) {
+ $next_code = $decoded[$i];
+ }
+ }
+
+ $delta += ($next_code - $cur_code) * ($codecount + 1);
+ $cur_code = $next_code;
+
+ // Scan input again and encode all characters whose code point is $cur_code
+ for ($i = 0; $i < $deco_len; $i++) {
+ if ($decoded[$i] < $cur_code) {
+ $delta++;
+ } else if ($decoded[$i] == $cur_code) {
+ for ($q = $delta, $k = $this->_base; 1; $k += $this->_base) {
+ $t = ($k <= $bias)?
+ $this->_tmin :
+ (($k >= $bias + $this->_tmax)? $this->_tmax : $k - $bias);
+
+ if ($q < $t) {
+ break;
+ }
+
+ $encoded .= $this->_encodeDigit(ceil($t + (($q - $t) % ($this->_base - $t))));
+ $q = ($q - $t) / ($this->_base - $t);
+ }
+
+ $encoded .= $this->_encodeDigit($q);
+ $bias = $this->_adapt($delta, $codecount + 1, $is_first);
+ $codecount++;
+ $delta = 0;
+ $is_first = false;
+ }
+ }
+
+ $delta++;
+ $cur_code++;
+ }
+
+ return $encoded;
+ }
+
+ /**
+ * The actual decoding algorithm.
+ *
+ * @param string $encoded Encoded string which should be decoded
+ *
+ * @return string Decoded string
+ * @throws Exception
+ * @access private
+ */
+ private function _decode($encoded)
+ {
+ // We do need to find the Punycode prefix
+ if (!preg_match('!^' . preg_quote($this->_punycode_prefix, '!') . '!', $encoded)) {
+ return false;
+ }
+
+ $encode_test = preg_replace('!^' . preg_quote($this->_punycode_prefix, '!') . '!', '', $encoded);
+
+ // If nothing left after removing the prefix, it is hopeless
+ if (!$encode_test) {
+ return false;
+ }
+
+ // Find last occurence of the delimiter
+ $delim_pos = strrpos($encoded, '-');
+
+ if ($delim_pos > self::_byteLength($this->_punycode_prefix)) {
+ for ($k = self::_byteLength($this->_punycode_prefix); $k < $delim_pos; ++$k) {
+ $decoded[] = ord($encoded{$k});
+ }
+ } else {
+ $decoded = array();
+ }
+
+ $deco_len = count($decoded);
+ $enco_len = self::_byteLength($encoded);
+
+ // Wandering through the strings; init
+ $is_first = true;
+ $bias = $this->_initial_bias;
+ $idx = 0;
+ $char = $this->_initial_n;
+
+ for ($enco_idx = ($delim_pos)? ($delim_pos + 1) : 0; $enco_idx < $enco_len; ++$deco_len) {
+ for ($old_idx = $idx, $w = 1, $k = $this->_base; 1 ; $k += $this->_base) {
+ $digit = $this->_decodeDigit($encoded{$enco_idx++});
+ $idx += $digit * $w;
+
+ $t = ($k <= $bias) ?
+ $this->_tmin :
+ (($k >= $bias + $this->_tmax)? $this->_tmax : ($k - $bias));
+
+ if ($digit < $t) {
+ break;
+ }
+
+ $w = (int)($w * ($this->_base - $t));
+ }
+
+ $bias = $this->_adapt($idx - $old_idx, $deco_len + 1, $is_first);
+ $is_first = false;
+ $char += (int) ($idx / ($deco_len + 1));
+ $idx %= ($deco_len + 1);
+
+ if ($deco_len > 0) {
+ // Make room for the decoded char
+ for ($i = $deco_len; $i > $idx; $i--) {
+ $decoded[$i] = $decoded[($i - 1)];
+ }
+ }
+
+ $decoded[$idx++] = $char;
+ }
+
+ return $this->_ucs4_to_utf8($decoded);
+ }
+
+ /**
+ * Adapt the bias according to the current code point and position.
+ *
+ * @param int $delta ...
+ * @param int $npoints ...
+ * @param boolean $is_first ...
+ *
+ * @return int
+ * @access private
+ */
+ private function _adapt($delta, $npoints, $is_first)
+ {
+ $delta = (int) ($is_first ? ($delta / $this->_damp) : ($delta / 2));
+ $delta += (int) ($delta / $npoints);
+
+ for ($k = 0; $delta > (($this->_base - $this->_tmin) * $this->_tmax) / 2; $k += $this->_base) {
+ $delta = (int) ($delta / ($this->_base - $this->_tmin));
+ }
+
+ return (int) ($k + ($this->_base - $this->_tmin + 1) * $delta / ($delta + $this->_skew));
+ }
+
+ /**
+ * Encoding a certain digit.
+ *
+ * @param int $d One digit to encode
+ *
+ * @return char Encoded digit
+ * @access private
+ */
+ private function _encodeDigit($d)
+ {
+ return chr($d + 22 + 75 * ($d < 26));
+ }
+
+ /**
+ * Decode a certain digit.
+ *
+ * @param char $cp One digit (character) to decode
+ *
+ * @return int Decoded digit
+ * @access private
+ */
+ private function _decodeDigit($cp)
+ {
+ $cp = ord($cp);
+ return ($cp - 48 < 10)? $cp - 22 : (($cp - 65 < 26)? $cp - 65 : (($cp - 97 < 26)? $cp - 97 : $this->_base));
+ }
+
+ /**
+ * Do Nameprep according to RFC3491 and RFC3454.
+ *
+ * @param array $input Unicode Characters
+ *
+ * @return string Unicode Characters, Nameprep'd
+ * @throws Exception
+ * @access private
+ */
+ private function _nameprep($input)
+ {
+ $output = array();
+
+ // Walking through the input array, performing the required steps on each of
+ // the input chars and putting the result into the output array
+ // While mapping required chars we apply the cannonical ordering
+
+ foreach ($input as $v) {
+ // Map to nothing == skip that code point
+ if (in_array($v, self::$_np_map_nothing)) {
+ continue;
+ }
+
+ // Try to find prohibited input
+ if (in_array($v, self::$_np_prohibit) || in_array($v, self::$_general_prohibited)) {
+ throw new Net_IDNA2_Exception_Nameprep('Prohibited input U+' . sprintf('%08X', $v));
+ }
+
+ foreach (self::$_np_prohibit_ranges as $range) {
+ if ($range[0] <= $v && $v <= $range[1]) {
+ throw new Net_IDNA2_Exception_Nameprep('Prohibited input U+' . sprintf('%08X', $v));
+ }
+ }
+
+ // Hangul syllable decomposition
+ if (0xAC00 <= $v && $v <= 0xD7AF) {
+ foreach ($this->_hangulDecompose($v) as $out) {
+ $output[] = $out;
+ }
+ } else if (($this->_version == '2003') && isset(self::$_np_replacemaps[$v])) {
+ // There's a decomposition mapping for that code point
+ // Decompositions only in version 2003 (original) of IDNA
+ foreach ($this->_applyCannonicalOrdering(self::$_np_replacemaps[$v]) as $out) {
+ $output[] = $out;
+ }
+ } else {
+ $output[] = $v;
+ }
+ }
+
+ // Combine code points
+
+ $last_class = 0;
+ $last_starter = 0;
+ $out_len = count($output);
+
+ for ($i = 0; $i < $out_len; ++$i) {
+ $class = $this->_getCombiningClass($output[$i]);
+
+ if ((!$last_class || $last_class != $class) && $class) {
+ // Try to match
+ $seq_len = $i - $last_starter;
+ $out = $this->_combine(array_slice($output, $last_starter, $seq_len));
+
+ // On match: Replace the last starter with the composed character and remove
+ // the now redundant non-starter(s)
+ if ($out) {
+ $output[$last_starter] = $out;
+
+ if (count($out) != $seq_len) {
+ for ($j = $i + 1; $j < $out_len; ++$j) {
+ $output[$j - 1] = $output[$j];
+ }
+
+ unset($output[$out_len]);
+ }
+
+ // Rewind the for loop by one, since there can be more possible compositions
+ $i--;
+ $out_len--;
+ $last_class = ($i == $last_starter)? 0 : $this->_getCombiningClass($output[$i - 1]);
+
+ continue;
+ }
+ }
+
+ // The current class is 0
+ if (!$class) {
+ $last_starter = $i;
+ }
+
+ $last_class = $class;
+ }
+
+ return $output;
+ }
+
+ /**
+ * Decomposes a Hangul syllable
+ * (see http://www.unicode.org/unicode/reports/tr15/#Hangul).
+ *
+ * @param integer $char 32bit UCS4 code point
+ *
+ * @return array Either Hangul Syllable decomposed or original 32bit
+ * value as one value array
+ * @access private
+ */
+ private function _hangulDecompose($char)
+ {
+ $sindex = $char - $this->_sbase;
+
+ if ($sindex < 0 || $sindex >= $this->_scount) {
+ return array($char);
+ }
+
+ $result = array();
+ $T = $this->_tbase + $sindex % $this->_tcount;
+ $result[] = (int)($this->_lbase + $sindex / $this->_ncount);
+ $result[] = (int)($this->_vbase + ($sindex % $this->_ncount) / $this->_tcount);
+
+ if ($T != $this->_tbase) {
+ $result[] = $T;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Ccomposes a Hangul syllable
+ * (see http://www.unicode.org/unicode/reports/tr15/#Hangul).
+ *
+ * @param array $input Decomposed UCS4 sequence
+ *
+ * @return array UCS4 sequence with syllables composed
+ * @access private
+ */
+ private function _hangulCompose($input)
+ {
+ $inp_len = count($input);
+
+ if (!$inp_len) {
+ return array();
+ }
+
+ $result = array();
+ $last = $input[0];
+ $result[] = $last; // copy first char from input to output
+
+ for ($i = 1; $i < $inp_len; ++$i) {
+ $char = $input[$i];
+
+ // Find out, wether two current characters from L and V
+ $lindex = $last - $this->_lbase;
+
+ if (0 <= $lindex && $lindex < $this->_lcount) {
+ $vindex = $char - $this->_vbase;
+
+ if (0 <= $vindex && $vindex < $this->_vcount) {
+ // create syllable of form LV
+ $last = ($this->_sbase + ($lindex * $this->_vcount + $vindex) * $this->_tcount);
+ $out_off = count($result) - 1;
+ $result[$out_off] = $last; // reset last
+
+ // discard char
+ continue;
+ }
+ }
+
+ // Find out, wether two current characters are LV and T
+ $sindex = $last - $this->_sbase;
+
+ if (0 <= $sindex && $sindex < $this->_scount && ($sindex % $this->_tcount) == 0) {
+ $tindex = $char - $this->_tbase;
+
+ if (0 <= $tindex && $tindex <= $this->_tcount) {
+ // create syllable of form LVT
+ $last += $tindex;
+ $out_off = count($result) - 1;
+ $result[$out_off] = $last; // reset last
+
+ // discard char
+ continue;
+ }
+ }
+
+ // if neither case was true, just add the character
+ $last = $char;
+ $result[] = $char;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns the combining class of a certain wide char.
+ *
+ * @param integer $char Wide char to check (32bit integer)
+ *
+ * @return integer Combining class if found, else 0
+ * @access private
+ */
+ private function _getCombiningClass($char)
+ {
+ return isset(self::$_np_norm_combcls[$char])? self::$_np_norm_combcls[$char] : 0;
+ }
+
+ /**
+ * Apllies the cannonical ordering of a decomposed UCS4 sequence.
+ *
+ * @param array $input Decomposed UCS4 sequence
+ *
+ * @return array Ordered USC4 sequence
+ * @access private
+ */
+ private function _applyCannonicalOrdering($input)
+ {
+ $swap = true;
+ $size = count($input);
+
+ while ($swap) {
+ $swap = false;
+ $last = $this->_getCombiningClass($input[0]);
+
+ for ($i = 0; $i < $size - 1; ++$i) {
+ $next = $this->_getCombiningClass($input[$i + 1]);
+
+ if ($next != 0 && $last > $next) {
+ // Move item leftward until it fits
+ for ($j = $i + 1; $j > 0; --$j) {
+ if ($this->_getCombiningClass($input[$j - 1]) <= $next) {
+ break;
+ }
+
+ $t = $input[$j];
+ $input[$j] = $input[$j - 1];
+ $input[$j - 1] = $t;
+ $swap = 1;
+ }
+
+ // Reentering the loop looking at the old character again
+ $next = $last;
+ }
+
+ $last = $next;
+ }
+ }
+
+ return $input;
+ }
+
+ /**
+ * Do composition of a sequence of starter and non-starter.
+ *
+ * @param array $input UCS4 Decomposed sequence
+ *
+ * @return array Ordered USC4 sequence
+ * @access private
+ */
+ private function _combine($input)
+ {
+ $inp_len = count($input);
+
+ // Is it a Hangul syllable?
+ if (1 != $inp_len) {
+ $hangul = $this->_hangulCompose($input);
+
+ // This place is probably wrong
+ if (count($hangul) != $inp_len) {
+ return $hangul;
+ }
+ }
+
+ foreach (self::$_np_replacemaps as $np_src => $np_target) {
+ if ($np_target[0] != $input[0]) {
+ continue;
+ }
+
+ if (count($np_target) != $inp_len) {
+ continue;
+ }
+
+ $hit = false;
+
+ foreach ($input as $k2 => $v2) {
+ if ($v2 == $np_target[$k2]) {
+ $hit = true;
+ } else {
+ $hit = false;
+ break;
+ }
+ }
+
+ if ($hit) {
+ return $np_src;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * This converts an UTF-8 encoded string to its UCS-4 (array) representation
+ * By talking about UCS-4 we mean arrays of 32bit integers representing
+ * each of the "chars". This is due to PHP not being able to handle strings with
+ * bit depth different from 8. This applies to the reverse method _ucs4_to_utf8(), too.
+ * The following UTF-8 encodings are supported:
+ *
+ * bytes bits representation
+ * 1 7 0xxxxxxx
+ * 2 11 110xxxxx 10xxxxxx
+ * 3 16 1110xxxx 10xxxxxx 10xxxxxx
+ * 4 21 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * 5 26 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * 6 31 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ *
+ * Each x represents a bit that can be used to store character data.
+ *
+ * @param string $input utf8-encoded string
+ *
+ * @return array ucs4-encoded array
+ * @throws Exception
+ * @access private
+ */
+ private function _utf8_to_ucs4($input)
+ {
+ $output = array();
+ $out_len = 0;
+ $inp_len = self::_byteLength($input, '8bit');
+ $mode = 'next';
+ $test = 'none';
+ for ($k = 0; $k < $inp_len; ++$k) {
+ $v = ord($input{$k}); // Extract byte from input string
+
+ if ($v < 128) { // We found an ASCII char - put into stirng as is
+ $output[$out_len] = $v;
+ ++$out_len;
+ if ('add' == $mode) {
+ throw new UnexpectedValueException('Conversion from UTF-8 to UCS-4 failed: malformed input at byte '.$k);
+ }
+ continue;
+ }
+ if ('next' == $mode) { // Try to find the next start byte; determine the width of the Unicode char
+ $start_byte = $v;
+ $mode = 'add';
+ $test = 'range';
+ if ($v >> 5 == 6) { // &110xxxxx 10xxxxx
+ $next_byte = 0; // Tells, how many times subsequent bitmasks must rotate 6bits to the left
+ $v = ($v - 192) << 6;
+ } elseif ($v >> 4 == 14) { // &1110xxxx 10xxxxxx 10xxxxxx
+ $next_byte = 1;
+ $v = ($v - 224) << 12;
+ } elseif ($v >> 3 == 30) { // &11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ $next_byte = 2;
+ $v = ($v - 240) << 18;
+ } elseif ($v >> 2 == 62) { // &111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ $next_byte = 3;
+ $v = ($v - 248) << 24;
+ } elseif ($v >> 1 == 126) { // &1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ $next_byte = 4;
+ $v = ($v - 252) << 30;
+ } else {
+ throw new UnexpectedValueException('This might be UTF-8, but I don\'t understand it at byte '.$k);
+ }
+ if ('add' == $mode) {
+ $output[$out_len] = (int) $v;
+ ++$out_len;
+ continue;
+ }
+ }
+ if ('add' == $mode) {
+ if (!$this->_allow_overlong && $test == 'range') {
+ $test = 'none';
+ if (($v < 0xA0 && $start_byte == 0xE0) || ($v < 0x90 && $start_byte == 0xF0) || ($v > 0x8F && $start_byte == 0xF4)) {
+ throw new OutOfRangeException('Bogus UTF-8 character detected (out of legal range) at byte '.$k);
+ }
+ }
+ if ($v >> 6 == 2) { // Bit mask must be 10xxxxxx
+ $v = ($v - 128) << ($next_byte * 6);
+ $output[($out_len - 1)] += $v;
+ --$next_byte;
+ } else {
+ throw new UnexpectedValueException('Conversion from UTF-8 to UCS-4 failed: malformed input at byte '.$k);
+ }
+ if ($next_byte < 0) {
+ $mode = 'next';
+ }
+ }
+ } // for
+ return $output;
+ }
+
+ /**
+ * Convert UCS-4 array into UTF-8 string
+ *
+ * @param array $input ucs4-encoded array
+ *
+ * @return string utf8-encoded string
+ * @throws Exception
+ * @access private
+ */
+ private function _ucs4_to_utf8($input)
+ {
+ $output = '';
+
+ foreach ($input as $v) {
+ // $v = ord($v);
+
+ if ($v < 128) {
+ // 7bit are transferred literally
+ $output .= chr($v);
+ } else if ($v < 1 << 11) {
+ // 2 bytes
+ $output .= chr(192 + ($v >> 6))
+ . chr(128 + ($v & 63));
+ } else if ($v < 1 << 16) {
+ // 3 bytes
+ $output .= chr(224 + ($v >> 12))
+ . chr(128 + (($v >> 6) & 63))
+ . chr(128 + ($v & 63));
+ } else if ($v < 1 << 21) {
+ // 4 bytes
+ $output .= chr(240 + ($v >> 18))
+ . chr(128 + (($v >> 12) & 63))
+ . chr(128 + (($v >> 6) & 63))
+ . chr(128 + ($v & 63));
+ } else if ($v < 1 << 26) {
+ // 5 bytes
+ $output .= chr(248 + ($v >> 24))
+ . chr(128 + (($v >> 18) & 63))
+ . chr(128 + (($v >> 12) & 63))
+ . chr(128 + (($v >> 6) & 63))
+ . chr(128 + ($v & 63));
+ } else if ($v < 1 << 31) {
+ // 6 bytes
+ $output .= chr(252 + ($v >> 30))
+ . chr(128 + (($v >> 24) & 63))
+ . chr(128 + (($v >> 18) & 63))
+ . chr(128 + (($v >> 12) & 63))
+ . chr(128 + (($v >> 6) & 63))
+ . chr(128 + ($v & 63));
+ } else {
+ throw new UnexpectedValueException('Conversion from UCS-4 to UTF-8 failed: malformed input');
+ }
+ }
+
+ return $output;
+ }
+
+ /**
+ * Convert UCS-4 array into UCS-4 string
+ *
+ * @param array $input ucs4-encoded array
+ *
+ * @return string ucs4-encoded string
+ * @throws Exception
+ * @access private
+ */
+ private function _ucs4_to_ucs4_string($input)
+ {
+ $output = '';
+ // Take array values and split output to 4 bytes per value
+ // The bit mask is 255, which reads &11111111
+ foreach ($input as $v) {
+ $output .= ($v & (255 << 24) >> 24) . ($v & (255 << 16) >> 16) . ($v & (255 << 8) >> 8) . ($v & 255);
+ }
+ return $output;
+ }
+
+ /**
+ * Convert UCS-4 string into UCS-4 array
+ *
+ * @param string $input ucs4-encoded string
+ *
+ * @return array ucs4-encoded array
+ * @throws InvalidArgumentException
+ * @access private
+ */
+ private function _ucs4_string_to_ucs4($input)
+ {
+ $output = array();
+
+ $inp_len = self::_byteLength($input);
+ // Input length must be dividable by 4
+ if ($inp_len % 4) {
+ throw new InvalidArgumentException('Input UCS4 string is broken');
+ }
+
+ // Empty input - return empty output
+ if (!$inp_len) {
+ return $output;
+ }
+
+ for ($i = 0, $out_len = -1; $i < $inp_len; ++$i) {
+ // Increment output position every 4 input bytes
+ if (!$i % 4) {
+ $out_len++;
+ $output[$out_len] = 0;
+ }
+ $output[$out_len] += ord($input{$i}) << (8 * (3 - ($i % 4) ) );
+ }
+ return $output;
+ }
+
+ /**
+ * Echo hex representation of UCS4 sequence.
+ *
+ * @param array $input UCS4 sequence
+ * @param boolean $include_bit Include bitmask in output
+ *
+ * @return void
+ * @static
+ * @access private
+ */
+ private static function _showHex($input, $include_bit = false)
+ {
+ foreach ($input as $k => $v) {
+ echo '[', $k, '] => ', sprintf('%X', $v);
+
+ if ($include_bit) {
+ echo ' (', Net_IDNA2::_showBitmask($v), ')';
+ }
+
+ echo "\n";
+ }
+ }
+
+ /**
+ * Gives you a bit representation of given Byte (8 bits), Word (16 bits) or DWord (32 bits)
+ * Output width is automagically determined
+ *
+ * @param int $octet ...
+ *
+ * @return string Bitmask-representation
+ * @static
+ * @access private
+ */
+ private static function _showBitmask($octet)
+ {
+ if ($octet >= (1 << 16)) {
+ $w = 31;
+ } else if ($octet >= (1 << 8)) {
+ $w = 15;
+ } else {
+ $w = 7;
+ }
+
+ $return = '';
+
+ for ($i = $w; $i > -1; $i--) {
+ $return .= ($octet & (1 << $i))? '1' : '0';
+ }
+
+ return $return;
+ }
+
+ /**
+ * Gets the length of a string in bytes even if mbstring function
+ * overloading is turned on
+ *
+ * @param string $string the string for which to get the length.
+ *
+ * @return integer the length of the string in bytes.
+ *
+ * @see Net_IDNA2::$_mb_string_overload
+ */
+ private static function _byteLength($string)
+ {
+ if (self::$_mb_string_overload) {
+ return mb_strlen($string, '8bit');
+ }
+ return strlen((binary)$string);
+ }
+
+ // }}}}
+
+ // {{{ factory
+ /**
+ * Attempts to return a concrete IDNA instance for either php4 or php5.
+ *
+ * @param array $params Set of paramaters
+ *
+ * @return Net_IDNA2
+ * @access public
+ */
+ function getInstance($params = array())
+ {
+ return new Net_IDNA2($params);
+ }
+ // }}}
+
+ // {{{ singleton
+ /**
+ * Attempts to return a concrete IDNA instance for either php4 or php5,
+ * only creating a new instance if no IDNA instance with the same
+ * parameters currently exists.
+ *
+ * @param array $params Set of paramaters
+ *
+ * @return object Net_IDNA2
+ * @access public
+ */
+ function singleton($params = array())
+ {
+ static $instances;
+ if (!isset($instances)) {
+ $instances = array();
+ }
+
+ $signature = serialize($params);
+ if (!isset($instances[$signature])) {
+ $instances[$signature] = Net_IDNA2::getInstance($params);
+ }
+
+ return $instances[$signature];
+ }
+ // }}}
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Vendors/Net/IDNA2CustomExceptions.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Vendors/Net/IDNA2CustomExceptions.php
new file mode 100644
index 0000000..69b0f69
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/MailSo/Vendors/Net/IDNA2CustomExceptions.php
@@ -0,0 +1,18 @@
+getSignature();
+ }
+
+ return $sSignature;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/LICENSE.txt b/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/LICENSE.txt
new file mode 100644
index 0000000..90e632a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/LICENSE.txt
@@ -0,0 +1,48 @@
+MIT License
+
+Copyright (c) <2011-2015> Serban Ghita, Nick Ilyin and contributors.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Developer’s Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+(c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+(d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/Mobile_Detect.json b/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/Mobile_Detect.json
new file mode 100644
index 0000000..b5bbffd
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/Mobile_Detect.json
@@ -0,0 +1 @@
+{"version":"2.8.22","headerMatch":{"HTTP_ACCEPT":{"matches":["application\/x-obml2d","application\/vnd.rim.html","text\/vnd.wap.wml","application\/vnd.wap.xhtml+xml"]},"HTTP_X_WAP_PROFILE":null,"HTTP_X_WAP_CLIENTID":null,"HTTP_WAP_CONNECTION":null,"HTTP_PROFILE":null,"HTTP_X_OPERAMINI_PHONE_UA":null,"HTTP_X_NOKIA_GATEWAY_ID":null,"HTTP_X_ORANGE_ID":null,"HTTP_X_VODAFONE_3GPDPCONTEXT":null,"HTTP_X_HUAWEI_USERID":null,"HTTP_UA_OS":null,"HTTP_X_MOBILE_GATEWAY":null,"HTTP_X_ATT_DEVICEID":null,"HTTP_UA_CPU":{"matches":["ARM"]}},"uaHttpHeaders":["HTTP_USER_AGENT","HTTP_X_OPERAMINI_PHONE_UA","HTTP_X_DEVICE_USER_AGENT","HTTP_X_ORIGINAL_USER_AGENT","HTTP_X_SKYFIRE_PHONE","HTTP_X_BOLT_PHONE_UA","HTTP_DEVICE_STOCK_UA","HTTP_X_UCBROWSER_DEVICE_UA"],"uaMatch":{"phones":{"iPhone":"\\biPhone\\b|\\biPod\\b","BlackBerry":"BlackBerry|\\bBB10\\b|rim[0-9]+","HTC":"HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m","Nexus":"Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6","Dell":"Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b","Motorola":"Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b","Samsung":"Samsung|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F","LG":"\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)","Sony":"SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533","Asus":"Asus.*Galaxy|PadFone.*Mobile","NokiaLumia":"Lumia [0-9]{3,4}","Micromax":"Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b","Palm":"PalmSource|Palm","Vertu":"Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature","Pantech":"PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790","Fly":"IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250","Wiko":"KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM","iMobile":"i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)","SimValley":"\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b","Wolfgang":"AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q","Alcatel":"Alcatel","Nintendo":"Nintendo 3DS","Amoi":"Amoi","INQ":"INQ","GenericPhone":"Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser"},"tablets":{"iPad":"iPad|iPad.*Mobile","NexusTablet":"Android.*Nexus[\\s]+(7|9|10)","SamsungTablet":"SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561","Kindle":"Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI)\\b","SurfaceTablet":"Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)","HPTablet":"HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10","AsusTablet":"^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K017 |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA","BlackBerryTablet":"PlayBook|RIM Tablet","HTCtablet":"HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410","MotorolaTablet":"xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617","NookTablet":"Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2","AcerTablet":"Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20","ToshibaTablet":"Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO","LGTablet":"\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b","FujitsuTablet":"Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b","PrestigioTablet":"PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002","LenovoTablet":"Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)","DellTablet":"Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7","YarvikTablet":"Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b","MedionTablet":"Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB","ArnovaTablet":"AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2","IntensoTablet":"INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004","IRUTablet":"M702pro","MegafonTablet":"MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b","EbodaTablet":"E-Boda (Supreme|Impresspeed|Izzycomm|Essential)","AllViewTablet":"Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)","ArchosTablet":"\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b","AinolTablet":"NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark","NokiaLumiaTablet":"Lumia 2520","SonyTablet":"Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31","PhilipsTablet":"\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b","CubeTablet":"Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT","CobyTablet":"MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010","MIDTablet":"M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10","MSITablet":"MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b","SMiTTablet":"Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)","RockChipTablet":"Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A","FlyTablet":"IQ310|Fly Vision","bqTablet":"Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus","HuaweiTablet":"MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim","NecTablet":"\\bN-06D|\\bN-08D","PantechTablet":"Pantech.*P4100","BronchoTablet":"Broncho.*(N701|N708|N802|a710)","VersusTablet":"TOUCHPAD.*[78910]|\\bTOUCHTAB\\b","ZyncTablet":"z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900","PositivoTablet":"TB07STA|TB10STA|TB07FTA|TB10FTA","NabiTablet":"Android.*\\bNabi","KoboTablet":"Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build","DanewTablet":"DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b","TexetTablet":"NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE","PlaystationTablet":"Playstation.*(Portable|Vita)","TrekstorTablet":"ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab","PyleAudioTablet":"\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b","AdvanTablet":"Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ","DanyTechTablet":"Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1","GalapadTablet":"Android.*\\bG1\\b","MicromaxTablet":"Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b","KarbonnTablet":"Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b","AllFineTablet":"Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide","PROSCANTablet":"\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b","YONESTablet":"BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026","ChangJiaTablet":"TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503","GUTablet":"TX-A1301|TX-M9002|Q702|kf026","PointOfViewTablet":"TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10","OvermaxTablet":"OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)","HCLTablet":"HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync","DPSTablet":"DPS Dream 9|DPS Dual 7","VistureTablet":"V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10","CrestaTablet":"CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989","MediatekTablet":"\\bMT8125|MT8389|MT8135|MT8377\\b","ConcordeTablet":"Concorde([ ]+)?Tab|ConCorde ReadMan","GoCleverTablet":"GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042","ModecomTablet":"FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003","VoninoTablet":"\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b","ECSTablet":"V07OT2|TM105A|S10OT1|TR10CS1","StorexTablet":"eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab","VodafoneTablet":"SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7","EssentielBTablet":"Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2","RossMoorTablet":"RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711","iMobileTablet":"i-mobile i-note","TolinoTablet":"tolino tab [0-9.]+|tolino shine","AudioSonicTablet":"\\bC-22Q|T7-QC|T-17B|T-17P\\b","AMPETablet":"Android.* A78 ","SkkTablet":"Android.* (SKYPAD|PHOENIX|CYCLOPS)","TecnoTablet":"TECNO P9","JXDTablet":"Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b","iJoyTablet":"Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)","FX2Tablet":"FX2 PAD7|FX2 PAD10","XoroTablet":"KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151","ViewsonicTablet":"ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a","OdysTablet":"LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10","CaptivaTablet":"CAPTIVA PAD","IconbitTablet":"NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S","TeclastTablet":"T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi","OndaTablet":"\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+","JaytechTablet":"TPC-PA762","BlaupunktTablet":"Endeavour 800NG|Endeavour 1010","DigmaTablet":"\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b","EvolioTablet":"ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b","LavaTablet":"QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b","AocTablet":"MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712","MpmanTablet":"MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010","CelkonTablet":"CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b","WolderTablet":"miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b","MiTablet":"\\bMI PAD\\b|\\bHM NOTE 1W\\b","NibiruTablet":"Nibiru M1|Nibiru Jupiter One","NexoTablet":"NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI","LeaderTablet":"TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100","UbislateTablet":"UbiSlate[\\s]?7C","PocketBookTablet":"Pocketbook","KocasoTablet":"\\b(TB-1207)\\b","Hudl":"Hudl HT7S3|Hudl 2","TelstraTablet":"T-Hub2","GenericTablet":"Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bJolla\\b|\\bTP750\\b"},"browsers":{"Chrome":"\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?","Dolfin":"\\bDolfin\\b","Opera":"Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+","Skyfire":"Skyfire","IE":"IEMobile|MSIEMobile","Firefox":"fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile","Bolt":"bolt","TeaShark":"teashark","Blazer":"Blazer","Safari":"Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari","Tizen":"Tizen","UCBrowser":"UC.*Browser|UCWEB","baiduboxapp":"baiduboxapp","baidubrowser":"baidubrowser","DiigoBrowser":"DiigoBrowser","Puffin":"Puffin","Mercury":"\\bMercury\\b","ObigoBrowser":"Obigo","NetFront":"NF-Browser","GenericBrowser":"NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger","PaleMoon":"Android.*PaleMoon|Mobile.*PaleMoon"},"os":{"AndroidOS":"Android","BlackBerryOS":"blackberry|\\bBB10\\b|rim tablet os","PalmOS":"PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino","SymbianOS":"Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b","WindowsMobileOS":"Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;","WindowsPhoneOS":"Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;","iOS":"\\biPhone.*Mobile|\\biPod|\\biPad","MeeGoOS":"MeeGo","MaemoOS":"Maemo","JavaOS":"J2ME\/|\\bMIDP\\b|\\bCLDC\\b","webOS":"webOS|hpwOS","badaOS":"\\bBada\\b","BREWOS":"BREW"},"utilities":{"Bot":"Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom","MobileBot":"Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2","DesktopMode":"WPDesktop","TV":"SonyDTV|HbbTV","WebKit":"(webkit)[ \/]([\\w.]+)","Console":"\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b","Watch":"SM-V700"}}}
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/Mobile_Detect.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/Mobile_Detect.php
new file mode 100644
index 0000000..00ce9a9
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/Mobile_Detect.php
@@ -0,0 +1,1447 @@
+
+ * Nick Ilyin
+ *
+ * Original author: Victor Stanciu
+ *
+ * @license Code and contributions have 'MIT License'
+ * More details: https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE.txt
+ *
+ * @link Homepage: http://mobiledetect.net
+ * GitHub Repo: https://github.com/serbanghita/Mobile-Detect
+ * Google Code: http://code.google.com/p/php-mobile-detect/
+ * README: https://github.com/serbanghita/Mobile-Detect/blob/master/README.md
+ * HOWTO: https://github.com/serbanghita/Mobile-Detect/wiki/Code-examples
+ *
+ * @version 2.8.22
+ */
+
+class Mobile_Detect
+{
+ /**
+ * Mobile detection type.
+ *
+ * @deprecated since version 2.6.9
+ */
+ const DETECTION_TYPE_MOBILE = 'mobile';
+
+ /**
+ * Extended detection type.
+ *
+ * @deprecated since version 2.6.9
+ */
+ const DETECTION_TYPE_EXTENDED = 'extended';
+
+ /**
+ * A frequently used regular expression to extract version #s.
+ *
+ * @deprecated since version 2.6.9
+ */
+ const VER = '([\w._\+]+)';
+
+ /**
+ * Top-level device.
+ */
+ const MOBILE_GRADE_A = 'A';
+
+ /**
+ * Mid-level device.
+ */
+ const MOBILE_GRADE_B = 'B';
+
+ /**
+ * Low-level device.
+ */
+ const MOBILE_GRADE_C = 'C';
+
+ /**
+ * Stores the version number of the current release.
+ */
+ const VERSION = '2.8.22';
+
+ /**
+ * A type for the version() method indicating a string return value.
+ */
+ const VERSION_TYPE_STRING = 'text';
+
+ /**
+ * A type for the version() method indicating a float return value.
+ */
+ const VERSION_TYPE_FLOAT = 'float';
+
+ /**
+ * A cache for resolved matches
+ * @var array
+ */
+ protected $cache = array();
+
+ /**
+ * The User-Agent HTTP header is stored in here.
+ * @var string
+ */
+ protected $userAgent = null;
+
+ /**
+ * HTTP headers in the PHP-flavor. So HTTP_USER_AGENT and SERVER_SOFTWARE.
+ * @var array
+ */
+ protected $httpHeaders = array();
+
+ /**
+ * CloudFront headers. E.g. CloudFront-Is-Desktop-Viewer, CloudFront-Is-Mobile-Viewer & CloudFront-Is-Tablet-Viewer.
+ * @var array
+ */
+ protected $cloudfrontHeaders = array();
+
+ /**
+ * The matching Regex.
+ * This is good for debug.
+ * @var string
+ */
+ protected $matchingRegex = null;
+
+ /**
+ * The matches extracted from the regex expression.
+ * This is good for debug.
+ * @var string
+ */
+ protected $matchesArray = null;
+
+ /**
+ * The detection type, using self::DETECTION_TYPE_MOBILE or self::DETECTION_TYPE_EXTENDED.
+ *
+ * @deprecated since version 2.6.9
+ *
+ * @var string
+ */
+ protected $detectionType = self::DETECTION_TYPE_MOBILE;
+
+ /**
+ * HTTP headers that trigger the 'isMobile' detection
+ * to be true.
+ *
+ * @var array
+ */
+ protected static $mobileHeaders = array(
+
+ 'HTTP_ACCEPT' => array('matches' => array(
+ // Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/
+ 'application/x-obml2d',
+ // BlackBerry devices.
+ 'application/vnd.rim.html',
+ 'text/vnd.wap.wml',
+ 'application/vnd.wap.xhtml+xml'
+ )),
+ 'HTTP_X_WAP_PROFILE' => null,
+ 'HTTP_X_WAP_CLIENTID' => null,
+ 'HTTP_WAP_CONNECTION' => null,
+ 'HTTP_PROFILE' => null,
+ // Reported by Opera on Nokia devices (eg. C3).
+ 'HTTP_X_OPERAMINI_PHONE_UA' => null,
+ 'HTTP_X_NOKIA_GATEWAY_ID' => null,
+ 'HTTP_X_ORANGE_ID' => null,
+ 'HTTP_X_VODAFONE_3GPDPCONTEXT' => null,
+ 'HTTP_X_HUAWEI_USERID' => null,
+ // Reported by Windows Smartphones.
+ 'HTTP_UA_OS' => null,
+ // Reported by Verizon, Vodafone proxy system.
+ 'HTTP_X_MOBILE_GATEWAY' => null,
+ // Seen this on HTC Sensation. SensationXE_Beats_Z715e.
+ 'HTTP_X_ATT_DEVICEID' => null,
+ // Seen this on a HTC.
+ 'HTTP_UA_CPU' => array('matches' => array('ARM')),
+ );
+
+ /**
+ * List of mobile devices (phones).
+ *
+ * @var array
+ */
+ protected static $phoneDevices = array(
+ 'iPhone' => '\biPhone\b|\biPod\b', // |\biTunes
+ 'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+',
+ 'HTC' => 'HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b|T-Mobile G1|Z520m',
+ 'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6',
+ // @todo: Is 'Dell Streak' a tablet or a phone? ;)
+ 'Dell' => 'Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b',
+ 'Motorola' => 'Motorola|DROIDX|DROID BIONIC|\bDroid\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\bMoto E\b',
+ 'Samsung' => 'Samsung|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F',
+ 'LG' => '\bLG\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)',
+ 'Sony' => 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533',
+ 'Asus' => 'Asus.*Galaxy|PadFone.*Mobile',
+ 'NokiaLumia' => 'Lumia [0-9]{3,4}',
+ // http://www.micromaxinfo.com/mobiles/smartphones
+ // Added because the codes might conflict with Acer Tablets.
+ 'Micromax' => 'Micromax.*\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\b',
+ // @todo Complete the regex.
+ 'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ;
+ 'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun ;)
+ // http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH)
+ // Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android.
+ 'Pantech' => 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790',
+ // http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones.
+ 'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250',
+ // http://fr.wikomobile.com
+ 'Wiko' => 'KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM',
+ 'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)',
+ // Added simvalley mobile just for fun. They have some interesting devices.
+ // http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html
+ 'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b',
+ // Wolfgang - a brand that is sold by Aldi supermarkets.
+ // http://www.wolfgangmobile.com/
+ 'Wolfgang' => 'AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q',
+ 'Alcatel' => 'Alcatel',
+ 'Nintendo' => 'Nintendo 3DS',
+ // http://en.wikipedia.org/wiki/Amoi
+ 'Amoi' => 'Amoi',
+ // http://en.wikipedia.org/wiki/INQ
+ 'INQ' => 'INQ',
+ // @Tapatalk is a mobile app; http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039
+ 'GenericPhone' => 'Tapatalk|PDA;|SAGEM|\bmmp\b|pocket|\bpsp\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\bwap\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser',
+ );
+
+ /**
+ * List of tablet devices.
+ *
+ * @var array
+ */
+ protected static $tabletDevices = array(
+ // @todo: check for mobile friendly emails topic.
+ 'iPad' => 'iPad|iPad.*Mobile',
+ // Removed |^.*Android.*Nexus(?!(?:Mobile).)*$
+ // @see #442
+ 'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)',
+ 'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561', // SCH-P709|SCH-P729|SM-T2558|GT-I9205 - Samsung Mega - treat them like a regular phone.
+ // http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html
+ 'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI)\b',
+ // Only the Surface tablets with Windows RT are considered mobile.
+ // http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx
+ 'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)',
+ // http://shopping1.hp.com/is-bin/INTERSHOP.enfinity/WFS/WW-USSMBPublicStore-Site/en_US/-/USD/ViewStandardCatalog-Browse?CatalogCategoryID=JfIQ7EN5lqMAAAEyDcJUDwMT
+ 'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10',
+ // Watch out for PadFone, see #132.
+ // http://www.asus.com/de/Tablets_Mobile/Memo_Pad_Products/
+ 'AsusTablet' => '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b|\bK00C\b|\bK00E\b|\bK00L\b|TX201LA|ME176C|ME102A|\bM80TA\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K017 |ME572C|ME103K|ME170C|ME171C|\bME70C\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA',
+ 'BlackBerryTablet' => 'PlayBook|RIM Tablet',
+ 'HTCtablet' => 'HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410',
+ 'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617',
+ 'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2',
+ // http://www.acer.ro/ac/ro/RO/content/drivers
+ // http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer)
+ // http://us.acer.com/ac/en/US/content/group/tablets
+ // http://www.acer.de/ac/de/DE/content/models/tablets/
+ // Can conflict with Micromax and Motorola phones codes.
+ 'AcerTablet' => 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\b|W3-810|\bA3-A10\b|\bA3-A11\b|\bA3-A20',
+ // http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/
+ // http://us.toshiba.com/tablets/tablet-finder
+ // http://www.toshiba.co.jp/regza/tablet/
+ 'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO',
+ // http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html
+ // http://www.lg.com/us/tablets
+ 'LGTablet' => '\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\b',
+ 'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b',
+ // Prestigio Tablets http://www.prestigio.com/support
+ 'PrestigioTablet' => 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002',
+ // http://support.lenovo.com/en_GB/downloads/default.page?#
+ 'LenovoTablet' => 'Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)',
+ // http://www.dell.com/support/home/us/en/04/Products/tab_mob/tablets
+ 'DellTablet' => 'Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7',
+ // http://www.yarvik.com/en/matrix/tablets/
+ 'YarvikTablet' => 'Android.*\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\b',
+ 'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB',
+ 'ArnovaTablet' => 'AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2',
+ // http://www.intenso.de/kategorie_en.php?kategorie=33
+ // @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate
+ 'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004',
+ // IRU.ru Tablets http://www.iru.ru/catalog/soho/planetable/
+ 'IRUTablet' => 'M702pro',
+ 'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b',
+ // http://www.e-boda.ro/tablete-pc.html
+ 'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)',
+ // http://www.allview.ro/produse/droseries/lista-tablete-pc/
+ 'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)',
+ // http://wiki.archosfans.com/index.php?title=Main_Page
+ 'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b',
+ // http://www.ainol.com/plugin.php?identifier=ainol&module=product
+ 'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark',
+ 'NokiaLumiaTablet' => 'Lumia 2520',
+ // @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER
+ // Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser
+ // http://www.sony.jp/support/tablet/
+ 'SonyTablet' => 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31',
+ // http://www.support.philips.com/support/catalog/worldproducts.jsp?userLanguage=en&userCountry=cn&categoryid=3G_LTE_TABLET_SU_CN_CARE&title=3G%20tablets%20/%20LTE%20range&_dyncharset=UTF-8
+ 'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b',
+ // db + http://www.cube-tablet.com/buy-products.html
+ 'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT',
+ // http://www.cobyusa.com/?p=pcat&pcat_id=3001
+ 'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010',
+ // http://www.match.net.cn/products.asp
+ 'MIDTablet' => 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10',
+ // http://www.msi.com/support
+ // @todo Research the Windows Tablets.
+ 'MSITablet' => 'MSI \b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\b',
+ // @todo http://www.kyoceramobile.com/support/drivers/
+ // 'KyoceraTablet' => null,
+ // @todo http://intexuae.com/index.php/category/mobile-devices/tablets-products/
+ // 'IntextTablet' => null,
+ // http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets)
+ // http://www.imp3.net/14/show.php?itemid=20454
+ 'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)',
+ // http://www.rock-chips.com/index.php?do=prod&pid=2
+ 'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A',
+ // http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/
+ 'FlyTablet' => 'IQ310|Fly Vision',
+ // http://www.bqreaders.com/gb/tablets-prices-sale.html
+ 'bqTablet' => 'Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris E10)|Maxwell.*Lite|Maxwell.*Plus',
+ // http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290
+ // http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets)
+ 'HuaweiTablet' => 'MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim',
+ // Nec or Medias Tab
+ 'NecTablet' => '\bN-06D|\bN-08D',
+ // Pantech Tablets: http://www.pantechusa.com/phones/
+ 'PantechTablet' => 'Pantech.*P4100',
+ // Broncho Tablets: http://www.broncho.cn/ (hard to find)
+ 'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)',
+ // http://versusuk.com/support.html
+ 'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b',
+ // http://www.zync.in/index.php/our-products/tablet-phablets
+ 'ZyncTablet' => 'z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900',
+ // http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/
+ 'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA',
+ // https://www.nabitablet.com/
+ 'NabiTablet' => 'Android.*\bNabi',
+ 'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build',
+ // French Danew Tablets http://www.danew.com/produits-tablette.php
+ 'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b',
+ // Texet Tablets and Readers http://www.texet.ru/tablet/
+ 'TexetTablet' => 'NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE',
+ // Avoid detecting 'PLAYSTATION 3' as mobile.
+ 'PlaystationTablet' => 'Playstation.*(Portable|Vita)',
+ // http://www.trekstor.de/surftabs.html
+ 'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab',
+ // http://www.pyleaudio.com/Products.aspx?%2fproducts%2fPersonal-Electronics%2fTablets
+ 'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b',
+ // http://www.advandigital.com/index.php?link=content-product&jns=JP001
+ // because of the short codenames we have to include whitespaces to reduce the possible conflicts.
+ 'AdvanTablet' => 'Android.* \b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\b ',
+ // http://www.danytech.com/category/tablet-pc
+ 'DanyTechTablet' => 'Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1',
+ // http://www.galapad.net/product.html
+ 'GalapadTablet' => 'Android.*\bG1\b',
+ // http://www.micromaxinfo.com/tablet/funbook
+ 'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b',
+ // http://www.karbonnmobiles.com/products_tablet.php
+ 'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b',
+ // http://www.myallfine.com/Products.asp
+ 'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide',
+ // http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr=
+ 'PROSCANTablet' => '\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\b',
+ // http://www.yonesnav.com/products/products.php
+ 'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026',
+ // http://www.cjshowroom.com/eproducts.aspx?classcode=004001001
+ // China manufacturer makes tablets for different small brands (eg. http://www.zeepad.net/index.html)
+ 'ChangJiaTablet' => 'TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503',
+ // http://www.gloryunion.cn/products.asp
+ // http://www.allwinnertech.com/en/apply/mobile.html
+ // http://www.ptcl.com.pk/pd_content.php?pd_id=284 (EVOTAB)
+ // @todo: Softwiner tablets?
+ // aka. Cute or Cool tablets. Not sure yet, must research to avoid collisions.
+ 'GUTablet' => 'TX-A1301|TX-M9002|Q702|kf026', // A12R|D75A|D77|D79|R83|A95|A106C|R15|A75|A76|D71|D72|R71|R73|R77|D82|R85|D92|A97|D92|R91|A10F|A77F|W71F|A78F|W78F|W81F|A97F|W91F|W97F|R16G|C72|C73E|K72|K73|R96G
+ // http://www.pointofview-online.com/showroom.php?shop_mode=product_listing&category_id=118
+ 'PointOfViewTablet' => 'TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10',
+ // http://www.overmax.pl/pl/katalog-produktow,p8/tablety,c14/
+ // @todo: add more tests.
+ 'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)',
+ // http://hclmetablet.com/India/index.php
+ 'HCLTablet' => 'HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync',
+ // http://www.edigital.hu/Tablet_es_e-book_olvaso/Tablet-c18385.html
+ 'DPSTablet' => 'DPS Dream 9|DPS Dual 7',
+ // http://www.visture.com/index.asp
+ 'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10',
+ // http://www.mijncresta.nl/tablet
+ 'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989',
+ // MediaTek - http://www.mediatek.com/_en/01_products/02_proSys.php?cata_sn=1&cata1_sn=1&cata2_sn=309
+ 'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b',
+ // Concorde tab
+ 'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan',
+ // GoClever Tablets - http://www.goclever.com/uk/products,c1/tablet,c5/
+ 'GoCleverTablet' => 'GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042',
+ // Modecom Tablets - http://www.modecom.eu/tablets/portal/
+ 'ModecomTablet' => 'FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003',
+ // Vonino Tablets - http://www.vonino.eu/tablets
+ 'VoninoTablet' => '\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\bQ8\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\b',
+ // ECS Tablets - http://www.ecs.com.tw/ECSWebSite/Product/Product_Tablet_List.aspx?CategoryID=14&MenuID=107&childid=M_107&LanID=0
+ 'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1',
+ // Storex Tablets - http://storex.fr/espace_client/support.html
+ // @note: no need to add all the tablet codes since they are guided by the first regex.
+ 'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab',
+ // Generic Vodafone tablets.
+ 'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7',
+ // French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb
+ // Aka: http://www.essentielb.fr/
+ 'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2',
+ // Ross & Moor - http://ross-moor.ru/
+ 'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711',
+ // i-mobile http://product.i-mobilephone.com/Mobile_Device
+ 'iMobileTablet' => 'i-mobile i-note',
+ // http://www.tolino.de/de/vergleichen/
+ 'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine',
+ // AudioSonic - a Kmart brand
+ // http://www.kmart.com.au/webapp/wcs/stores/servlet/Search?langId=-1&storeId=10701&catalogId=10001&categoryId=193001&pageSize=72¤tPage=1&searchCategory=193001%2b4294965664&sortBy=p_MaxPrice%7c1
+ 'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b',
+ // AMPE Tablets - http://www.ampe.com.my/product-category/tablets/
+ // @todo: add them gradually to avoid conflicts.
+ 'AMPETablet' => 'Android.* A78 ',
+ // Skk Mobile - http://skkmobile.com.ph/product_tablets.php
+ 'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)',
+ // Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1
+ 'TecnoTablet' => 'TECNO P9',
+ // JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3
+ 'JXDTablet' => 'Android.* \b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b',
+ // i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/
+ 'iJoyTablet' => 'Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)',
+ // http://www.intracon.eu/tablet
+ 'FX2Tablet' => 'FX2 PAD7|FX2 PAD10',
+ // http://www.xoro.de/produkte/
+ // @note: Might be the same brand with 'Simply tablets'
+ 'XoroTablet' => 'KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151',
+ // http://www1.viewsonic.com/products/computing/tablets/
+ 'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a',
+ // http://www.odys.de/web/internet-tablet_en.html
+ 'OdysTablet' => 'LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\bXELIO\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10',
+ // http://www.captiva-power.de/products.html#tablets-en
+ 'CaptivaTablet' => 'CAPTIVA PAD',
+ // IconBIT - http://www.iconbit.com/products/tablets/
+ 'IconbitTablet' => 'NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S',
+ // http://www.teclast.com/topic.php?channelID=70&topicID=140&pid=63
+ 'TeclastTablet' => 'T98 4G|\bP80\b|\bX90HD\b|X98 Air|X98 Air 3G|\bX89\b|P80 3G|\bX80h\b|P98 Air|\bX89HD\b|P98 3G|\bP90HD\b|P89 3G|X98 3G|\bP70h\b|P79HD 3G|G18d 3G|\bP79HD\b|\bP89s\b|\bA88\b|\bP10HD\b|\bP19HD\b|G18 3G|\bP78HD\b|\bA78\b|\bP75\b|G17s 3G|G17h 3G|\bP85t\b|\bP90\b|\bP11\b|\bP98t\b|\bP98HD\b|\bG18d\b|\bP85s\b|\bP11HD\b|\bP88s\b|\bA80HD\b|\bA80se\b|\bA10h\b|\bP89\b|\bP78s\b|\bG18\b|\bP85\b|\bA70h\b|\bA70\b|\bG17\b|\bP18\b|\bA80s\b|\bA11s\b|\bP88HD\b|\bA80h\b|\bP76s\b|\bP76h\b|\bP98\b|\bA10HD\b|\bP78\b|\bP88\b|\bA11\b|\bA10t\b|\bP76a\b|\bP76t\b|\bP76e\b|\bP85HD\b|\bP85a\b|\bP86\b|\bP75HD\b|\bP76v\b|\bA12\b|\bP75a\b|\bA15\b|\bP76Ti\b|\bP81HD\b|\bA10\b|\bT760VE\b|\bT720HD\b|\bP76\b|\bP73\b|\bP71\b|\bP72\b|\bT720SE\b|\bC520Ti\b|\bT760\b|\bT720VE\b|T720-3GE|T720-WiFi',
+ // Onda - http://www.onda-tablet.com/buy-android-onda.html?dir=desc&limit=all&order=price
+ 'OndaTablet' => '\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\b[\s]+',
+ 'JaytechTablet' => 'TPC-PA762',
+ 'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010',
+ // http://www.digma.ru/support/download/
+ // @todo: Ebooks also (if requested)
+ 'DigmaTablet' => '\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\b',
+ // http://www.evolioshop.com/ro/tablete-pc.html
+ // http://www.evolio.ro/support/downloads_static.html?cat=2
+ // @todo: Research some more
+ 'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b',
+ // @todo http://www.lavamobiles.com/tablets-data-cards
+ 'LavaTablet' => 'QPAD E704|\bIvoryS\b|E-TAB IVORY|\bE-TAB\b',
+ // http://www.breezetablet.com/
+ 'AocTablet' => 'MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712',
+ // http://www.mpmaneurope.com/en/products/internet-tablets-14/android-tablets-14/
+ 'MpmanTablet' => 'MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\bMPG7\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010',
+ // https://www.celkonmobiles.com/?_a=categoryphones&sid=2
+ 'CelkonTablet' => 'CT695|CT888|CT[\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\bCT-1\b',
+ // http://www.wolderelectronics.com/productos/manuales-y-guias-rapidas/categoria-2-miTab
+ 'WolderTablet' => 'miTab \b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\b',
+ // http://www.mi.com/en
+ 'MiTablet' => '\bMI PAD\b|\bHM NOTE 1W\b',
+ // http://www.nbru.cn/index.html
+ 'NibiruTablet' => 'Nibiru M1|Nibiru Jupiter One',
+ // http://navroad.com/products/produkty/tablety/
+ 'NexoTablet' => 'NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI',
+ // http://leader-online.com/new_site/product-category/tablets/
+ // http://www.leader-online.net.au/List/Tablet
+ 'LeaderTablet' => 'TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100',
+ // http://www.datawind.com/ubislate/
+ 'UbislateTablet' => 'UbiSlate[\s]?7C',
+ // http://www.pocketbook-int.com/ru/support
+ 'PocketBookTablet' => 'Pocketbook',
+ // http://www.kocaso.com/product_tablet.html
+ 'KocasoTablet' => '\b(TB-1207)\b',
+ // http://www.tesco.com/direct/hudl/
+ 'Hudl' => 'Hudl HT7S3|Hudl 2',
+ // http://www.telstra.com.au/home-phone/thub-2/
+ 'TelstraTablet' => 'T-Hub2',
+ 'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\bM6pro\b|CT1020W|arc 10HD|\bJolla\b|\bTP750\b'
+ );
+
+ /**
+ * List of mobile Operating Systems.
+ *
+ * @var array
+ */
+ protected static $operatingSystems = array(
+ 'AndroidOS' => 'Android',
+ 'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os',
+ 'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino',
+ 'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b',
+ // @reference: http://en.wikipedia.org/wiki/Windows_Mobile
+ 'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;',
+ // @reference: http://en.wikipedia.org/wiki/Windows_Phone
+ // http://wifeng.cn/?r=blog&a=view&id=106
+ // http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx
+ // http://msdn.microsoft.com/library/ms537503.aspx
+ // https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
+ 'WindowsPhoneOS' => 'Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;',
+ 'iOS' => '\biPhone.*Mobile|\biPod|\biPad',
+ // http://en.wikipedia.org/wiki/MeeGo
+ // @todo: research MeeGo in UAs
+ 'MeeGoOS' => 'MeeGo',
+ // http://en.wikipedia.org/wiki/Maemo
+ // @todo: research Maemo in UAs
+ 'MaemoOS' => 'Maemo',
+ 'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135
+ 'webOS' => 'webOS|hpwOS',
+ 'badaOS' => '\bBada\b',
+ 'BREWOS' => 'BREW',
+ );
+
+ /**
+ * List of mobile User Agents.
+ *
+ * @var array
+ */
+ protected static $browsers = array(
+ // @reference: https://developers.google.com/chrome/mobile/docs/user-agent
+ 'Chrome' => '\bCrMo\b|CriOS|Android.*Chrome/[.0-9]* (Mobile)?',
+ 'Dolfin' => '\bDolfin\b',
+ 'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+|Coast/[0-9.]+',
+ 'Skyfire' => 'Skyfire',
+ 'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+
+ 'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile',
+ 'Bolt' => 'bolt',
+ 'TeaShark' => 'teashark',
+ 'Blazer' => 'Blazer',
+ // @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3
+ 'Safari' => 'Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari',
+ // http://en.wikipedia.org/wiki/Midori_(web_browser)
+ //'Midori' => 'midori',
+ 'Tizen' => 'Tizen',
+ 'UCBrowser' => 'UC.*Browser|UCWEB',
+ 'baiduboxapp' => 'baiduboxapp',
+ 'baidubrowser' => 'baidubrowser',
+ // https://github.com/serbanghita/Mobile-Detect/issues/7
+ 'DiigoBrowser' => 'DiigoBrowser',
+ // http://www.puffinbrowser.com/index.php
+ 'Puffin' => 'Puffin',
+ // http://mercury-browser.com/index.html
+ 'Mercury' => '\bMercury\b',
+ // http://en.wikipedia.org/wiki/Obigo_Browser
+ 'ObigoBrowser' => 'Obigo',
+ // http://en.wikipedia.org/wiki/NetFront
+ 'NetFront' => 'NF-Browser',
+ // @reference: http://en.wikipedia.org/wiki/Minimo
+ // http://en.wikipedia.org/wiki/Vision_Mobile_Browser
+ 'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger',
+ // @reference: https://en.wikipedia.org/wiki/Pale_Moon_(web_browser)
+ 'PaleMoon' => 'Android.*PaleMoon|Mobile.*PaleMoon',
+ );
+
+ /**
+ * Utilities.
+ *
+ * @var array
+ */
+ protected static $utilities = array(
+ // Experimental. When a mobile device wants to switch to 'Desktop Mode'.
+ // http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/
+ // https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011
+ // https://developers.facebook.com/docs/sharing/best-practices
+ 'Bot' => 'Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom',
+ 'MobileBot' => 'Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker/M1A1-R2D2',
+ 'DesktopMode' => 'WPDesktop',
+ 'TV' => 'SonyDTV|HbbTV', // experimental
+ 'WebKit' => '(webkit)[ /]([\w.]+)',
+ // @todo: Include JXD consoles.
+ 'Console' => '\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\b',
+ 'Watch' => 'SM-V700',
+ );
+
+ /**
+ * All possible HTTP headers that represent the
+ * User-Agent string.
+ *
+ * @var array
+ */
+ protected static $uaHttpHeaders = array(
+ // The default User-Agent string.
+ 'HTTP_USER_AGENT',
+ // Header can occur on devices using Opera Mini.
+ 'HTTP_X_OPERAMINI_PHONE_UA',
+ // Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/
+ 'HTTP_X_DEVICE_USER_AGENT',
+ 'HTTP_X_ORIGINAL_USER_AGENT',
+ 'HTTP_X_SKYFIRE_PHONE',
+ 'HTTP_X_BOLT_PHONE_UA',
+ 'HTTP_DEVICE_STOCK_UA',
+ 'HTTP_X_UCBROWSER_DEVICE_UA'
+ );
+
+ /**
+ * The individual segments that could exist in a User-Agent string. VER refers to the regular
+ * expression defined in the constant self::VER.
+ *
+ * @var array
+ */
+ protected static $properties = array(
+
+ // Build
+ 'Mobile' => 'Mobile/[VER]',
+ 'Build' => 'Build/[VER]',
+ 'Version' => 'Version/[VER]',
+ 'VendorID' => 'VendorID/[VER]',
+
+ // Devices
+ 'iPad' => 'iPad.*CPU[a-z ]+[VER]',
+ 'iPhone' => 'iPhone.*CPU[a-z ]+[VER]',
+ 'iPod' => 'iPod.*CPU[a-z ]+[VER]',
+ //'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'),
+ 'Kindle' => 'Kindle/[VER]',
+
+ // Browser
+ 'Chrome' => array('Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]'),
+ 'Coast' => array('Coast/[VER]'),
+ 'Dolfin' => 'Dolfin/[VER]',
+ // @reference: https://developer.mozilla.org/en-US/docs/User_Agent_Strings_Reference
+ 'Firefox' => 'Firefox/[VER]',
+ 'Fennec' => 'Fennec/[VER]',
+ // http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx
+ // https://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx
+ 'IE' => array('IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];', 'Trident/[0-9.]+;.*rv:[VER]'),
+ // http://en.wikipedia.org/wiki/NetFront
+ 'NetFront' => 'NetFront/[VER]',
+ 'NokiaBrowser' => 'NokiaBrowser/[VER]',
+ 'Opera' => array( ' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]' ),
+ 'Opera Mini' => 'Opera Mini/[VER]',
+ 'Opera Mobi' => 'Version/[VER]',
+ 'UC Browser' => 'UC Browser[VER]',
+ 'MQQBrowser' => 'MQQBrowser/[VER]',
+ 'MicroMessenger' => 'MicroMessenger/[VER]',
+ 'baiduboxapp' => 'baiduboxapp/[VER]',
+ 'baidubrowser' => 'baidubrowser/[VER]',
+ 'Iron' => 'Iron/[VER]',
+ // @note: Safari 7534.48.3 is actually Version 5.1.
+ // @note: On BlackBerry the Version is overwriten by the OS.
+ 'Safari' => array( 'Version/[VER]', 'Safari/[VER]' ),
+ 'Skyfire' => 'Skyfire/[VER]',
+ 'Tizen' => 'Tizen/[VER]',
+ 'Webkit' => 'webkit[ /][VER]',
+ 'PaleMoon' => 'PaleMoon/[VER]',
+
+ // Engine
+ 'Gecko' => 'Gecko/[VER]',
+ 'Trident' => 'Trident/[VER]',
+ 'Presto' => 'Presto/[VER]',
+ 'Goanna' => 'Goanna/[VER]',
+
+ // OS
+ 'iOS' => ' \bi?OS\b [VER][ ;]{1}',
+ 'Android' => 'Android [VER]',
+ 'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'),
+ 'BREW' => 'BREW [VER]',
+ 'Java' => 'Java/[VER]',
+ // @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx
+ // @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases
+ 'Windows Phone OS' => array( 'Windows Phone OS [VER]', 'Windows Phone [VER]'),
+ 'Windows Phone' => 'Windows Phone [VER]',
+ 'Windows CE' => 'Windows CE/[VER]',
+ // http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd
+ 'Windows NT' => 'Windows NT [VER]',
+ 'Symbian' => array('SymbianOS/[VER]', 'Symbian/[VER]'),
+ 'webOS' => array('webOS/[VER]', 'hpwOS/[VER];'),
+ );
+
+ /**
+ * Construct an instance of this class.
+ *
+ * @param array $headers Specify the headers as injection. Should be PHP _SERVER flavored.
+ * If left empty, will use the global _SERVER['HTTP_*'] vars instead.
+ * @param string $userAgent Inject the User-Agent header. If null, will use HTTP_USER_AGENT
+ * from the $headers array instead.
+ */
+ public function __construct(
+ array $headers = null,
+ $userAgent = null
+ ) {
+ $this->setHttpHeaders($headers);
+ $this->setUserAgent($userAgent);
+ }
+
+ /**
+ * Get the current script version.
+ * This is useful for the demo.php file,
+ * so people can check on what version they are testing
+ * for mobile devices.
+ *
+ * @return string The version number in semantic version format.
+ */
+ public static function getScriptVersion()
+ {
+ return self::VERSION;
+ }
+
+ /**
+ * Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers.
+ *
+ * @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract
+ * the headers. The default null is left for backwards compatibility.
+ */
+ public function setHttpHeaders($httpHeaders = null)
+ {
+ // use global _SERVER if $httpHeaders aren't defined
+ if (!is_array($httpHeaders) || !count($httpHeaders)) {
+ $httpHeaders = $_SERVER;
+ }
+
+ // clear existing headers
+ $this->httpHeaders = array();
+
+ // Only save HTTP headers. In PHP land, that means only _SERVER vars that
+ // start with HTTP_.
+ foreach ($httpHeaders as $key => $value) {
+ if (substr($key, 0, 5) === 'HTTP_') {
+ $this->httpHeaders[$key] = $value;
+ }
+ }
+
+ // In case we're dealing with CloudFront, we need to know.
+ $this->setCfHeaders($httpHeaders);
+ }
+
+ /**
+ * Retrieves the HTTP headers.
+ *
+ * @return array
+ */
+ public function getHttpHeaders()
+ {
+ return $this->httpHeaders;
+ }
+
+ /**
+ * Retrieves a particular header. If it doesn't exist, no exception/error is caused.
+ * Simply null is returned.
+ *
+ * @param string $header The name of the header to retrieve. Can be HTTP compliant such as
+ * "User-Agent" or "X-Device-User-Agent" or can be php-esque with the
+ * all-caps, HTTP_ prefixed, underscore seperated awesomeness.
+ *
+ * @return string|null The value of the header.
+ */
+ public function getHttpHeader($header)
+ {
+ // are we using PHP-flavored headers?
+ if (strpos($header, '_') === false) {
+ $header = str_replace('-', '_', $header);
+ $header = strtoupper($header);
+ }
+
+ // test the alternate, too
+ $altHeader = 'HTTP_' . $header;
+
+ //Test both the regular and the HTTP_ prefix
+ if (isset($this->httpHeaders[$header])) {
+ return $this->httpHeaders[$header];
+ } elseif (isset($this->httpHeaders[$altHeader])) {
+ return $this->httpHeaders[$altHeader];
+ }
+
+ return null;
+ }
+
+ public function getMobileHeaders()
+ {
+ return self::$mobileHeaders;
+ }
+
+ /**
+ * Get all possible HTTP headers that
+ * can contain the User-Agent string.
+ *
+ * @return array List of HTTP headers.
+ */
+ public function getUaHttpHeaders()
+ {
+ return self::$uaHttpHeaders;
+ }
+
+
+ /**
+ * Set CloudFront headers
+ * http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-device
+ *
+ * @param array $cfHeaders List of HTTP headers
+ *
+ * @return boolean If there were CloudFront headers to be set
+ */
+ public function setCfHeaders($cfHeaders = null) {
+ // use global _SERVER if $cfHeaders aren't defined
+ if (!is_array($cfHeaders) || !count($cfHeaders)) {
+ $cfHeaders = $_SERVER;
+ }
+
+ // clear existing headers
+ $this->cloudfrontHeaders = array();
+
+ // Only save CLOUDFRONT headers. In PHP land, that means only _SERVER vars that
+ // start with cloudfront-.
+ $response = false;
+ foreach ($cfHeaders as $key => $value) {
+ if (substr(strtolower($key), 0, 16) === 'http_cloudfront_') {
+ $this->cloudfrontHeaders[strtoupper($key)] = $value;
+ $response = true;
+ }
+ }
+
+ return $response;
+ }
+
+ /**
+ * Retrieves the cloudfront headers.
+ *
+ * @return array
+ */
+ public function getCfHeaders()
+ {
+ return $this->cloudfrontHeaders;
+ }
+
+ /**
+ * Set the User-Agent to be used.
+ *
+ * @param string $userAgent The user agent string to set.
+ *
+ * @return string|null
+ */
+ public function setUserAgent($userAgent = null)
+ {
+ // Invalidate cache due to #375
+ $this->cache = array();
+
+ if (false === empty($userAgent)) {
+ return $this->userAgent = $userAgent;
+ } else {
+ $this->userAgent = null;
+ foreach ($this->getUaHttpHeaders() as $altHeader) {
+ if (false === empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow. (Serban)
+ $this->userAgent .= $this->httpHeaders[$altHeader] . " ";
+ }
+ }
+
+ if (!empty($this->userAgent)) {
+ return $this->userAgent = trim($this->userAgent);
+ }
+ }
+
+ if (count($this->getCfHeaders()) > 0) {
+ return $this->userAgent = 'Amazon CloudFront';
+ }
+ return $this->userAgent = null;
+ }
+
+ /**
+ * Retrieve the User-Agent.
+ *
+ * @return string|null The user agent if it's set.
+ */
+ public function getUserAgent()
+ {
+ return $this->userAgent;
+ }
+
+ /**
+ * Set the detection type. Must be one of self::DETECTION_TYPE_MOBILE or
+ * self::DETECTION_TYPE_EXTENDED. Otherwise, nothing is set.
+ *
+ * @deprecated since version 2.6.9
+ *
+ * @param string $type The type. Must be a self::DETECTION_TYPE_* constant. The default
+ * parameter is null which will default to self::DETECTION_TYPE_MOBILE.
+ */
+ public function setDetectionType($type = null)
+ {
+ if ($type === null) {
+ $type = self::DETECTION_TYPE_MOBILE;
+ }
+
+ if ($type !== self::DETECTION_TYPE_MOBILE && $type !== self::DETECTION_TYPE_EXTENDED) {
+ return;
+ }
+
+ $this->detectionType = $type;
+ }
+
+ public function getMatchingRegex()
+ {
+ return $this->matchingRegex;
+ }
+
+ public function getMatchesArray()
+ {
+ return $this->matchesArray;
+ }
+
+ /**
+ * Retrieve the list of known phone devices.
+ *
+ * @return array List of phone devices.
+ */
+ public static function getPhoneDevices()
+ {
+ return self::$phoneDevices;
+ }
+
+ /**
+ * Retrieve the list of known tablet devices.
+ *
+ * @return array List of tablet devices.
+ */
+ public static function getTabletDevices()
+ {
+ return self::$tabletDevices;
+ }
+
+ /**
+ * Alias for getBrowsers() method.
+ *
+ * @return array List of user agents.
+ */
+ public static function getUserAgents()
+ {
+ return self::getBrowsers();
+ }
+
+ /**
+ * Retrieve the list of known browsers. Specifically, the user agents.
+ *
+ * @return array List of browsers / user agents.
+ */
+ public static function getBrowsers()
+ {
+ return self::$browsers;
+ }
+
+ /**
+ * Retrieve the list of known utilities.
+ *
+ * @return array List of utilities.
+ */
+ public static function getUtilities()
+ {
+ return self::$utilities;
+ }
+
+ /**
+ * Method gets the mobile detection rules. This method is used for the magic methods $detect->is*().
+ *
+ * @deprecated since version 2.6.9
+ *
+ * @return array All the rules (but not extended).
+ */
+ public static function getMobileDetectionRules()
+ {
+ static $rules;
+
+ if (!$rules) {
+ $rules = array_merge(
+ self::$phoneDevices,
+ self::$tabletDevices,
+ self::$operatingSystems,
+ self::$browsers
+ );
+ }
+
+ return $rules;
+
+ }
+
+ /**
+ * Method gets the mobile detection rules + utilities.
+ * The reason this is separate is because utilities rules
+ * don't necessary imply mobile. This method is used inside
+ * the new $detect->is('stuff') method.
+ *
+ * @deprecated since version 2.6.9
+ *
+ * @return array All the rules + extended.
+ */
+ public function getMobileDetectionRulesExtended()
+ {
+ static $rules;
+
+ if (!$rules) {
+ // Merge all rules together.
+ $rules = array_merge(
+ self::$phoneDevices,
+ self::$tabletDevices,
+ self::$operatingSystems,
+ self::$browsers,
+ self::$utilities
+ );
+ }
+
+ return $rules;
+ }
+
+ /**
+ * Retrieve the current set of rules.
+ *
+ * @deprecated since version 2.6.9
+ *
+ * @return array
+ */
+ public function getRules()
+ {
+ if ($this->detectionType == self::DETECTION_TYPE_EXTENDED) {
+ return self::getMobileDetectionRulesExtended();
+ } else {
+ return self::getMobileDetectionRules();
+ }
+ }
+
+ /**
+ * Retrieve the list of mobile operating systems.
+ *
+ * @return array The list of mobile operating systems.
+ */
+ public static function getOperatingSystems()
+ {
+ return self::$operatingSystems;
+ }
+
+ /**
+ * Check the HTTP headers for signs of mobile.
+ * This is the fastest mobile check possible; it's used
+ * inside isMobile() method.
+ *
+ * @return bool
+ */
+ public function checkHttpHeadersForMobile()
+ {
+
+ foreach ($this->getMobileHeaders() as $mobileHeader => $matchType) {
+ if (isset($this->httpHeaders[$mobileHeader])) {
+ if (is_array($matchType['matches'])) {
+ foreach ($matchType['matches'] as $_match) {
+ if (strpos($this->httpHeaders[$mobileHeader], $_match) !== false) {
+ return true;
+ }
+ }
+
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ return false;
+
+ }
+
+ /**
+ * Magic overloading method.
+ *
+ * @method boolean is[...]()
+ * @param string $name
+ * @param array $arguments
+ * @return mixed
+ * @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is'
+ */
+ public function __call($name, $arguments)
+ {
+ // make sure the name starts with 'is', otherwise
+ if (substr($name, 0, 2) !== 'is') {
+ throw new BadMethodCallException("No such method exists: $name");
+ }
+
+ $this->setDetectionType(self::DETECTION_TYPE_MOBILE);
+
+ $key = substr($name, 2);
+
+ return $this->matchUAAgainstKey($key);
+ }
+
+ /**
+ * Find a detection rule that matches the current User-agent.
+ *
+ * @param null $userAgent deprecated
+ * @return boolean
+ */
+ protected function matchDetectionRulesAgainstUA($userAgent = null)
+ {
+ // Begin general search.
+ foreach ($this->getRules() as $_regex) {
+ if (empty($_regex)) {
+ continue;
+ }
+
+ if ($this->match($_regex, $userAgent)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Search for a certain key in the rules array.
+ * If the key is found then try to match the corresponding
+ * regex against the User-Agent.
+ *
+ * @param string $key
+ *
+ * @return boolean
+ */
+ protected function matchUAAgainstKey($key)
+ {
+ // Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc.
+ $key = strtolower($key);
+ if (false === isset($this->cache[$key])) {
+
+ // change the keys to lower case
+ $_rules = array_change_key_case($this->getRules());
+
+ if (false === empty($_rules[$key])) {
+ $this->cache[$key] = $this->match($_rules[$key]);
+ }
+
+ if (false === isset($this->cache[$key])) {
+ $this->cache[$key] = false;
+ }
+ }
+
+ return $this->cache[$key];
+ }
+
+ /**
+ * Check if the device is mobile.
+ * Returns true if any type of mobile device detected, including special ones
+ * @param null $userAgent deprecated
+ * @param null $httpHeaders deprecated
+ * @return bool
+ */
+ public function isMobile($userAgent = null, $httpHeaders = null)
+ {
+
+ if ($httpHeaders) {
+ $this->setHttpHeaders($httpHeaders);
+ }
+
+ if ($userAgent) {
+ $this->setUserAgent($userAgent);
+ }
+
+ // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
+ if ($this->getUserAgent() === 'Amazon CloudFront') {
+ $cfHeaders = $this->getCfHeaders();
+ if(array_key_exists('HTTP_CLOUDFRONT_IS_MOBILE_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_MOBILE_VIEWER'] === 'true') {
+ return true;
+ }
+ }
+
+ $this->setDetectionType(self::DETECTION_TYPE_MOBILE);
+
+ if ($this->checkHttpHeadersForMobile()) {
+ return true;
+ } else {
+ return $this->matchDetectionRulesAgainstUA();
+ }
+
+ }
+
+ /**
+ * Check if the device is a tablet.
+ * Return true if any type of tablet device is detected.
+ *
+ * @param string $userAgent deprecated
+ * @param array $httpHeaders deprecated
+ * @return bool
+ */
+ public function isTablet($userAgent = null, $httpHeaders = null)
+ {
+ // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
+ if ($this->getUserAgent() === 'Amazon CloudFront') {
+ $cfHeaders = $this->getCfHeaders();
+ if(array_key_exists('HTTP_CLOUDFRONT_IS_TABLET_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_TABLET_VIEWER'] === 'true') {
+ return true;
+ }
+ }
+
+ $this->setDetectionType(self::DETECTION_TYPE_MOBILE);
+
+ foreach (self::$tabletDevices as $_regex) {
+ if ($this->match($_regex, $userAgent)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * This method checks for a certain property in the
+ * userAgent.
+ * @todo: The httpHeaders part is not yet used.
+ *
+ * @param string $key
+ * @param string $userAgent deprecated
+ * @param string $httpHeaders deprecated
+ * @return bool|int|null
+ */
+ public function is($key, $userAgent = null, $httpHeaders = null)
+ {
+ // Set the UA and HTTP headers only if needed (eg. batch mode).
+ if ($httpHeaders) {
+ $this->setHttpHeaders($httpHeaders);
+ }
+
+ if ($userAgent) {
+ $this->setUserAgent($userAgent);
+ }
+
+ $this->setDetectionType(self::DETECTION_TYPE_EXTENDED);
+
+ return $this->matchUAAgainstKey($key);
+ }
+
+ /**
+ * Some detection rules are relative (not standard),
+ * because of the diversity of devices, vendors and
+ * their conventions in representing the User-Agent or
+ * the HTTP headers.
+ *
+ * This method will be used to check custom regexes against
+ * the User-Agent string.
+ *
+ * @param $regex
+ * @param string $userAgent
+ * @return bool
+ *
+ * @todo: search in the HTTP headers too.
+ */
+ public function match($regex, $userAgent = null)
+ {
+ $match = (bool) preg_match(sprintf('#%s#is', $regex), (false === empty($userAgent) ? $userAgent : $this->userAgent), $matches);
+ // If positive match is found, store the results for debug.
+ if ($match) {
+ $this->matchingRegex = $regex;
+ $this->matchesArray = $matches;
+ }
+
+ return $match;
+ }
+
+ /**
+ * Get the properties array.
+ *
+ * @return array
+ */
+ public static function getProperties()
+ {
+ return self::$properties;
+ }
+
+ /**
+ * Prepare the version number.
+ *
+ * @todo Remove the error supression from str_replace() call.
+ *
+ * @param string $ver The string version, like "2.6.21.2152";
+ *
+ * @return float
+ */
+ public function prepareVersionNo($ver)
+ {
+ $ver = str_replace(array('_', ' ', '/'), '.', $ver);
+ $arrVer = explode('.', $ver, 2);
+
+ if (isset($arrVer[1])) {
+ $arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions.
+ }
+
+ return (float) implode('.', $arrVer);
+ }
+
+ /**
+ * Check the version of the given property in the User-Agent.
+ * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
+ *
+ * @param string $propertyName The name of the property. See self::getProperties() array
+ * keys for all possible properties.
+ * @param string $type Either self::VERSION_TYPE_STRING to get a string value or
+ * self::VERSION_TYPE_FLOAT indicating a float value. This parameter
+ * is optional and defaults to self::VERSION_TYPE_STRING. Passing an
+ * invalid parameter will default to the this type as well.
+ *
+ * @return string|float The version of the property we are trying to extract.
+ */
+ public function version($propertyName, $type = self::VERSION_TYPE_STRING)
+ {
+ if (empty($propertyName)) {
+ return false;
+ }
+
+ // set the $type to the default if we don't recognize the type
+ if ($type !== self::VERSION_TYPE_STRING && $type !== self::VERSION_TYPE_FLOAT) {
+ $type = self::VERSION_TYPE_STRING;
+ }
+
+ $properties = self::getProperties();
+
+ // Check if the property exists in the properties array.
+ if (true === isset($properties[$propertyName])) {
+
+ // Prepare the pattern to be matched.
+ // Make sure we always deal with an array (string is converted).
+ $properties[$propertyName] = (array) $properties[$propertyName];
+
+ foreach ($properties[$propertyName] as $propertyMatchString) {
+
+ $propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString);
+
+ // Identify and extract the version.
+ preg_match(sprintf('#%s#is', $propertyPattern), $this->userAgent, $match);
+
+ if (false === empty($match[1])) {
+ $version = ($type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1]);
+
+ return $version;
+ }
+
+ }
+
+ }
+
+ return false;
+ }
+
+ /**
+ * Retrieve the mobile grading, using self::MOBILE_GRADE_* constants.
+ *
+ * @return string One of the self::MOBILE_GRADE_* constants.
+ */
+ public function mobileGrade()
+ {
+ $isMobile = $this->isMobile();
+
+ if (
+ // Apple iOS 4-7.0 – Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3 / 5.1 / 6.1), iPad 3 (5.1 / 6.0), iPad Mini (6.1), iPad Retina (7.0), iPhone 3GS (4.3), iPhone 4 (4.3 / 5.1), iPhone 4S (5.1 / 6.0), iPhone 5 (6.0), and iPhone 5S (7.0)
+ $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) >= 4.3 ||
+ $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) >= 4.3 ||
+ $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) >= 4.3 ||
+
+ // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5)
+ // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM
+ // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices
+ // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7
+ ( $this->version('Android', self::VERSION_TYPE_FLOAT)>2.1 && $this->is('Webkit') ) ||
+
+ // Windows Phone 7.5-8 - Tested on the HTC Surround (7.5), HTC Trophy (7.5), LG-E900 (7.5), Nokia 800 (7.8), HTC Mazaa (7.8), Nokia Lumia 520 (8), Nokia Lumia 920 (8), HTC 8x (8)
+ $this->version('Windows Phone OS', self::VERSION_TYPE_FLOAT) >= 7.5 ||
+
+ // Tested on the Torch 9800 (6) and Style 9670 (6), BlackBerry® Torch 9810 (7), BlackBerry Z10 (10)
+ $this->is('BlackBerry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 6.0 ||
+ // Blackberry Playbook (1.0-2.0) - Tested on PlayBook
+ $this->match('Playbook.*Tablet') ||
+
+ // Palm WebOS (1.4-3.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0), HP TouchPad (3.0)
+ ( $this->version('webOS', self::VERSION_TYPE_FLOAT) >= 1.4 && $this->match('Palm|Pre|Pixi') ) ||
+ // Palm WebOS 3.0 - Tested on HP TouchPad
+ $this->match('hp.*TouchPad') ||
+
+ // Firefox Mobile 18 - Tested on Android 2.3 and 4.1 devices
+ ( $this->is('Firefox') && $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 18 ) ||
+
+ // Chrome for Android - Tested on Android 4.0, 4.1 device
+ ( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 4.0 ) ||
+
+ // Skyfire 4.1 - Tested on Android 2.3 device
+ ( $this->is('Skyfire') && $this->version('Skyfire', self::VERSION_TYPE_FLOAT) >= 4.1 && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) ||
+
+ // Opera Mobile 11.5-12: Tested on Android 2.3
+ ( $this->is('Opera') && $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11.5 && $this->is('AndroidOS') ) ||
+
+ // Meego 1.2 - Tested on Nokia 950 and N9
+ $this->is('MeeGoOS') ||
+
+ // Tizen (pre-release) - Tested on early hardware
+ $this->is('Tizen') ||
+
+ // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser
+ // @todo: more tests here!
+ $this->is('Dolfin') && $this->version('Bada', self::VERSION_TYPE_FLOAT) >= 2.0 ||
+
+ // UC Browser - Tested on Android 2.3 device
+ ( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) ||
+
+ // Kindle 3 and Fire - Tested on the built-in WebKit browser for each
+ ( $this->match('Kindle Fire') ||
+ $this->is('Kindle') && $this->version('Kindle', self::VERSION_TYPE_FLOAT) >= 3.0 ) ||
+
+ // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet
+ $this->is('AndroidOS') && $this->is('NookTablet') ||
+
+ // Chrome Desktop 16-24 - Tested on OS X 10.7 and Windows 7
+ $this->version('Chrome', self::VERSION_TYPE_FLOAT) >= 16 && !$isMobile ||
+
+ // Safari Desktop 5-6 - Tested on OS X 10.7 and Windows 7
+ $this->version('Safari', self::VERSION_TYPE_FLOAT) >= 5.0 && !$isMobile ||
+
+ // Firefox Desktop 10-18 - Tested on OS X 10.7 and Windows 7
+ $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 10.0 && !$isMobile ||
+
+ // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7
+ $this->version('IE', self::VERSION_TYPE_FLOAT) >= 7.0 && !$isMobile ||
+
+ // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7
+ $this->version('Opera', self::VERSION_TYPE_FLOAT) >= 10 && !$isMobile
+ ){
+ return self::MOBILE_GRADE_A;
+ }
+
+ if (
+ $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT)<4.3 ||
+ $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<4.3 ||
+ $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT)<4.3 ||
+
+ // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770
+ $this->is('Blackberry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 5 && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<6 ||
+
+ //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3
+ ($this->version('Opera Mini', self::VERSION_TYPE_FLOAT) >= 5.0 && $this->version('Opera Mini', self::VERSION_TYPE_FLOAT) <= 7.0 &&
+ ($this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 || $this->is('iOS')) ) ||
+
+ // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1)
+ $this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') ||
+
+ // @todo: report this (tested on Nokia N71)
+ $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11 && $this->is('SymbianOS')
+ ){
+ return self::MOBILE_GRADE_B;
+ }
+
+ if (
+ // Blackberry 4.x - Tested on the Curve 8330
+ $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) <= 5.0 ||
+ // Windows Mobile - Tested on the HTC Leo (WinMo 5.2)
+ $this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile', self::VERSION_TYPE_FLOAT) <= 5.2 ||
+
+ // Tested on original iPhone (3.1), iPhone 3 (3.2)
+ $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) <= 3.2 ||
+ $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) <= 3.2 ||
+ $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) <= 3.2 ||
+
+ // Internet Explorer 7 and older - Tested on Windows XP
+ $this->version('IE', self::VERSION_TYPE_FLOAT) <= 7.0 && !$isMobile
+ ){
+ return self::MOBILE_GRADE_C;
+ }
+
+ // All older smartphone platforms and featurephones - Any device that doesn't support media queries
+ // will receive the basic, C grade experience.
+ return self::MOBILE_GRADE_C;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/README.md b/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/README.md
new file mode 100644
index 0000000..28da9a4
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/README.md
@@ -0,0 +1,278 @@
+[![Build Status](https://travis-ci.org/serbanghita/Mobile-Detect.svg?branch=devel)](https://travis-ci.org/serbanghita/Mobile-Detect) [![Latest Stable Version](https://poser.pugx.org/mobiledetect/mobiledetectlib/v/stable.svg)](https://packagist.org/packages/mobiledetect/mobiledetectlib) [![Total Downloads](https://poser.pugx.org/mobiledetect/mobiledetectlib/downloads.svg)](https://packagist.org/packages/mobiledetect/mobiledetectlib) [![Daily Downloads](https://poser.pugx.org/mobiledetect/mobiledetectlib/d/daily.png)](https://packagist.org/packages/mobiledetect/mobiledetectlib) [![License](https://poser.pugx.org/mobiledetect/mobiledetectlib/license.svg)](https://packagist.org/packages/mobiledetect/mobiledetectlib)
+[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/serbanghita/Mobile-Detect?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
+![Mobile Detect](http://demo.mobiledetect.net/logo-github.png)
+
+> Motto: "Every business should have a mobile detection script to detect mobile readers."
+
+*Mobile_Detect is a lightweight PHP class for detecting mobile devices (including tablets).
+It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.*
+
+We're committed to make Mobile_Detect the best open-source mobile detection resource and this is why before
+each release we're running [unit tests](./tests), we also research and update the detection rules on **daily**
+and **weekly** basis.
+
+Your website's _content strategy_ is important! You need a complete toolkit to deliver an experience that is _optimized_, _fast_ and _relevant_ to your users. Mobile_Detect class is a [server-side detection](http://www.w3.org/TR/mwabp/#bp-devcap-detection) tool that can help you with your RWD strategy, it is not a replacement for CSS3 media queries or other forms of client-side feature detection.
+
+##### Announcements
+
+For `2.x` branch we are no longer taking optimizations pull requests, but only new regexes and User-Agents for our tests.
+On `2.x` releases we are focusing on **new tablets only**. All the pull requests about TVs, bots or optimizations will be closed and analyzed after `3.0.0-beta` is released.
+
+Still working on `3.0.0` branch to provide you with device detection!
+We're really excited on this one!
+We would like to speed this up, but life and family gets in the way ;)
+
+Special thanks to **JetBrains** for providing licenses for **PHPStorm**. In case you never heard or tried PHPStorm, you're
+clearly missing out! [Check PHPStorm](https://www.jetbrains.com/phpstorm/) out!
+
+##### Download and demo
+
+|Download|Docs|Examples|
+|-------------|-------------|-------------|
+|[Go to releases](../../tags)|[Become a contributor](../../wiki/Become-a-contributor)|[Code examples](../../wiki/Code-examples)
+|[Mobile_Detect.php](./Mobile_Detect.php)|[History](../../wiki/History)|[:iphone: Live demo!](http://is.gd/mobiletest)
+|[Composer package](https://packagist.org/packages/mobiledetect/mobiledetectlib)|
+
+#### Continuous updates
+
+You can use [composer](https://getcomposer.org/doc/00-intro.md) in your release and update process to make sure you have the latest Mobile_Detect version.
+
+```
+composer require mobiledetect/mobiledetectlib
+```
+
+```json
+{
+ "require": {
+ "mobiledetect/mobiledetectlib": "^2.8"
+ }
+}
+```
+
+##### Help
+
+|Pledgie|Paypal|
+|-------|------|
+|[Donate :+1:](https://pledgie.com/campaigns/21856)|[Donate :beer:](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=mobiledetectlib%40gmail%2ecom&lc=US&item_name=Mobile%20Detect¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted)|
+
+
+I'm currently paying for hosting and spend a lot of my family time to maintain the project and planning the future releases.
+I would highly appreciate any money donations that will keep the research going.
+
+Special thanks to the community :+1: for donations, [BrowserStack](https://www.browserstack.com/) - for providing access to their great platform, [Zend](http://www.zend.com/) - for donating licenses, [Dragos Gavrila](https://twitter.com/grafician) who contributed with the logo.
+
+##### 3rd party modules / [Submit new](../../issues/new?title=New%203rd%20party%20module&body=Name, Link and Description of the module.)
+
+:point_right: Keep `Mobile_Detect.php` class in a separate `module` and do NOT include it in your script core because of the high frequency of updates.
+:point_right: When including the class into you `web application` or `module` always use `include_once '../path/to/Mobile_Detect.php` to prevent conflicts.
+
+
+
+
+ mobile-detect.js
+ A JavaScript port of Mobile-Detect class. Made by Heinrich Goebl .
+
+
+
+ Varnish Cache
+
+ Varnish Mobile Detect - Drop-in varnish solution to mobile user detection based on the Mobile-Detect library. Made by willemk .
+ mobiledetect2vcl - Python script to transform the Mobile Detect JSON database into an UA-based mobile detection VCL subroutine easily integrable in any Varnish Cache configuration. Made by Carlos Abalde .
+
+
+
+
+ LUA
+
+ mobile-detect.lua is a port of Mobile-Detect to Lua for NGINX HTTP servers. Follows closely to mobile-detect.js. Supports all methods that server-side mobile-detect.js supports. Fully unit-tested and synced with Travis CI (Build Passing badge included). Made by Mark Walters .
+
+
+
+
+ WordPress
+
+ WordPress Mobile Detect - Gives you the ability to wrap that infographic in a [notdevice][/notdevice]
shortcode so at the server level WordPress
will decide to show that content only if the user is NOT on a phone or tablet. Made by Jesse Friedman .
+
+ mobble - provides mobile related conditional functions for your site. e.g. is_iphone(), is_mobile() and is_tablet(). Made by Scott Evans.
+
+ WordPress Responsage - A small WordPress
theme plugin that allows you to make your images responsive. Made by Adrian Ciaschetti .
+
+ WP247 Body Classes - Add unique classes to the body
tag for easy styling based on various attributes (archive, user, post, mobile) and various WordPress "is" functions. Mobile attributes include type of device, Operating System, Browser, etc. Examples: .is-mobile, .is-not-mobile, .is-tablet, .is-ios, .is-not-ios, .is-androidos, .is-chromebrowser. Made by wescleveland56
+
+
+
+
+ Drupal
+
+ Drupal Mobile Switch - The Mobile Switch Drupal
module provides a automatic theme switch functionality for mobile devices,
+ detected by Browscap or Mobile Detect. Made by Siegfried Neumann .
+
+ Drupal Context Mobile Detect - This is a Drupal context
module which integrates Context and PHP Mobile Detect library.
+ Created by Artem Shymko .
+
+ Drupal Mobile Detect - Lightweight mobile detect module for Drupal
created by Matthew Donadio
+
+
+
+
+ Joomla
+
+ yagendoo Joomla! Mobile Detection Plugin - Lightweight PHP plugin for Joomla!
+ that detects a mobile browser using the Mobile Detect class. Made by yagendoo media .
+
+ User Agent Detector plugin by @ReneKreijveld. This system plugin detects the user agent of your
+ website visitor and sets a session variable accordingly. Based on the user agent, the plugin detects if the site is running on a desktop pc, tablet or smartphone.
+ It can also detect if the visitor is a spider bot (search engine). Session variable that is set: ualayout. Possible values: desktop, tablet, mobile, bot..
+
+
+
+
+ Magento
+ Magento - This Magento helper
from Optimise Web enables the use of all functions provided by MobileDetect.net.
+ Made by Kathir Vel .
+
+
+
+ PrestaShop
+ PrestaShop is a free, secure and open source shopping cart platform. Mobile_Detect is included in the default package since 1.5.x.
+
+
+
+ Zend Framework
+
+ ZF2 Mobile-Detect - Zend Framework 2 module that provides Mobile-Detect features (Mobile_Detect class as a service, helper for views and plugin controllers). Made by neilime
+
+ ZF2 MobileDetectModule - Facilitates integration of a PHP MobileDetect class with some ZF2-based application. Has similar idea like the existing ZF2 Mobile-Detect module, but differs in initialization and provision routine of the actual Mobile_Detect class. Appropriate view helper and controller plugin also have different conceptions. Made by Nikola Posa
+
+
+
+
+ Symfony
+ Symfony2 Mobile Detect Bundle - The bundle for detecting mobile devices, manage mobile view and redirect to the mobile and tablet version.
+ Made by Nikolay Ivlev .
+ Silex Mobile Detect Service Provider - Silex
service provider to interact with Mobile detect class methods. Made by Lhassan Baazzi .
+
+
+
+
+ Laravel
+
+ Agent a user agent class for Laravel, based on Mobile Detect with some additional functionality. Made by Jens Segers .
+ BrowserDetect is a browser & mobile detection package, collects and wrap together the best user-agent identifiers for Laravel. Created by Varga Zsolt .
+
+
+
+
+ Slim Framework
+
+ Slim_Mobile_Detect implements Mobile_Detect lib for differents response's write on Slim Framework App
+
+
+
+
+ ExpressionEngine
+ EE2 Detect Mobile - Lightweight PHP plugin for EE2
that detects a mobile browser using the Mobile Detect class. Made by Gareth Davies .
+
+
+
+ Yii Framework
+
+ Yii Extension - Mobile detect plugin for Yii framework.
+ Made by Alexey Salnikov .
+
+ Yii2 Device Detect - Yii2 extension for Mobile-Detect library. Made by Alexander Nestorov
+
+
+
+
+
+ CakePHP
+ CakePHP MobileDetect - plugin
component for CakePHP
2.x. Made by Gregory Gaskill
+
+
+
+ FuelPHP
+ Special Agent is a FuelPHP package which uses php-mobile-detect to determine whether a device is mobile or not.
+It overrides the Fuelphp Agent class its methods. Made by Robbie Bardjin .
+
+
+
+ TYPO3
+ px_mobiledetect is an extension that helps to detect visitor's mobile device class (if that’s tablet or mobile device like smartphone). Made by Alexander Tretyak.
+
+
+
+ PHP
+
+ PageCache is a lightweight PHP library for full page cache, with built-in Mobile-Detect support. Made by Muhammed Mamedov .
+
+
+
+
+ Statamic
+ Statamic CMS Mobile Detect - plugin
. Made by Sergei Filippov of Haiku Lab .
+
+
+
+ Kohana
+ Kohana Mobile Detect - an example of implementation of Mobile_Detect
class with Kohana framework. Written by Luiz Alberto S. Ribeiro .
+
+
+
+ Perl
+ MobileDetect.pm - Perl module
for Mobile Detect. Made by Sebastian Enger .
+
+
+
+ python
+ pymobiledetect - Mobile detect python package
. Made by Bas van Oostveen.
+
+
+
+ Ruby
+ mobile_detect.rb - A Ruby gem
using the JSON data exposed by the php project and implementing a basic subset of the API (as much as can be done by the exposed data). Made by Karthik T .
+
+
+
+ GoMobileDetect
+ GoMobileDetect - Go
port of Mobile Detect class. Made by Shaked .
+
+
+
+ LUA
+ ua-lua is a small lib written in LUA
providing device type detection. ua-lua is detecting mobile or tablet devices based on user-agent inside nginx daemon. Made by Frédéric Robinet .
+
+
+
+ MemHT
+ MemHT is a Free PHP CMS and Blog that permit the creation and the management online of websites with few and easy steps. Has the class included in the core.
+
+
+
+ concrete5
+ concrete5 is a CMS that is free and open source. The library is included in the core.
+
+
+
+ engine7
+ ExEngine 7 PHP Open Source Framework. The Mobile_Detect class is included in the engine.
+
+
+
+ Zikula
+ Zikula is a free and open-source Content Management Framework, which allows you to run impressive websites and build powerful online applications. The core uses Mobile-Detect to switch to a special Mobile theme, using jQueryMobile
+
+
+
+ UserAgentInfo
+ UserAgentInfo is a PHP class for parsing user agent strings (HTTP_USER_AGENT). Includes mobile checks, bot checks, browser types/versions and more.
+Based on browscap, Mobile_Detect and ua-parser. Created for high traffic websites and fast batch processing. Made by quentin389
+
+
+
+ Craft CMS
+ LJ Mobile Detect is a simple implementation of Mobile Detect for Craft CMS. Made by Lewis Jenkins
+
+
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/composer.json b/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/composer.json
new file mode 100644
index 0000000..c56611f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/composer.json
@@ -0,0 +1,30 @@
+{
+ "name": "mobiledetect/mobiledetectlib",
+ "type": "library",
+ "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.",
+ "keywords": ["mobile", "mobile detect", "mobile detector", "php mobile detect", "detect mobile devices"],
+ "homepage": "https://github.com/serbanghita/Mobile-Detect",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Serban Ghita",
+ "email": "serbanghita@gmail.com",
+ "homepage": "http://mobiledetect.net",
+ "role": "Developer"
+ }
+ ],
+ "require": {
+ "php": ">=5.0.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "*",
+ "johnkary/phpunit-speedtrap": "~1.0@dev",
+ "codeclimate/php-test-reporter": "dev-master"
+ },
+ "autoload": {
+ "classmap": ["Mobile_Detect.php"],
+ "psr-0": {
+ "Detection": "namespaced/"
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/namespaced/Detection/MobileDetect.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/namespaced/Detection/MobileDetect.php
new file mode 100644
index 0000000..ca7efec
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/Mobile_Detect/namespaced/Detection/MobileDetect.php
@@ -0,0 +1,22 @@
+
+
+ The PSR-2 coding standard.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/PHP-OAuth2/Client.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/PHP-OAuth2/Client.php
new file mode 100644
index 0000000..0b59cf6
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/PHP-OAuth2/Client.php
@@ -0,0 +1,513 @@
+
+ * @author Anis Berejeb
+ * @version 1.2-dev
+ */
+namespace OAuth2;
+
+class Client
+{
+ /**
+ * Different AUTH method
+ */
+ const AUTH_TYPE_URI = 0;
+ const AUTH_TYPE_AUTHORIZATION_BASIC = 1;
+ const AUTH_TYPE_FORM = 2;
+
+ /**
+ * Different Access token type
+ */
+ const ACCESS_TOKEN_URI = 0;
+ const ACCESS_TOKEN_BEARER = 1;
+ const ACCESS_TOKEN_OAUTH = 2;
+ const ACCESS_TOKEN_MAC = 3;
+
+ /**
+ * Different Grant types
+ */
+ const GRANT_TYPE_AUTH_CODE = 'authorization_code';
+ const GRANT_TYPE_PASSWORD = 'password';
+ const GRANT_TYPE_CLIENT_CREDENTIALS = 'client_credentials';
+ const GRANT_TYPE_REFRESH_TOKEN = 'refresh_token';
+
+ /**
+ * HTTP Methods
+ */
+ const HTTP_METHOD_GET = 'GET';
+ const HTTP_METHOD_POST = 'POST';
+ const HTTP_METHOD_PUT = 'PUT';
+ const HTTP_METHOD_DELETE = 'DELETE';
+ const HTTP_METHOD_HEAD = 'HEAD';
+
+ /**
+ * HTTP Form content types
+ */
+ const HTTP_FORM_CONTENT_TYPE_APPLICATION = 0;
+ const HTTP_FORM_CONTENT_TYPE_MULTIPART = 1;
+
+ /**
+ * Client ID
+ *
+ * @var string
+ */
+ protected $client_id = null;
+
+ /**
+ * Client Secret
+ *
+ * @var string
+ */
+ protected $client_secret = null;
+
+ /**
+ * Client Authentication method
+ *
+ * @var int
+ */
+ protected $client_auth = self::AUTH_TYPE_URI;
+
+ /**
+ * Access Token
+ *
+ * @var string
+ */
+ protected $access_token = null;
+
+ /**
+ * Access Token Type
+ *
+ * @var int
+ */
+ protected $access_token_type = self::ACCESS_TOKEN_URI;
+
+ /**
+ * Access Token Secret
+ *
+ * @var string
+ */
+ protected $access_token_secret = null;
+
+ /**
+ * Access Token crypt algorithm
+ *
+ * @var string
+ */
+ protected $access_token_algorithm = null;
+
+ /**
+ * Access Token Parameter name
+ *
+ * @var string
+ */
+ protected $access_token_param_name = 'access_token';
+
+ /**
+ * The path to the certificate file to use for https connections
+ *
+ * @var string Defaults to .
+ */
+ protected $certificate_file = null;
+
+ /**
+ * cURL options
+ *
+ * @var array
+ */
+ protected $curl_options = array();
+
+ /**
+ * Construct
+ *
+ * @param string $client_id Client ID
+ * @param string $client_secret Client Secret
+ * @param int $client_auth (AUTH_TYPE_URI, AUTH_TYPE_AUTHORIZATION_BASIC, AUTH_TYPE_FORM)
+ * @param string $certificate_file Indicates if we want to use a certificate file to trust the server. Optional, defaults to null.
+ * @return void
+ */
+ public function __construct($client_id, $client_secret, $client_auth = self::AUTH_TYPE_URI, $certificate_file = null)
+ {
+ if (!extension_loaded('curl')) {
+ throw new Exception('The PHP exention curl must be installed to use this library.', Exception::CURL_NOT_FOUND);
+ }
+
+ $this->client_id = $client_id;
+ $this->client_secret = $client_secret;
+ $this->client_auth = $client_auth;
+ $this->certificate_file = $certificate_file;
+ if (!empty($this->certificate_file) && !is_file($this->certificate_file)) {
+ throw new InvalidArgumentException('The certificate file was not found', InvalidArgumentException::CERTIFICATE_NOT_FOUND);
+ }
+ }
+
+ /**
+ * Get the client Id
+ *
+ * @return string Client ID
+ */
+ public function getClientId()
+ {
+ return $this->client_id;
+ }
+
+ /**
+ * Get the client Secret
+ *
+ * @return string Client Secret
+ */
+ public function getClientSecret()
+ {
+ return $this->client_secret;
+ }
+
+ /**
+ * getAuthenticationUrl
+ *
+ * @param string $auth_endpoint Url of the authentication endpoint
+ * @param string $redirect_uri Redirection URI
+ * @param array $extra_parameters Array of extra parameters like scope or state (Ex: array('scope' => null, 'state' => ''))
+ * @return string URL used for authentication
+ */
+ public function getAuthenticationUrl($auth_endpoint, $redirect_uri, array $extra_parameters = array())
+ {
+ $parameters = array_merge(array(
+ 'response_type' => 'code',
+ 'client_id' => $this->client_id,
+ 'redirect_uri' => $redirect_uri
+ ), $extra_parameters);
+ return $auth_endpoint . '?' . http_build_query($parameters, null, '&');
+ }
+
+ /**
+ * getAccessToken
+ *
+ * @param string $token_endpoint Url of the token endpoint
+ * @param int $grant_type Grant Type ('authorization_code', 'password', 'client_credentials', 'refresh_token', or a custom code (@see GrantType Classes)
+ * @param array $parameters Array sent to the server (depend on which grant type you're using)
+ * @return array Array of parameters required by the grant_type (CF SPEC)
+ */
+ public function getAccessToken($token_endpoint, $grant_type, array $parameters)
+ {
+ if (!$grant_type) {
+ throw new InvalidArgumentException('The grant_type is mandatory.', InvalidArgumentException::INVALID_GRANT_TYPE);
+ }
+ $grantTypeClassName = $this->convertToCamelCase($grant_type);
+ $grantTypeClass = __NAMESPACE__ . '\\GrantType\\' . $grantTypeClassName;
+ if (!class_exists($grantTypeClass)) {
+ throw new InvalidArgumentException('Unknown grant type \'' . $grant_type . '\'', InvalidArgumentException::INVALID_GRANT_TYPE);
+ }
+ $grantTypeObject = new $grantTypeClass();
+ $grantTypeObject->validateParameters($parameters);
+ if (!defined($grantTypeClass . '::GRANT_TYPE')) {
+ throw new Exception('Unknown constant GRANT_TYPE for class ' . $grantTypeClassName, Exception::GRANT_TYPE_ERROR);
+ }
+ $parameters['grant_type'] = $grantTypeClass::GRANT_TYPE;
+ $http_headers = array();
+ switch ($this->client_auth) {
+ case self::AUTH_TYPE_URI:
+ case self::AUTH_TYPE_FORM:
+ $parameters['client_id'] = $this->client_id;
+ $parameters['client_secret'] = $this->client_secret;
+ break;
+ case self::AUTH_TYPE_AUTHORIZATION_BASIC:
+ $parameters['client_id'] = $this->client_id;
+ $http_headers['Authorization'] = 'Basic ' . base64_encode($this->client_id . ':' . $this->client_secret);
+ break;
+ default:
+ throw new Exception('Unknown client auth type.', Exception::INVALID_CLIENT_AUTHENTICATION_TYPE);
+ break;
+ }
+
+ return $this->executeRequest($token_endpoint, $parameters, self::HTTP_METHOD_POST, $http_headers, self::HTTP_FORM_CONTENT_TYPE_APPLICATION);
+ }
+
+ /**
+ * setToken
+ *
+ * @param string $token Set the access token
+ * @return void
+ */
+ public function setAccessToken($token)
+ {
+ $this->access_token = $token;
+ }
+
+ /**
+ * Set the client authentication type
+ *
+ * @param string $client_auth (AUTH_TYPE_URI, AUTH_TYPE_AUTHORIZATION_BASIC, AUTH_TYPE_FORM)
+ * @return void
+ */
+ public function setClientAuthType($client_auth)
+ {
+ $this->client_auth = $client_auth;
+ }
+
+ /**
+ * Set an option for the curl transfer
+ *
+ * @param int $option The CURLOPT_XXX option to set
+ * @param mixed $value The value to be set on option
+ * @return void
+ */
+ public function setCurlOption($option, $value)
+ {
+ $this->curl_options[$option] = $value;
+ }
+
+ /**
+ * Set multiple options for a cURL transfer
+ *
+ * @param array $options An array specifying which options to set and their values
+ * @return void
+ */
+ public function setCurlOptions($options)
+ {
+ $this->curl_options = array_merge($this->curl_options, $options);
+ }
+
+ /**
+ * Set the access token type
+ *
+ * @param int $type Access token type (ACCESS_TOKEN_BEARER, ACCESS_TOKEN_MAC, ACCESS_TOKEN_URI)
+ * @param string $secret The secret key used to encrypt the MAC header
+ * @param string $algorithm Algorithm used to encrypt the signature
+ * @return void
+ */
+ public function setAccessTokenType($type, $secret = null, $algorithm = null)
+ {
+ $this->access_token_type = $type;
+ $this->access_token_secret = $secret;
+ $this->access_token_algorithm = $algorithm;
+ }
+
+ /**
+ * Fetch a protected ressource
+ *
+ * @param string $protected_ressource_url Protected resource URL
+ * @param array $parameters Array of parameters
+ * @param string $http_method HTTP Method to use (POST, PUT, GET, HEAD, DELETE)
+ * @param array $http_headers HTTP headers
+ * @param int $form_content_type HTTP form content type to use
+ * @return array
+ */
+ public function fetch($protected_resource_url, $parameters = array(), $http_method = self::HTTP_METHOD_GET, array $http_headers = array(), $form_content_type = self::HTTP_FORM_CONTENT_TYPE_MULTIPART)
+ {
+ if ($this->access_token) {
+ switch ($this->access_token_type) {
+ case self::ACCESS_TOKEN_URI:
+ if (is_array($parameters)) {
+ $parameters[$this->access_token_param_name] = $this->access_token;
+ } else {
+ throw new InvalidArgumentException(
+ 'You need to give parameters as array if you want to give the token within the URI.',
+ InvalidArgumentException::REQUIRE_PARAMS_AS_ARRAY
+ );
+ }
+ break;
+ case self::ACCESS_TOKEN_BEARER:
+ $http_headers['Authorization'] = 'Bearer ' . $this->access_token;
+ break;
+ case self::ACCESS_TOKEN_OAUTH:
+ $http_headers['Authorization'] = 'OAuth ' . $this->access_token;
+ break;
+ case self::ACCESS_TOKEN_MAC:
+ $http_headers['Authorization'] = 'MAC ' . $this->generateMACSignature($protected_resource_url, $parameters, $http_method);
+ break;
+ default:
+ throw new Exception('Unknown access token type.', Exception::INVALID_ACCESS_TOKEN_TYPE);
+ break;
+ }
+ }
+ return $this->executeRequest($protected_resource_url, $parameters, $http_method, $http_headers, $form_content_type);
+ }
+
+ /**
+ * Generate the MAC signature
+ *
+ * @param string $url Called URL
+ * @param array $parameters Parameters
+ * @param string $http_method Http Method
+ * @return string
+ */
+ private function generateMACSignature($url, $parameters, $http_method)
+ {
+ $timestamp = time();
+ $nonce = uniqid();
+ $parsed_url = parse_url($url);
+ if (!isset($parsed_url['port']))
+ {
+ $parsed_url['port'] = ($parsed_url['scheme'] == 'https') ? 443 : 80;
+ }
+ if ($http_method == self::HTTP_METHOD_GET) {
+ if (is_array($parameters)) {
+ $parsed_url['path'] .= '?' . http_build_query($parameters, null, '&');
+ } elseif ($parameters) {
+ $parsed_url['path'] .= '?' . $parameters;
+ }
+ }
+
+ $signature = base64_encode(hash_hmac($this->access_token_algorithm,
+ $timestamp . "\n"
+ . $nonce . "\n"
+ . $http_method . "\n"
+ . $parsed_url['path'] . "\n"
+ . $parsed_url['host'] . "\n"
+ . $parsed_url['port'] . "\n\n"
+ , $this->access_token_secret, true));
+
+ return 'id="' . $this->access_token . '", ts="' . $timestamp . '", nonce="' . $nonce . '", mac="' . $signature . '"';
+ }
+
+ /**
+ * Execute a request (with curl)
+ *
+ * @param string $url URL
+ * @param mixed $parameters Array of parameters
+ * @param string $http_method HTTP Method
+ * @param array $http_headers HTTP Headers
+ * @param int $form_content_type HTTP form content type to use
+ * @return array
+ */
+ private function executeRequest($url, $parameters = array(), $http_method = self::HTTP_METHOD_GET, array $http_headers = null, $form_content_type = self::HTTP_FORM_CONTENT_TYPE_MULTIPART)
+ {
+ $curl_options = array(
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_SSL_VERIFYPEER => true,
+ CURLOPT_CUSTOMREQUEST => $http_method
+ );
+
+ switch($http_method) {
+ case self::HTTP_METHOD_POST:
+ $curl_options[CURLOPT_POST] = true;
+ /* No break */
+ case self::HTTP_METHOD_PUT:
+
+ /**
+ * Passing an array to CURLOPT_POSTFIELDS will encode the data as multipart/form-data,
+ * while passing a URL-encoded string will encode the data as application/x-www-form-urlencoded.
+ * http://php.net/manual/en/function.curl-setopt.php
+ */
+ if(is_array($parameters) && self::HTTP_FORM_CONTENT_TYPE_APPLICATION === $form_content_type) {
+ $parameters = http_build_query($parameters, null, '&');
+ }
+ $curl_options[CURLOPT_POSTFIELDS] = $parameters;
+ break;
+ case self::HTTP_METHOD_HEAD:
+ $curl_options[CURLOPT_NOBODY] = true;
+ /* No break */
+ case self::HTTP_METHOD_DELETE:
+ case self::HTTP_METHOD_GET:
+ if (is_array($parameters)) {
+ $url .= '?' . http_build_query($parameters, null, '&');
+ } elseif ($parameters) {
+ $url .= '?' . $parameters;
+ }
+ break;
+ default:
+ break;
+ }
+
+ $curl_options[CURLOPT_URL] = $url;
+
+ if (is_array($http_headers)) {
+ $header = array();
+ foreach($http_headers as $key => $parsed_urlvalue) {
+ $header[] = "$key: $parsed_urlvalue";
+ }
+ $curl_options[CURLOPT_HTTPHEADER] = $header;
+ }
+
+ $ch = curl_init();
+ curl_setopt_array($ch, $curl_options);
+ // https handling
+ if (!empty($this->certificate_file)) {
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
+ curl_setopt($ch, CURLOPT_CAINFO, $this->certificate_file);
+ } else {
+ // bypass ssl verification
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
+ }
+ if (!empty($this->curl_options)) {
+ curl_setopt_array($ch, $this->curl_options);
+ }
+ $result = curl_exec($ch);
+ $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ $content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
+ if ($curl_error = curl_error($ch)) {
+ throw new Exception($curl_error, Exception::CURL_ERROR);
+ } else {
+ $json_decode = json_decode($result, true);
+ }
+ curl_close($ch);
+
+ return array(
+ 'result' => (null === $json_decode) ? $result : $json_decode,
+ 'code' => $http_code,
+ 'content_type' => $content_type
+ );
+ }
+
+ /**
+ * Set the name of the parameter that carry the access token
+ *
+ * @param string $name Token parameter name
+ * @return void
+ */
+ public function setAccessTokenParamName($name)
+ {
+ $this->access_token_param_name = $name;
+ }
+
+ /**
+ * Converts the class name to camel case
+ *
+ * @param mixed $grant_type the grant type
+ * @return string
+ */
+ private function convertToCamelCase($grant_type)
+ {
+ $parts = explode('_', $grant_type);
+ array_walk($parts, function(&$item) { $item = ucfirst($item);});
+ return implode('', $parts);
+ }
+}
+
+class Exception extends \Exception
+{
+ const CURL_NOT_FOUND = 0x01;
+ const CURL_ERROR = 0x02;
+ const GRANT_TYPE_ERROR = 0x03;
+ const INVALID_CLIENT_AUTHENTICATION_TYPE = 0x04;
+ const INVALID_ACCESS_TOKEN_TYPE = 0x05;
+}
+
+class InvalidArgumentException extends \InvalidArgumentException
+{
+ const INVALID_GRANT_TYPE = 0x01;
+ const CERTIFICATE_NOT_FOUND = 0x02;
+ const REQUIRE_PARAMS_AS_ARRAY = 0x03;
+ const MISSING_PARAMETER = 0x04;
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php
new file mode 100644
index 0000000..f3436e4
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php
@@ -0,0 +1,41 @@
+getAuthenticationUrl(AUTHORIZATION_ENDPOINT, REDIRECT_URI);
+ header('Location: ' . $auth_url);
+ die('Redirect');
+}
+else
+{
+ $params = array('code' => $_GET['code'], 'redirect_uri' => REDIRECT_URI);
+ $response = $client->getAccessToken(TOKEN_ENDPOINT, 'authorization_code', $params);
+ parse_str($response['result'], $info);
+ $client->setAccessToken($info['access_token']);
+ $response = $client->fetch('https://graph.facebook.com/me');
+ var_dump($response, $response['result']);
+}
+
+How can I add a new Grant Type ?
+================================
+Simply write a new class in the namespace OAuth2\GrantType. You can place the class file under GrantType.
+Here is an example :
+
+namespace OAuth2\GrantType;
+
+/**
+ * MyCustomGrantType Grant Type
+ */
+class MyCustomGrantType implements IGrantType
+{
+ /**
+ * Defines the Grant Type
+ *
+ * @var string Defaults to 'my_custom_grant_type'.
+ */
+ const GRANT_TYPE = 'my_custom_grant_type';
+
+ /**
+ * Adds a specific Handling of the parameters
+ *
+ * @return array of Specific parameters to be sent.
+ * @param mixed $parameters the parameters array (passed by reference)
+ */
+ public function validateParameters(&$parameters)
+ {
+ if (!isset($parameters['first_mandatory_parameter']))
+ {
+ throw new \Exception('The \'first_mandatory_parameter\' parameter must be defined for the Password grant type');
+ }
+ elseif (!isset($parameters['second_mandatory_parameter']))
+ {
+ throw new \Exception('The \'seconde_mandatory_parameter\' parameter must be defined for the Password grant type');
+ }
+ }
+}
+
+call the OAuth client getAccessToken with the grantType you defined in the GRANT_TYPE constant, As following :
+$response = $client->getAccessToken(TOKEN_ENDPOINT, 'my_custom_grant_type', $params);
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/PHPGangsta/GoogleAuthenticator.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/PHPGangsta/GoogleAuthenticator.php
new file mode 100644
index 0000000..5e70eed
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/PHPGangsta/GoogleAuthenticator.php
@@ -0,0 +1,201 @@
+_getBase32LookupTable();
+ unset($validChars[32]);
+
+ $secret = '';
+ for ($i = 0; $i < $secretLength; $i++) {
+ $secret .= $validChars[array_rand($validChars)];
+ }
+ return $secret;
+ }
+
+ /**
+ * Calculate the code, with given secret and point in time
+ *
+ * @param string $secret
+ * @param int|null $timeSlice
+ * @return string
+ */
+ public function getCode($secret, $timeSlice = null)
+ {
+ if ($timeSlice === null) {
+ $timeSlice = floor(time() / 30);
+ }
+
+ $secretkey = $this->_base32Decode($secret);
+
+ // Pack time into binary string
+ $time = chr(0).chr(0).chr(0).chr(0).pack('N*', $timeSlice);
+ // Hash it with users secret key
+ $hm = hash_hmac('SHA1', $time, $secretkey, true);
+ // Use last nipple of result as index/offset
+ $offset = ord(substr($hm, -1)) & 0x0F;
+ // grab 4 bytes of the result
+ $hashpart = substr($hm, $offset, 4);
+
+ // Unpak binary value
+ $value = unpack('N', $hashpart);
+ $value = $value[1];
+ // Only 32 bits
+ $value = $value & 0x7FFFFFFF;
+
+ $modulo = pow(10, $this->_codeLength);
+ return str_pad($value % $modulo, $this->_codeLength, '0', STR_PAD_LEFT);
+ }
+
+ /**
+ * Get QR-Code URL for image, from google charts
+ *
+ * @param string $name
+ * @param string $secret
+ * @return string
+ */
+ public function getQRCodeGoogleUrl($name, $secret) {
+ $urlencoded = urlencode('otpauth://totp/'.$name.'?secret='.$secret.'');
+ return 'https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl='.$urlencoded.'';
+ }
+
+ /**
+ * Check if the code is correct. This will accept codes starting from $discrepancy*30sec ago to $discrepancy*30sec from now
+ *
+ * @param string $secret
+ * @param string $code
+ * @param int $discrepancy This is the allowed time drift in 30 second units (8 means 4 minutes before or after)
+ * @return bool
+ */
+ public function verifyCode($secret, $code, $discrepancy = 1)
+ {
+ $currentTimeSlice = floor(time() / 30);
+
+ for ($i = -$discrepancy; $i <= $discrepancy; $i++) {
+ $calculatedCode = $this->getCode($secret, $currentTimeSlice + $i);
+ if ($calculatedCode == $code ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Set the code length, should be >=6
+ *
+ * @param int $length
+ * @return PHPGangsta_GoogleAuthenticator
+ */
+ public function setCodeLength($length)
+ {
+ $this->_codeLength = $length;
+ return $this;
+ }
+
+ /**
+ * Helper class to decode base32
+ *
+ * @param $secret
+ * @return bool|string
+ */
+ protected function _base32Decode($secret)
+ {
+ if (empty($secret)) return '';
+
+ $base32chars = $this->_getBase32LookupTable();
+ $base32charsFlipped = array_flip($base32chars);
+
+ $paddingCharCount = substr_count($secret, $base32chars[32]);
+ $allowedValues = array(6, 4, 3, 1, 0);
+ if (!in_array($paddingCharCount, $allowedValues)) return false;
+ for ($i = 0; $i < 4; $i++){
+ if ($paddingCharCount == $allowedValues[$i] &&
+ substr($secret, -($allowedValues[$i])) != str_repeat($base32chars[32], $allowedValues[$i])) return false;
+ }
+ $secret = str_replace('=','', $secret);
+ $secret = str_split($secret);
+ $binaryString = "";
+ for ($i = 0; $i < count($secret); $i = $i+8) {
+ $x = "";
+ if (!in_array($secret[$i], $base32chars)) return false;
+ for ($j = 0; $j < 8; $j++) {
+ $x .= str_pad(base_convert(@$base32charsFlipped[@$secret[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT);
+ }
+ $eightBits = str_split($x, 8);
+ for ($z = 0; $z < count($eightBits); $z++) {
+ $binaryString .= ( ($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48 ) ? $y:"";
+ }
+ }
+ return $binaryString;
+ }
+
+ /**
+ * Helper class to encode base32
+ *
+ * @param string $secret
+ * @param bool $padding
+ * @return string
+ */
+ protected function _base32Encode($secret, $padding = true)
+ {
+ if (empty($secret)) return '';
+
+ $base32chars = $this->_getBase32LookupTable();
+
+ $secret = str_split($secret);
+ $binaryString = "";
+ for ($i = 0; $i < count($secret); $i++) {
+ $binaryString .= str_pad(base_convert(ord($secret[$i]), 10, 2), 8, '0', STR_PAD_LEFT);
+ }
+ $fiveBitBinaryArray = str_split($binaryString, 5);
+ $base32 = "";
+ $i = 0;
+ while ($i < count($fiveBitBinaryArray)) {
+ $base32 .= $base32chars[base_convert(str_pad($fiveBitBinaryArray[$i], 5, '0'), 2, 10)];
+ $i++;
+ }
+ if ($padding && ($x = strlen($binaryString) % 40) != 0) {
+ if ($x == 8) $base32 .= str_repeat($base32chars[32], 6);
+ elseif ($x == 16) $base32 .= str_repeat($base32chars[32], 4);
+ elseif ($x == 24) $base32 .= str_repeat($base32chars[32], 3);
+ elseif ($x == 32) $base32 .= $base32chars[32];
+ }
+ return $base32;
+ }
+
+ /**
+ * Get array with all 32 characters for decoding from/encoding to base32
+ *
+ * @return array
+ */
+ protected function _getBase32LookupTable()
+ {
+ return array(
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23
+ 'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31
+ '=' // padding char
+ );
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/PHPThumb/GD.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/PHPThumb/GD.php
new file mode 100644
index 0000000..733fe47
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/PHPThumb/GD.php
@@ -0,0 +1,1417 @@
+
+ * Copyright (c) 2009, Ian Selby/Gen X Design
+ *
+ * Author(s): Ian Selby
+ *
+ * Licensed under the MIT License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author Ian Selby
+ * @copyright Copyright (c) 2009 Gen X Design
+ * @link http://phpthumb.gxdlabs.com
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+
+class GD extends PHPThumb
+{
+ /**
+ * The prior image (before manipulation)
+ *
+ * @var resource
+ */
+ protected $oldImage;
+
+ /**
+ * The working image (used during manipulation)
+ *
+ * @var resource
+ */
+ protected $workingImage;
+
+ /**
+ * The current dimensions of the image
+ *
+ * @var array
+ */
+ protected $currentDimensions;
+
+ /**
+ * The new, calculated dimensions of the image
+ *
+ * @var array
+ */
+ protected $newDimensions;
+
+ /**
+ * The options for this class
+ *
+ * This array contains various options that determine the behavior in
+ * various functions throughout the class. Functions note which specific
+ * option key / values are used in their documentation
+ *
+ * @var array
+ */
+ protected $options;
+
+ /**
+ * The maximum width an image can be after resizing (in pixels)
+ *
+ * @var int
+ */
+ protected $maxWidth;
+
+ /**
+ * The maximum height an image can be after resizing (in pixels)
+ *
+ * @var int
+ */
+ protected $maxHeight;
+
+ /**
+ * The percentage to resize the image by
+ *
+ * @var int
+ */
+ protected $percent;
+
+ /**
+ * @param string $fileName
+ * @param array $options
+ * @param array $plugins
+ */
+ public function __construct($fileName, $options = array(), array $plugins = array())
+ {
+ parent::__construct($fileName, $options, $plugins);
+
+ $this->determineFormat();
+ $this->verifyFormatCompatiblity();
+
+ switch ($this->format) {
+ case 'GIF':
+ $this->oldImage = @imagecreatefromgif($this->fileName);
+ break;
+ case 'JPG':
+ $this->oldImage = @imagecreatefromjpeg($this->fileName);
+ break;
+ case 'PNG':
+ $this->oldImage = @imagecreatefrompng($this->fileName);
+ break;
+ case 'STRING':
+ $this->oldImage = @imagecreatefromstring($this->fileName);
+ break;
+ }
+
+ if (!is_resource($this->oldImage))
+ {
+ throw new \Exception('Invalid image file');
+ }
+ else
+ {
+ $this->currentDimensions = array (
+ 'width' => imagesx($this->oldImage),
+ 'height' => imagesy($this->oldImage)
+ );
+ }
+ }
+
+ public function __destruct()
+ {
+ if (is_resource($this->oldImage)) {
+ imagedestroy($this->oldImage);
+ }
+
+ if (is_resource($this->workingImage)) {
+ imagedestroy($this->workingImage);
+ }
+ }
+
+ /**
+ * Pad an image to desired dimensions. Moves the image into the center and fills the rest with $color.
+ * @param $width
+ * @param $height
+ * @param array $color
+ * @return GD
+ */
+ public function pad($width, $height, $color = array(255, 255, 255))
+ {
+ // no resize - woohoo!
+ if ($width == $this->currentDimensions['width'] && $height == $this->currentDimensions['height']) {
+ return $this;
+ }
+
+ // create the working image
+ if (function_exists('imagecreatetruecolor')) {
+ $this->workingImage = imagecreatetruecolor($width, $height);
+ } else {
+ $this->workingImage = imagecreate($width, $height);
+ }
+
+ // create the fill color
+ $fillColor = imagecolorallocate(
+ $this->workingImage,
+ $color[0],
+ $color[1],
+ $color[2]
+ );
+
+ // fill our working image with the fill color
+ imagefill(
+ $this->workingImage,
+ 0,
+ 0,
+ $fillColor
+ );
+
+ // copy the image into the center of our working image
+ imagecopyresampled(
+ $this->workingImage,
+ $this->oldImage,
+ intval(($width-$this->currentDimensions['width']) / 2),
+ intval(($height-$this->currentDimensions['height']) / 2),
+ 0,
+ 0,
+ $this->currentDimensions['width'],
+ $this->currentDimensions['height'],
+ $this->currentDimensions['width'],
+ $this->currentDimensions['height']
+ );
+
+ // update all the variables and resources to be correct
+ $this->oldImage = $this->workingImage;
+ $this->currentDimensions['width'] = $width;
+ $this->currentDimensions['height'] = $height;
+
+ return $this;
+ }
+
+ /**
+ * Resizes an image to be no larger than $maxWidth or $maxHeight
+ *
+ * If either param is set to zero, then that dimension will not be considered as a part of the resize.
+ * Additionally, if $this->options['resizeUp'] is set to true (false by default), then this function will
+ * also scale the image up to the maximum dimensions provided.
+ *
+ * @param int $maxWidth The maximum width of the image in pixels
+ * @param int $maxHeight The maximum height of the image in pixels
+ * @return \PHPThumb\GD
+ */
+ public function resize($maxWidth = 0, $maxHeight = 0)
+ {
+ // make sure our arguments are valid
+ if (!is_numeric($maxWidth)) {
+ throw new \InvalidArgumentException('$maxWidth must be numeric');
+ }
+
+ if (!is_numeric($maxHeight)) {
+ throw new \InvalidArgumentException('$maxHeight must be numeric');
+ }
+
+ // make sure we're not exceeding our image size if we're not supposed to
+ if ($this->options['resizeUp'] === false) {
+ $this->maxHeight = (intval($maxHeight) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $maxHeight;
+ $this->maxWidth = (intval($maxWidth) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $maxWidth;
+ } else {
+ $this->maxHeight = intval($maxHeight);
+ $this->maxWidth = intval($maxWidth);
+ }
+
+ // get the new dimensions...
+ $this->calcImageSize($this->currentDimensions['width'], $this->currentDimensions['height']);
+
+ // create the working image
+ if (function_exists('imagecreatetruecolor')) {
+ $this->workingImage = imagecreatetruecolor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
+ } else {
+ $this->workingImage = imagecreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
+ }
+
+ $this->preserveAlpha();
+
+ // and create the newly sized image
+ imagecopyresampled(
+ $this->workingImage,
+ $this->oldImage,
+ 0,
+ 0,
+ 0,
+ 0,
+ $this->newDimensions['newWidth'],
+ $this->newDimensions['newHeight'],
+ $this->currentDimensions['width'],
+ $this->currentDimensions['height']
+ );
+
+ // update all the variables and resources to be correct
+ $this->oldImage = $this->workingImage;
+ $this->currentDimensions['width'] = $this->newDimensions['newWidth'];
+ $this->currentDimensions['height'] = $this->newDimensions['newHeight'];
+
+ return $this;
+ }
+
+ /**
+ * Adaptively Resizes the Image
+ *
+ * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the
+ * remaining overflow (from the center) to get the image to be the size specified
+ *
+ * @param int $maxWidth
+ * @param int $maxHeight
+ * @return \PHPThumb\GD
+ */
+ public function adaptiveResize($width, $height)
+ {
+ // make sure our arguments are valid
+ if ((!is_numeric($width) || $width == 0) && (!is_numeric($height) || $height == 0)) {
+ throw new \InvalidArgumentException('$width and $height must be numeric and greater than zero');
+ }
+
+ if (!is_numeric($width) || $width == 0) {
+ $width = ($height * $this->currentDimensions['width']) / $this->currentDimensions['height'];
+ }
+
+ if (!is_numeric($height) || $height == 0) {
+ $height = ($width * $this->currentDimensions['height']) / $this->currentDimensions['width'];
+ }
+
+ // make sure we're not exceeding our image size if we're not supposed to
+ if ($this->options['resizeUp'] === false) {
+ $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height;
+ $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width;
+ } else {
+ $this->maxHeight = intval($height);
+ $this->maxWidth = intval($width);
+ }
+
+ $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']);
+
+ // resize the image to be close to our desired dimensions
+ $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
+
+ // reset the max dimensions...
+ if ($this->options['resizeUp'] === false) {
+ $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height;
+ $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width;
+ } else {
+ $this->maxHeight = intval($height);
+ $this->maxWidth = intval($width);
+ }
+
+ // create the working image
+ if (function_exists('imagecreatetruecolor')) {
+ $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight);
+ } else {
+ $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight);
+ }
+
+ $this->preserveAlpha();
+
+ $cropWidth = $this->maxWidth;
+ $cropHeight = $this->maxHeight;
+ $cropX = 0;
+ $cropY = 0;
+
+ // now, figure out how to crop the rest of the image...
+ if ($this->currentDimensions['width'] > $this->maxWidth) {
+ $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth) / 2);
+ } elseif ($this->currentDimensions['height'] > $this->maxHeight) {
+ $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight) / 2);
+ }
+
+ imagecopyresampled(
+ $this->workingImage,
+ $this->oldImage,
+ 0,
+ 0,
+ $cropX,
+ $cropY,
+ $cropWidth,
+ $cropHeight,
+ $cropWidth,
+ $cropHeight
+ );
+
+ // update all the variables and resources to be correct
+ $this->oldImage = $this->workingImage;
+ $this->currentDimensions['width'] = $this->maxWidth;
+ $this->currentDimensions['height'] = $this->maxHeight;
+
+ return $this;
+ }
+
+ /**
+ * Adaptively Resizes the Image and Crops Using a Percentage
+ *
+ * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the
+ * remaining overflow using a provided percentage to get the image to be the size specified.
+ *
+ * The percentage mean different things depending on the orientation of the original image.
+ *
+ * For Landscape images:
+ * ---------------------
+ *
+ * A percentage of 1 would crop the image all the way to the left, which would be the same as
+ * using adaptiveResizeQuadrant() with $quadrant = 'L'
+ *
+ * A percentage of 50 would crop the image to the center which would be the same as using
+ * adaptiveResizeQuadrant() with $quadrant = 'C', or even the original adaptiveResize()
+ *
+ * A percentage of 100 would crop the image to the image all the way to the right, etc, etc.
+ * Note that you can use any percentage between 1 and 100.
+ *
+ * For Portrait images:
+ * --------------------
+ *
+ * This works the same as for Landscape images except that a percentage of 1 means top and 100 means bottom
+ *
+ * @param int $maxWidth
+ * @param int $maxHeight
+ * @param int $percent
+ * @return \PHPThumb\GD
+ */
+ public function adaptiveResizePercent($width, $height, $percent = 50)
+ {
+ // make sure our arguments are valid
+ if (!is_numeric($width) || $width == 0) {
+ throw new \InvalidArgumentException('$width must be numeric and greater than zero');
+ }
+
+ if (!is_numeric($height) || $height == 0) {
+ throw new \InvalidArgumentException('$height must be numeric and greater than zero');
+ }
+
+ // make sure we're not exceeding our image size if we're not supposed to
+ if ($this->options['resizeUp'] === false) {
+ $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height;
+ $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width;
+ } else {
+ $this->maxHeight = intval($height);
+ $this->maxWidth = intval($width);
+ }
+
+ $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']);
+
+ // resize the image to be close to our desired dimensions
+ $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
+
+ // reset the max dimensions...
+ if ($this->options['resizeUp'] === false) {
+ $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height;
+ $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width;
+ } else {
+ $this->maxHeight = intval($height);
+ $this->maxWidth = intval($width);
+ }
+
+ // create the working image
+ if (function_exists('imagecreatetruecolor')) {
+ $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight);
+ } else {
+ $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight);
+ }
+
+ $this->preserveAlpha();
+
+ $cropWidth = $this->maxWidth;
+ $cropHeight = $this->maxHeight;
+ $cropX = 0;
+ $cropY = 0;
+
+ // Crop the rest of the image using the quadrant
+
+ if ($percent > 100) {
+ $percent = 100;
+ } elseif ($percent < 1) {
+ $percent = 1;
+ }
+
+ if ($this->currentDimensions['width'] > $this->maxWidth) {
+ // Image is landscape
+ $maxCropX = $this->currentDimensions['width'] - $this->maxWidth;
+ $cropX = intval(($percent / 100) * $maxCropX);
+
+ } elseif ($this->currentDimensions['height'] > $this->maxHeight) {
+ // Image is portrait
+ $maxCropY = $this->currentDimensions['height'] - $this->maxHeight;
+ $cropY = intval(($percent / 100) * $maxCropY);
+ }
+
+ imagecopyresampled(
+ $this->workingImage,
+ $this->oldImage,
+ 0,
+ 0,
+ $cropX,
+ $cropY,
+ $cropWidth,
+ $cropHeight,
+ $cropWidth,
+ $cropHeight
+ );
+
+ // update all the variables and resources to be correct
+ $this->oldImage = $this->workingImage;
+ $this->currentDimensions['width'] = $this->maxWidth;
+ $this->currentDimensions['height'] = $this->maxHeight;
+
+ return $this;
+ }
+
+ /**
+ * Adaptively Resizes the Image and Crops Using a Quadrant
+ *
+ * This function attempts to get the image to as close to the provided dimensions as possible, and then crops the
+ * remaining overflow using the quadrant to get the image to be the size specified.
+ *
+ * The quadrants available are Top, Bottom, Center, Left, and Right:
+ *
+ *
+ * +---+---+---+
+ * | | T | |
+ * +---+---+---+
+ * | L | C | R |
+ * +---+---+---+
+ * | | B | |
+ * +---+---+---+
+ *
+ * Note that if your image is Landscape and you choose either of the Top or Bottom quadrants (which won't
+ * make sence since only the Left and Right would be available, then the Center quadrant will be used
+ * to crop. This would have exactly the same result as using adaptiveResize().
+ * The same goes if your image is portrait and you choose either the Left or Right quadrants.
+ *
+ * @param int $maxWidth
+ * @param int $maxHeight
+ * @param string $quadrant T, B, C, L, R
+ * @return \PHPThumb\GD
+ */
+ public function adaptiveResizeQuadrant($width, $height, $quadrant = 'C')
+ {
+ // make sure our arguments are valid
+ if (!is_numeric($width) || $width == 0) {
+ throw new \InvalidArgumentException('$width must be numeric and greater than zero');
+ }
+
+ if (!is_numeric($height) || $height == 0) {
+ throw new \InvalidArgumentException('$height must be numeric and greater than zero');
+ }
+
+ // make sure we're not exceeding our image size if we're not supposed to
+ if ($this->options['resizeUp'] === false) {
+ $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height;
+ $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width;
+ } else {
+ $this->maxHeight = intval($height);
+ $this->maxWidth = intval($width);
+ }
+
+ $this->calcImageSizeStrict($this->currentDimensions['width'], $this->currentDimensions['height']);
+
+ // resize the image to be close to our desired dimensions
+ $this->resize($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
+
+ // reset the max dimensions...
+ if ($this->options['resizeUp'] === false) {
+ $this->maxHeight = (intval($height) > $this->currentDimensions['height']) ? $this->currentDimensions['height'] : $height;
+ $this->maxWidth = (intval($width) > $this->currentDimensions['width']) ? $this->currentDimensions['width'] : $width;
+ } else {
+ $this->maxHeight = intval($height);
+ $this->maxWidth = intval($width);
+ }
+
+ // create the working image
+ if (function_exists('imagecreatetruecolor')) {
+ $this->workingImage = imagecreatetruecolor($this->maxWidth, $this->maxHeight);
+ } else {
+ $this->workingImage = imagecreate($this->maxWidth, $this->maxHeight);
+ }
+
+ $this->preserveAlpha();
+
+ $cropWidth = $this->maxWidth;
+ $cropHeight = $this->maxHeight;
+ $cropX = 0;
+ $cropY = 0;
+
+ // Crop the rest of the image using the quadrant
+
+ if ($this->currentDimensions['width'] > $this->maxWidth) {
+ // Image is landscape
+ switch ($quadrant) {
+ case 'L':
+ $cropX = 0;
+ break;
+ case 'R':
+ $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth));
+ break;
+ case 'C':
+ default:
+ $cropX = intval(($this->currentDimensions['width'] - $this->maxWidth) / 2);
+ break;
+ }
+ } elseif ($this->currentDimensions['height'] > $this->maxHeight) {
+ // Image is portrait
+ switch ($quadrant) {
+ case 'T':
+ $cropY = 0;
+ break;
+ case 'B':
+ $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight));
+ break;
+ case 'C':
+ default:
+ $cropY = intval(($this->currentDimensions['height'] - $this->maxHeight) / 2);
+ break;
+ }
+ }
+
+ imagecopyresampled(
+ $this->workingImage,
+ $this->oldImage,
+ 0,
+ 0,
+ $cropX,
+ $cropY,
+ $cropWidth,
+ $cropHeight,
+ $cropWidth,
+ $cropHeight
+ );
+
+ // update all the variables and resources to be correct
+ $this->oldImage = $this->workingImage;
+ $this->currentDimensions['width'] = $this->maxWidth;
+ $this->currentDimensions['height'] = $this->maxHeight;
+
+ return $this;
+ }
+
+ /**
+ * Resizes an image by a given percent uniformly,
+ * Percentage should be whole number representation (i.e. 1-100)
+ *
+ * @param int $percent
+ * @return GD
+ * @throws \InvalidArgumentException
+ */
+ public function resizePercent($percent = 0)
+ {
+ if (!is_numeric($percent)) {
+ throw new \InvalidArgumentException ('$percent must be numeric');
+ }
+
+ $this->percent = intval($percent);
+
+ $this->calcImageSizePercent($this->currentDimensions['width'], $this->currentDimensions['height']);
+
+ if (function_exists('imagecreatetruecolor')) {
+ $this->workingImage = imagecreatetruecolor($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
+ } else {
+ $this->workingImage = imagecreate($this->newDimensions['newWidth'], $this->newDimensions['newHeight']);
+ }
+
+ $this->preserveAlpha();
+
+ imagecopyresampled(
+ $this->workingImage,
+ $this->oldImage,
+ 0,
+ 0,
+ 0,
+ 0,
+ $this->newDimensions['newWidth'],
+ $this->newDimensions['newHeight'],
+ $this->currentDimensions['width'],
+ $this->currentDimensions['height']
+ );
+
+ $this->oldImage = $this->workingImage;
+ $this->currentDimensions['width'] = $this->newDimensions['newWidth'];
+ $this->currentDimensions['height'] = $this->newDimensions['newHeight'];
+
+ return $this;
+ }
+
+ /**
+ * Crops an image from the center with provided dimensions
+ *
+ * If no height is given, the width will be used as a height, thus creating a square crop
+ *
+ * @param int $cropWidth
+ * @param int $cropHeight
+ * @return \PHPThumb\GD
+ */
+ public function cropFromCenter($cropWidth, $cropHeight = null)
+ {
+ if (!is_numeric($cropWidth)) {
+ throw new \InvalidArgumentException('$cropWidth must be numeric');
+ }
+
+ if ($cropHeight !== null && !is_numeric($cropHeight)) {
+ throw new \InvalidArgumentException('$cropHeight must be numeric');
+ }
+
+ if ($cropHeight === null) {
+ $cropHeight = $cropWidth;
+ }
+
+ $cropWidth = ($this->currentDimensions['width'] < $cropWidth) ? $this->currentDimensions['width'] : $cropWidth;
+ $cropHeight = ($this->currentDimensions['height'] < $cropHeight) ? $this->currentDimensions['height'] : $cropHeight;
+
+ $cropX = intval(($this->currentDimensions['width'] - $cropWidth) / 2);
+ $cropY = intval(($this->currentDimensions['height'] - $cropHeight) / 2);
+
+ $this->crop($cropX, $cropY, $cropWidth, $cropHeight);
+
+ return $this;
+ }
+
+ /**
+ * Vanilla Cropping - Crops from x,y with specified width and height
+ *
+ * @param int $startX
+ * @param int $startY
+ * @param int $cropWidth
+ * @param int $cropHeight
+ * @return \PHPThumb\GD
+ */
+ public function crop($startX, $startY, $cropWidth, $cropHeight)
+ {
+ // validate input
+ if (!is_numeric($startX)) {
+ throw new \InvalidArgumentException('$startX must be numeric');
+ }
+
+ if (!is_numeric($startY)) {
+ throw new \InvalidArgumentException('$startY must be numeric');
+ }
+
+ if (!is_numeric($cropWidth)) {
+ throw new \InvalidArgumentException('$cropWidth must be numeric');
+ }
+
+ if (!is_numeric($cropHeight)) {
+ throw new \InvalidArgumentException('$cropHeight must be numeric');
+ }
+
+ // do some calculations
+ $cropWidth = ($this->currentDimensions['width'] < $cropWidth) ? $this->currentDimensions['width'] : $cropWidth;
+ $cropHeight = ($this->currentDimensions['height'] < $cropHeight) ? $this->currentDimensions['height'] : $cropHeight;
+
+ // ensure everything's in bounds
+ if (($startX + $cropWidth) > $this->currentDimensions['width']) {
+ $startX = ($this->currentDimensions['width'] - $cropWidth);
+ }
+
+ if (($startY + $cropHeight) > $this->currentDimensions['height']) {
+ $startY = ($this->currentDimensions['height'] - $cropHeight);
+ }
+
+ if ($startX < 0) {
+ $startX = 0;
+ }
+
+ if ($startY < 0) {
+ $startY = 0;
+ }
+
+ // create the working image
+ if (function_exists('imagecreatetruecolor')) {
+ $this->workingImage = imagecreatetruecolor($cropWidth, $cropHeight);
+ } else {
+ $this->workingImage = imagecreate($cropWidth, $cropHeight);
+ }
+
+ $this->preserveAlpha();
+
+ imagecopyresampled(
+ $this->workingImage,
+ $this->oldImage,
+ 0,
+ 0,
+ $startX,
+ $startY,
+ $cropWidth,
+ $cropHeight,
+ $cropWidth,
+ $cropHeight
+ );
+
+ $this->oldImage = $this->workingImage;
+ $this->currentDimensions['width'] = $cropWidth;
+ $this->currentDimensions['height'] = $cropHeight;
+
+ return $this;
+ }
+
+ /**
+ * Rotates image either 90 degrees clockwise or counter-clockwise
+ *
+ * @param string $direction
+ * @retunrn \PHPThumb\GD
+ */
+ public function rotateImage($direction = 'CW')
+ {
+ if ($direction == 'CW') {
+ $this->rotateImageNDegrees(90);
+ } else {
+ $this->rotateImageNDegrees(-90);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Rotates image specified number of degrees
+ *
+ * @param int $degrees
+ * @return \PHPThumb\GD
+ */
+ public function rotateImageNDegrees($degrees)
+ {
+ if (!is_numeric($degrees)) {
+ throw new \InvalidArgumentException('$degrees must be numeric');
+ }
+
+ if (!function_exists('imagerotate')) {
+ throw new \RuntimeException('Your version of GD does not support image rotation');
+ }
+
+ $this->workingImage = imagerotate($this->oldImage, $degrees, 0);
+
+ $newWidth = $this->currentDimensions['height'];
+ $newHeight = $this->currentDimensions['width'];
+ $this->oldImage = $this->workingImage;
+ $this->currentDimensions['width'] = $newWidth;
+ $this->currentDimensions['height'] = $newHeight;
+
+ return $this;
+ }
+
+ /**
+ * Applies a filter to the image
+ *
+ * @param int $filter
+ * @return \PHPThumb\GD
+ */
+ public function imageFilter($filter, $arg1 = false, $arg2 = false, $arg3 = false, $arg4 = false)
+ {
+ if (!is_numeric($filter)) {
+ throw new \InvalidArgumentException('$filter must be numeric');
+ }
+
+ if (!function_exists('imagefilter')) {
+ throw new \RuntimeException('Your version of GD does not support image filters');
+ }
+
+ $result = false;
+ if ($arg1 === false) {
+ $result = imagefilter($this->oldImage, $filter);
+ } elseif ($arg2 === false) {
+ $result = imagefilter($this->oldImage, $filter, $arg1);
+ } elseif ($arg3 === false) {
+ $result = imagefilter($this->oldImage, $filter, $arg1, $arg2);
+ } elseif ($arg4 === false) {
+ $result = imagefilter($this->oldImage, $filter, $arg1, $arg2, $arg3);
+ } else {
+ $result = imagefilter($this->oldImage, $filter, $arg1, $arg2, $arg3, $arg4);
+ }
+
+ if (!$result) {
+ throw new \RuntimeException('GD imagefilter failed');
+ }
+
+ $this->workingImage = $this->oldImage;
+
+ return $this;
+ }
+
+ /**
+ * Shows an image
+ *
+ * This function will show the current image by first sending the appropriate header
+ * for the format, and then outputting the image data. If headers have already been sent,
+ * a runtime exception will be thrown
+ *
+ * @param bool $rawData Whether or not the raw image stream should be output
+ * @return \PHPThumb\GD
+ */
+ public function show($rawData = false)
+ {
+ //Execute any plugins
+ if ($this->plugins) {
+ foreach ($this->plugins as $plugin) {
+ /* @var $plugin \PHPThumb\PluginInterface */
+ $plugin->execute($this);
+ }
+ }
+
+ if (headers_sent() && php_sapi_name() != 'cli') {
+ throw new \RuntimeException('Cannot show image, headers have already been sent');
+ }
+
+ // When the interlace option equals true or false call imageinterlace else leave it to default
+ if ($this->options['interlace'] === true) {
+ imageinterlace($this->oldImage, 1);
+ } elseif ($this->options['interlace'] === false) {
+ imageinterlace($this->oldImage, 0);
+ }
+
+ switch ($this->format) {
+ case 'GIF':
+ if ($rawData === false) {
+ header('Content-type: image/gif');
+ }
+ imagegif($this->oldImage);
+ break;
+ case 'JPG':
+ if ($rawData === false) {
+ header('Content-type: image/jpeg');
+ }
+ imagejpeg($this->oldImage, null, $this->options['jpegQuality']);
+ break;
+ case 'PNG':
+ case 'STRING':
+ if ($rawData === false) {
+ header('Content-type: image/png');
+ }
+ imagepng($this->oldImage);
+ break;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Returns the Working Image as a String
+ *
+ * This function is useful for getting the raw image data as a string for storage in
+ * a database, or other similar things.
+ *
+ * @return string
+ */
+ public function getImageAsString()
+ {
+ $data = null;
+ ob_start();
+ $this->show(true);
+ $data = ob_get_contents();
+ ob_end_clean();
+
+ return $data;
+ }
+
+ /**
+ * Saves an image
+ *
+ * This function will make sure the target directory is writeable, and then save the image.
+ *
+ * If the target directory is not writeable, the function will try to correct the permissions (if allowed, this
+ * is set as an option ($this->options['correctPermissions']). If the target cannot be made writeable, then a
+ * \RuntimeException is thrown.
+ *
+ * @param string $fileName The full path and filename of the image to save
+ * @param string $format The format to save the image in (optional, must be one of [GIF,JPG,PNG]
+ * @return \PHPThumb\GD
+ */
+ public function save($fileName, $format = null)
+ {
+ $validFormats = array('GIF', 'JPG', 'PNG');
+ $format = ($format !== null) ? strtoupper($format) : $this->format;
+
+ if (!in_array($format, $validFormats)) {
+ throw new \InvalidArgumentException("Invalid format type specified in save function: {$format}");
+ }
+
+ // make sure the directory is writeable
+ if (!is_writeable(dirname($fileName))) {
+ // try to correct the permissions
+ if ($this->options['correctPermissions'] === true) {
+ @chmod(dirname($fileName), 0777);
+
+ // throw an exception if not writeable
+ if (!is_writeable(dirname($fileName))) {
+ throw new \RuntimeException("File is not writeable, and could not correct permissions: {$fileName}");
+ }
+ } else { // throw an exception if not writeable
+ throw new \RuntimeException("File not writeable: {$fileName}");
+ }
+ }
+
+ // When the interlace option equals true or false call imageinterlace else leave it to default
+ if ($this->options['interlace'] === true) {
+ imageinterlace($this->oldImage, 1);
+ } elseif ($this->options['interlace'] === false) {
+ imageinterlace($this->oldImage, 0);
+ }
+
+ switch ($format) {
+ case 'GIF':
+ imagegif($this->oldImage, $fileName);
+ break;
+ case 'JPG':
+ imagejpeg($this->oldImage, $fileName, $this->options['jpegQuality']);
+ break;
+ case 'PNG':
+ imagepng($this->oldImage, $fileName);
+ break;
+ }
+
+ return $this;
+ }
+
+ #################################
+ # ----- GETTERS / SETTERS ----- #
+ #################################
+
+ /**
+ * Sets options for all operations.
+ * @param array $options
+ * @return GD
+ */
+ public function setOptions(array $options = array())
+ {
+ // we've yet to init the default options, so create them here
+ if (sizeof($this->options) == 0) {
+ $defaultOptions = array(
+ 'resizeUp' => false,
+ 'jpegQuality' => 100,
+ 'correctPermissions' => false,
+ 'preserveAlpha' => true,
+ 'alphaMaskColor' => array (255, 255, 255),
+ 'preserveTransparency' => true,
+ 'transparencyMaskColor' => array (0, 0, 0),
+ 'interlace' => null
+ );
+ } else { // otherwise, let's use what we've got already
+ $defaultOptions = $this->options;
+ }
+
+ $this->options = array_merge($defaultOptions, $options);
+
+ return $this;
+ }
+
+ /**
+ * Returns $currentDimensions.
+ *
+ * @see \PHPThumb\GD::$currentDimensions
+ */
+ public function getCurrentDimensions()
+ {
+ return $this->currentDimensions;
+ }
+
+ /**
+ * @param $currentDimensions
+ * @return GD
+ */
+ public function setCurrentDimensions($currentDimensions)
+ {
+ $this->currentDimensions = $currentDimensions;
+
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMaxHeight()
+ {
+ return $this->maxHeight;
+ }
+
+ /**
+ * @param $maxHeight
+ * @return GD
+ */
+ public function setMaxHeight($maxHeight)
+ {
+ $this->maxHeight = $maxHeight;
+
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMaxWidth()
+ {
+ return $this->maxWidth;
+ }
+
+ /**
+ * @param $maxWidth
+ * @return GD
+ */
+ public function setMaxWidth($maxWidth)
+ {
+ $this->maxWidth = $maxWidth;
+
+ return $this;
+ }
+
+ /**
+ * Returns $newDimensions.
+ *
+ * @see \PHPThumb\GD::$newDimensions
+ */
+ public function getNewDimensions()
+ {
+ return $this->newDimensions;
+ }
+
+ /**
+ * Sets $newDimensions.
+ *
+ * @param object $newDimensions
+ * @see \PHPThumb\GD::$newDimensions
+ */
+ public function setNewDimensions($newDimensions)
+ {
+ $this->newDimensions = $newDimensions;
+
+ return $this;
+ }
+
+ /**
+ * Returns $options.
+ *
+ * @see \PHPThumb\GD::$options
+ */
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+ /**
+ * Returns $percent.
+ *
+ * @see \PHPThumb\GD::$percent
+ */
+ public function getPercent()
+ {
+ return $this->percent;
+ }
+
+ /**
+ * Sets $percent.
+ *
+ * @param object $percent
+ * @see \PHPThumb\GD::$percent
+ */
+ public function setPercent($percent)
+ {
+ $this->percent = $percent;
+
+ return $this;
+ }
+
+ /**
+ * Returns $oldImage.
+ *
+ * @see \PHPThumb\GD::$oldImage
+ */
+ public function getOldImage()
+ {
+ return $this->oldImage;
+ }
+
+ /**
+ * Sets $oldImage.
+ *
+ * @param object $oldImage
+ * @see \PHPThumb\GD::$oldImage
+ */
+ public function setOldImage($oldImage)
+ {
+ $this->oldImage = $oldImage;
+
+ return $this;
+ }
+
+ /**
+ * Returns $workingImage.
+ *
+ * @see \PHPThumb\GD::$workingImage
+ */
+ public function getWorkingImage()
+ {
+ return $this->workingImage;
+ }
+
+ /**
+ * Sets $workingImage.
+ *
+ * @param object $workingImage
+ * @see \PHPThumb\GD::$workingImage
+ */
+ public function setWorkingImage($workingImage)
+ {
+ $this->workingImage = $workingImage;
+
+ return $this;
+ }
+
+
+ #################################
+ # ----- UTILITY FUNCTIONS ----- #
+ #################################
+
+ /**
+ * Calculates a new width and height for the image based on $this->maxWidth and the provided dimensions
+ *
+ * @return array
+ * @param int $width
+ * @param int $height
+ */
+ protected function calcWidth($width, $height)
+ {
+ $newWidthPercentage = (100 * $this->maxWidth) / $width;
+ $newHeight = ($height * $newWidthPercentage) / 100;
+
+ return array(
+ 'newWidth' => intval($this->maxWidth),
+ 'newHeight' => intval($newHeight)
+ );
+ }
+
+ /**
+ * Calculates a new width and height for the image based on $this->maxWidth and the provided dimensions
+ *
+ * @return array
+ * @param int $width
+ * @param int $height
+ */
+ protected function calcHeight($width, $height)
+ {
+ $newHeightPercentage = (100 * $this->maxHeight) / $height;
+ $newWidth = ($width * $newHeightPercentage) / 100;
+
+ return array(
+ 'newWidth' => ceil($newWidth),
+ 'newHeight' => ceil($this->maxHeight)
+ );
+ }
+
+ /**
+ * Calculates a new width and height for the image based on $this->percent and the provided dimensions
+ *
+ * @return array
+ * @param int $width
+ * @param int $height
+ */
+ protected function calcPercent($width, $height)
+ {
+ $newWidth = ($width * $this->percent) / 100;
+ $newHeight = ($height * $this->percent) / 100;
+
+ return array(
+ 'newWidth' => ceil($newWidth),
+ 'newHeight' => ceil($newHeight)
+ );
+ }
+
+ /**
+ * Calculates the new image dimensions
+ *
+ * These calculations are based on both the provided dimensions and $this->maxWidth and $this->maxHeight
+ *
+ * @param int $width
+ * @param int $height
+ */
+ protected function calcImageSize($width, $height)
+ {
+ $newSize = array(
+ 'newWidth' => $width,
+ 'newHeight' => $height
+ );
+
+ if ($this->maxWidth > 0) {
+ $newSize = $this->calcWidth($width, $height);
+
+ if ($this->maxHeight > 0 && $newSize['newHeight'] > $this->maxHeight) {
+ $newSize = $this->calcHeight($newSize['newWidth'], $newSize['newHeight']);
+ }
+ }
+
+ if ($this->maxHeight > 0) {
+ $newSize = $this->calcHeight($width, $height);
+
+ if ($this->maxWidth > 0 && $newSize['newWidth'] > $this->maxWidth) {
+ $newSize = $this->calcWidth($newSize['newWidth'], $newSize['newHeight']);
+ }
+ }
+
+ $this->newDimensions = $newSize;
+ }
+
+ /**
+ * Calculates new image dimensions, not allowing the width and height to be less than either the max width or height
+ *
+ * @param int $width
+ * @param int $height
+ */
+ protected function calcImageSizeStrict($width, $height)
+ {
+ // first, we need to determine what the longest resize dimension is..
+ if ($this->maxWidth >= $this->maxHeight) {
+ // and determine the longest original dimension
+ if ($width > $height) {
+ $newDimensions = $this->calcHeight($width, $height);
+
+ if ($newDimensions['newWidth'] < $this->maxWidth) {
+ $newDimensions = $this->calcWidth($width, $height);
+ }
+ } elseif ($height >= $width) {
+ $newDimensions = $this->calcWidth($width, $height);
+
+ if ($newDimensions['newHeight'] < $this->maxHeight) {
+ $newDimensions = $this->calcHeight($width, $height);
+ }
+ }
+ } elseif ($this->maxHeight > $this->maxWidth) {
+ if ($width >= $height) {
+ $newDimensions = $this->calcWidth($width, $height);
+
+ if ($newDimensions['newHeight'] < $this->maxHeight) {
+ $newDimensions = $this->calcHeight($width, $height);
+ }
+ } elseif ($height > $width) {
+ $newDimensions = $this->calcHeight($width, $height);
+
+ if ($newDimensions['newWidth'] < $this->maxWidth) {
+ $newDimensions = $this->calcWidth($width, $height);
+ }
+ }
+ }
+
+ $this->newDimensions = $newDimensions;
+ }
+
+ /**
+ * Calculates new dimensions based on $this->percent and the provided dimensions
+ *
+ * @param int $width
+ * @param int $height
+ */
+ protected function calcImageSizePercent($width, $height)
+ {
+ if ($this->percent > 0) {
+ $this->newDimensions = $this->calcPercent($width, $height);
+ }
+ }
+
+ /**
+ * Determines the file format by mime-type
+ *
+ * This function will throw exceptions for invalid images / mime-types
+ *
+ */
+ protected function determineFormat()
+ {
+ $formatInfo = getimagesize($this->fileName);
+
+ // non-image files will return false
+ if ($formatInfo === false) {
+ if ($this->remoteImage) {
+ throw new \Exception("Could not determine format of remote image: {$this->fileName}");
+ } else {
+ throw new \Exception("File is not a valid image: {$this->fileName}");
+ }
+ }
+
+ $mimeType = isset($formatInfo['mime']) ? $formatInfo['mime'] : null;
+
+ switch ($mimeType) {
+ case 'image/gif':
+ $this->format = 'GIF';
+ break;
+ case 'image/jpeg':
+ $this->format = 'JPG';
+ break;
+ case 'image/png':
+ $this->format = 'PNG';
+ break;
+ default:
+ throw new \Exception("Image format not supported: {$mimeType}");
+ }
+ }
+
+ /**
+ * Makes sure the correct GD implementation exists for the file type
+ *
+ */
+ protected function verifyFormatCompatiblity()
+ {
+ $isCompatible = true;
+ $gdInfo = gd_info();
+
+ switch ($this->format) {
+ case 'GIF':
+ $isCompatible = isset($gdInfo['GIF Create Support']);
+ break;
+ case 'JPG':
+ $isCompatible = (isset($gdInfo['JPG Support']) || isset($gdInfo['JPEG Support'])) ? true : false;
+ break;
+ case 'PNG':
+ $isCompatible = isset($gdInfo[$this->format . ' Support']);
+ break;
+ default:
+ $isCompatible = false;
+ }
+
+ if (!$isCompatible) {
+ // one last check for "JPEG" instead
+ $isCompatible = isset($gdInfo['JPEG Support']);
+
+ if (!$isCompatible) {
+ throw new \Exception("Your GD installation does not support {$this->format} image types");
+ }
+ }
+ }
+
+ /**
+ * Preserves the alpha or transparency for PNG and GIF files
+ *
+ * Alpha / transparency will not be preserved if the appropriate options are set to false.
+ * Also, the GIF transparency is pretty skunky (the results aren't awesome), but it works like a
+ * champ... that's the nature of GIFs tho, so no huge surprise.
+ *
+ * This functionality was originally suggested by commenter Aimi (no links / site provided) - Thanks! :)
+ *
+ */
+ protected function preserveAlpha()
+ {
+ if ($this->format == 'PNG' && $this->options['preserveAlpha'] === true) {
+ imagealphablending($this->workingImage, false);
+
+ $colorTransparent = imagecolorallocatealpha(
+ $this->workingImage,
+ $this->options['alphaMaskColor'][0],
+ $this->options['alphaMaskColor'][1],
+ $this->options['alphaMaskColor'][2],
+ 0
+ );
+
+ imagefill($this->workingImage, 0, 0, $colorTransparent);
+ imagesavealpha($this->workingImage, true);
+ }
+ // preserve transparency in GIFs... this is usually pretty rough tho
+ if ($this->format == 'GIF' && $this->options['preserveTransparency'] === true) {
+ $colorTransparent = imagecolorallocate(
+ $this->workingImage,
+ $this->options['transparencyMaskColor'][0],
+ $this->options['transparencyMaskColor'][1],
+ $this->options['transparencyMaskColor'][2]
+ );
+
+ imagecolortransparent($this->workingImage, $colorTransparent);
+ imagetruecolortopalette($this->workingImage, true, 256);
+ }
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/PHPThumb/PHPThumb.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/PHPThumb/PHPThumb.php
new file mode 100644
index 0000000..a86c8c9
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/PHPThumb/PHPThumb.php
@@ -0,0 +1,143 @@
+
+ * Copyright (c) 2009, Ian Selby/Gen X Design
+ *
+ * Author(s): Ian Selby
+ *
+ * Licensed under the MIT License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author Ian Selby
+ * @copyright Copyright (c) 2009 Gen X Design
+ * @link http://phpthumb.gxdlabs.com
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+
+abstract class PHPThumb
+{
+ /**
+ * The name of the file we're manipulating
+ * This must include the path to the file (absolute paths recommended)
+ *
+ * @var string
+ */
+ protected $fileName;
+
+ /**
+ * What the file format is (mime-type)
+ *
+ * @var string
+ */
+ protected $format;
+
+ /**
+ * Whether or not the image is hosted remotely
+ *
+ * @var bool
+ */
+ protected $remoteImage;
+
+ /**
+ * An array of attached plugins to execute in order.
+ * @var array
+ */
+ protected $plugins;
+
+ /**
+ * @param $fileName
+ * @param array $options
+ * @param array $plugins
+ */
+ public function __construct($fileName, array $options = array(), array $plugins = array())
+ {
+ $this->fileName = $fileName;
+ $this->remoteImage = false;
+
+ if(!$this->validateRequestedResource($fileName)) {
+ throw new \InvalidArgumentException("Image file not found: {$fileName}");
+ }
+
+ $this->setOptions($options);
+
+ $this->plugins = $plugins;
+ }
+
+ abstract public function setOptions(array $options = array());
+
+ /**
+ * Check the provided filename/url. If it is a url, validate that it is properly
+ * formatted. If it is a file, check to make sure that it actually exists on
+ * the filesystem.
+ *
+ * @param $filename
+ * @return bool
+ */
+ protected function validateRequestedResource($filename)
+ {
+ if(false !== filter_var($filename, FILTER_VALIDATE_URL)) {
+ $this->remoteImage = true;
+ return true;
+ }
+
+ if (file_exists($filename)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the filename.
+ * @return string
+ */
+ public function getFileName()
+ {
+ return $this->fileName;
+ }
+
+ /**
+ * Sets the filename.
+ * @param $fileName
+ * @return PHPThumb
+ */
+ public function setFileName($fileName)
+ {
+ $this->fileName = $fileName;
+
+ return $this;
+ }
+
+ /**
+ * Returns the format.
+ * @return string
+ */
+ public function getFormat()
+ {
+ return $this->format;
+ }
+
+ /**
+ * Sets the format.
+ * @param $format
+ * @return PHPThumb
+ */
+ public function setFormat($format)
+ {
+ $this->format = $format;
+
+ return $this;
+ }
+
+ /**
+ * Returns whether the image exists remotely, i.e. it was loaded via a URL.
+ * @return bool
+ */
+ public function getIsRemoteImage()
+ {
+ return $this->remoteImage;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/PHPThumb/PluginInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/PHPThumb/PluginInterface.php
new file mode 100644
index 0000000..56df976
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/PHPThumb/PluginInterface.php
@@ -0,0 +1,12 @@
+
+ * Copyright (c) 2009, Ian Selby/Gen X Design
+ *
+ * Author(s): Ian Selby
+ *
+ * Licensed under the MIT License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author Ian Selby
+ * @copyright Copyright (c) 2009 Gen X Design
+ * @link http://phpthumb.gxdlabs.com
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ * @version 3.0
+ * @package PhpThumb
+ * @filesource
+ */
+
+/**
+ * GD Reflection Lib Plugin
+ *
+ * This plugin allows you to create those fun Apple(tm)-style reflections in your images
+ *
+ * @package PhpThumb
+ * @subpackage Plugins
+ */
+class Reflection implements \PHPThumb\PluginInterface
+{
+ protected $currentDimensions;
+ protected $workingImage;
+ protected $newImage;
+ protected $options;
+
+ protected $percent;
+ protected $reflection;
+ protected $white;
+ protected $border;
+ protected $borderColor;
+
+ public function __construct($percent, $reflection, $white, $border, $borderColor)
+ {
+ $this->percent = $percent;
+ $this->reflection = $reflection;
+ $this->white = $white;
+ $this->border = $border;
+ $this->borderColor = $borderColor;
+ }
+
+ /**
+ * @param \PHPThumb\PHPThumb $phpthumb
+ * @return \PHPThumb\PHPThumb
+ */
+ public function execute($phpthumb)
+ {
+ $this->currentDimensions = $phpthumb->getCurrentDimensions();
+ $this->workingImage = $phpthumb->getWorkingImage();
+ $this->newImage = $phpthumb->getOldImage();
+ $this->options = $phpthumb->getOptions();
+
+ $width = $this->currentDimensions['width'];
+ $height = $this->currentDimensions['height'];
+ $this->reflectionHeight = intval($height * ($this->reflection / 100));
+ $newHeight = $height + $this->reflectionHeight;
+ $reflectedPart = $height * ($this->percent / 100);
+
+ $this->workingImage = imagecreatetruecolor($width, $newHeight);
+
+ imagealphablending($this->workingImage, true);
+
+ $colorToPaint = imagecolorallocatealpha(
+ $this->workingImage,
+ 255,
+ 255,
+ 255,
+ 0
+ );
+
+ imagefilledrectangle(
+ $this->workingImage,
+ 0,
+ 0,
+ $width,
+ $newHeight,
+ $colorToPaint
+ );
+
+ imagecopyresampled(
+ $this->workingImage,
+ $this->newImage,
+ 0,
+ 0,
+ 0,
+ $reflectedPart,
+ $width,
+ $this->reflectionHeight,
+ $width,
+ ($height - $reflectedPart)
+ );
+
+ $this->imageFlipVertical();
+
+ imagecopy(
+ $this->workingImage,
+ $this->newImage,
+ 0,
+ 0,
+ 0,
+ 0,
+ $width,
+ $height
+ );
+
+ imagealphablending($this->workingImage, true);
+
+ for ($i = 0; $i < $this->reflectionHeight; $i++) {
+ $colorToPaint = imagecolorallocatealpha(
+ $this->workingImage,
+ 255,
+ 255,
+ 255,
+ ($i / $this->reflectionHeight * -1 + 1) * $this->white
+ );
+
+ imagefilledrectangle(
+ $this->workingImage,
+ 0,
+ $height + $i,
+ $width,
+ $height + $i,
+ $colorToPaint
+ );
+ }
+
+ if ($this->border == true) {
+ $rgb = $this->hex2rgb($this->borderColor, false);
+ $colorToPaint = imagecolorallocate($this->workingImage, $rgb[0], $rgb[1], $rgb[2]);
+
+ //top line
+ imageline(
+ $this->workingImage,
+ 0,
+ 0,
+ $width,
+ 0,
+ $colorToPaint
+ );
+
+ //bottom line
+ imageline(
+ $this->workingImage,
+ 0,
+ $height,
+ $width,
+ $height,
+ $colorToPaint
+ );
+
+ //left line
+ imageline(
+ $this->workingImage,
+ 0,
+ 0,
+ 0,
+ $height,
+ $colorToPaint
+ );
+
+ //right line
+ imageline(
+ $this->workingImage,
+ $width - 1,
+ 0,
+ $width - 1,
+ $height,
+ $colorToPaint
+ );
+ }
+
+ if ($phpthumb->getFormat() == 'PNG') {
+ $colorTransparent = imagecolorallocatealpha(
+ $this->workingImage,
+ $this->options['alphaMaskColor'][0],
+ $this->options['alphaMaskColor'][1],
+ $this->options['alphaMaskColor'][2],
+ 0
+ );
+
+ imagefill($this->workingImage, 0, 0, $colorTransparent);
+ imagesavealpha($this->workingImage, true);
+ }
+
+ $phpthumb->setOldImage($this->workingImage);
+ $this->currentDimensions['width'] = $width;
+ $this->currentDimensions['height'] = $newHeight;
+ $phpthumb->setCurrentDimensions($this->currentDimensions);
+
+ return $phpthumb;
+ }
+
+ /**
+ * Flips the image vertically
+ *
+ */
+ protected function imageFlipVertical ()
+ {
+ $x_i = imagesx($this->workingImage);
+ $y_i = imagesy($this->workingImage);
+
+ for ($x = 0; $x < $x_i; $x++) {
+ for ($y = 0; $y < $y_i; $y++) {
+ imagecopy(
+ $this->workingImage,
+ $this->workingImage,
+ $x,
+ $y_i - $y - 1,
+ $x,
+ $y,
+ 1,
+ 1
+ );
+ }
+ }
+ }
+
+ /**
+ * Converts a hex color to rgb tuples
+ *
+ * @return mixed
+ * @param string $hex
+ * @param bool $asString
+ */
+ protected function hex2rgb ($hex, $asString = false)
+ {
+ // strip off any leading #
+ if (0 === strpos($hex, '#')) {
+ $hex = substr($hex, 1);
+ } elseif (0 === strpos($hex, '&H')) {
+ $hex = substr($hex, 2);
+ }
+
+ // break into hex 3-tuple
+ $cutpoint = ceil(strlen($hex) / 2)-1;
+ $rgb = explode(':', wordwrap($hex, $cutpoint, ':', $cutpoint), 3);
+
+ // convert each tuple to decimal
+ $rgb[0] = (isset($rgb[0]) ? hexdec($rgb[0]) : 0);
+ $rgb[1] = (isset($rgb[1]) ? hexdec($rgb[1]) : 0);
+ $rgb[2] = (isset($rgb[2]) ? hexdec($rgb[2]) : 0);
+
+ return ($asString ? "{$rgb[0]} {$rgb[1]} {$rgb[2]}" : $rgb);
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/RainLoop/Actions.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/RainLoop/Actions.php
new file mode 100644
index 0000000..b7db06c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/RainLoop/Actions.php
@@ -0,0 +1,10196 @@
+aCurrentActionParams = array();
+
+ $this->oHttp = null;
+ $this->oLogger = null;
+ $this->oPlugins = null;
+ $this->oMailClient = null;
+ $this->oSocial = null;
+ $this->oConfig = null;
+ $this->aCachers = array();
+
+ $this->oStorageProvider = null;
+ $this->oLocalStorageProvider = null;
+ $this->oSettingsProvider = null;
+ $this->oLocalSettingsProvider = null;
+ $this->oFilesProvider = null;
+ $this->oFiltersProvider = null;
+ $this->oDomainProvider = null;
+ $this->oAddressBookProvider = null;
+ $this->oSuggestionsProvider = null;
+ $this->oChangePasswordProvider = null;
+ $this->oTwoFactorAuthProvider = null;
+ $this->oPremProvider = null;
+
+ $this->sSpecAuthToken = '';
+
+ $oConfig = $this->Config();
+ $this->Plugins()->RunHook('filter.application-config', array(&$oConfig));
+
+ $this->Logger()->Ping();
+ }
+
+ /**
+ * @return \RainLoop\Actions
+ */
+ public static function NewInstance()
+ {
+ return new self();
+ }
+
+ /**
+ * @param string $sSpecAuthToken
+ *
+ * @return \RainLoop\Application
+ */
+ public function SetSpecAuthToken($sSpecAuthToken)
+ {
+ $this->sSpecAuthToken = $sSpecAuthToken;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetSpecAuthToken()
+ {
+ return $this->sSpecAuthToken;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetShortLifeSpecAuthToken($iLife = 60)
+ {
+ $aAccountHash = \RainLoop\Utils::DecodeKeyValues($this->getLocalAuthToken());
+ if (!empty($aAccountHash[0]) && 'token' === $aAccountHash[0] && \is_array($aAccountHash))
+ {
+ $aAccountHash[10] = \time() + $iLife;
+ return \RainLoop\Utils::EncodeKeyValues($aAccountHash);
+ }
+
+ return '';
+ }
+
+ /**
+ * @return \RainLoop\Application
+ */
+ public function Config()
+ {
+ if (null === $this->oConfig)
+ {
+ $this->oConfig = new \RainLoop\Config\Application();
+
+// $bSave = defined('APP_INSTALLED_START');
+// if (!$this->oConfig->Load())
+// {
+// $bSave = true;
+// }
+// else if (!$bSave)
+// {
+// $bSave = APP_VERSION !== $this->oConfig->Get('version', 'current');
+// }
+
+ $bSave = defined('APP_INSTALLED_START');
+
+ $bLoaded = $this->oConfig->Load();
+ if (!$bLoaded && !$bSave)
+ {
+ usleep(10000); // TODO
+ $bLoaded = $this->oConfig->Load();
+ }
+
+ if (!$bLoaded && !$this->oConfig->IsFileExists())
+ {
+ $bSave = true;
+ }
+
+ if ($bLoaded && !$bSave)
+ {
+ $bSave = APP_VERSION !== $this->oConfig->Get('version', 'current');
+ }
+
+ if ($bSave)
+ {
+ $this->oConfig->Save();
+ }
+ }
+
+ return $this->oConfig;
+ }
+
+ /**
+ * @param string $sName
+ * @param \RainLoop\Model\Account $oAccount = null
+ *
+ * @return mixed
+ */
+ private function fabrica($sName, $oAccount = null)
+ {
+ $mResult = null;
+ $this->Plugins()
+ ->RunHook('main.fabrica', array($sName, &$mResult), false)
+ ->RunHook('main.fabrica[2]', array($sName, &$mResult, $oAccount), false)
+ ;
+
+ if (null === $mResult)
+ {
+ switch ($sName)
+ {
+ case 'files':
+ // RainLoop\Providers\Files\IFiles
+ $mResult = new \RainLoop\Providers\Files\FileStorage(APP_PRIVATE_DATA.'storage/files');
+ break;
+ case 'storage':
+ case 'storage-local':
+ // RainLoop\Providers\Storage\IStorage
+ $mResult = new \RainLoop\Providers\Storage\FileStorage(
+ APP_PRIVATE_DATA.'storage', 'storage-local' === $sName);
+ break;
+ case 'settings':
+ case 'settings-local':
+ // RainLoop\Providers\Settings\ISettings
+ $mResult = new \RainLoop\Providers\Settings\DefaultSettings(
+ $this->StorageProvider('settings-local' === $sName));
+ break;
+ case 'login':
+ // \RainLoop\Providers\Login\LoginInterface
+ $mResult = new \RainLoop\Providers\Login\DefaultLogin();
+ break;
+ case 'domain':
+ // \RainLoop\Providers\Domain\DomainAdminInterface
+ $mResult = new \RainLoop\Providers\Domain\DefaultDomain(APP_PRIVATE_DATA.'domains', $this->Cacher());
+ break;
+ case 'filters':
+ // \RainLoop\Providers\Filters\FiltersInterface
+ $mResult = new \RainLoop\Providers\Filters\SieveStorage(
+ $this->Plugins(), $this->Config()
+ );
+ break;
+ case 'address-book':
+ // \RainLoop\Providers\AddressBook\AddressBookInterface
+
+ $sDsn = \trim($this->Config()->Get('contacts', 'pdo_dsn', ''));
+ $sUser = \trim($this->Config()->Get('contacts', 'pdo_user', ''));
+ $sPassword = (string) $this->Config()->Get('contacts', 'pdo_password', '');
+
+ $sDsnType = $this->ValidateContactPdoType(\trim($this->Config()->Get('contacts', 'type', 'sqlite')));
+ if ('sqlite' === $sDsnType)
+ {
+ $mResult = new \RainLoop\Providers\AddressBook\PdoAddressBook(
+ 'sqlite:'.APP_PRIVATE_DATA.'AddressBook.sqlite', '', '', 'sqlite');
+ }
+ else
+ {
+ $mResult = new \RainLoop\Providers\AddressBook\PdoAddressBook($sDsn, $sUser, $sPassword, $sDsnType);
+ }
+ break;
+ case 'suggestions':
+
+ if (null === $mResult)
+ {
+ $mResult = array();
+ }
+
+ if (\is_array($mResult) && \RainLoop\Utils::IsOwnCloud())
+ {
+ // \RainLoop\Providers\Suggestions\ISuggestions
+ $mResult[] = new \RainLoop\Providers\Suggestions\OwnCloudSuggestions();
+ }
+
+ break;
+ case 'change-password':
+ // \RainLoop\Providers\ChangePassword\ChangePasswordInterface
+ break;
+ case 'two-factor-auth':
+ // \RainLoop\Providers\TwoFactorAuth\TwoFactorAuthInterface
+ $mResult = new \RainLoop\Providers\TwoFactorAuth\GoogleTwoFactorAuth();
+ break;
+ }
+ }
+
+ foreach (\is_array($mResult) ? $mResult : array($mResult) as $oItem)
+ {
+ if ($oItem && \method_exists($oItem, 'SetLogger'))
+ {
+ $oItem->SetLogger($this->Logger());
+ }
+ }
+
+ $this->Plugins()->RunHook('filter.fabrica', array($sName, &$mResult, $oAccount), false);
+
+ return $mResult;
+ }
+
+ /**
+ * @return void
+ */
+ public function BootStart()
+ {
+ if (defined('APP_INSTALLED_START') && defined('APP_INSTALLED_VERSION') &&
+ APP_INSTALLED_START && !APP_INSTALLED_VERSION)
+ {
+ try
+ {
+ $this->KeenIO('Install');
+ }
+ catch (\Exception $oException) { unset($oException); }
+ }
+ }
+
+ /**
+ * @return void
+ */
+ public function BootEnd()
+ {
+ try
+ {
+ if ($this->MailClient()->IsLoggined())
+ {
+ $this->MailClient()->LogoutAndDisconnect();
+ }
+ }
+ catch (\Exception $oException) { unset($oException); }
+ }
+
+ /**
+ * @return string
+ */
+ public function ParseQueryAuthString()
+ {
+ $sQuery = \trim($this->Http()->GetQueryString());
+
+ $iPos = \strpos($sQuery, '&');
+ if (0 < $iPos)
+ {
+ $sQuery = \substr($sQuery, 0, $iPos);
+ }
+
+ $sQuery = \trim(\trim($sQuery), ' /');
+
+ $aSubQuery = $this->Http()->GetQuery('q', null);
+ if (\is_array($aSubQuery))
+ {
+ $aSubQuery = \array_map(function ($sS) {
+ return \trim(\trim($sS), ' /');
+ }, $aSubQuery);
+
+ if (0 < \count($aSubQuery))
+ {
+ $sQuery .= '/'.\implode('/', $aSubQuery);
+ }
+ }
+
+ if ('' === $this->GetSpecAuthToken())
+ {
+ $aPaths = \explode('/', $sQuery);
+ if (!empty($aPaths[0]) && !empty($aPaths[1]) && '_' === substr($aPaths[1], 0, 1))
+ {
+ $this->SetSpecAuthToken($aPaths[1]);
+ }
+ }
+
+ return $sQuery;
+ }
+
+ /**
+ * @param string $sLine
+ * @param \RainLoop\Model\Account $oAccount = null
+ * @param bool $bUrlEncode = false
+ *
+ * @return string
+ */
+ private function compileLogParams($sLine, $oAccount = null, $bUrlEncode = false)
+ {
+ if (false !== \strpos($sLine, '{date:'))
+ {
+ $iTimeOffset = (int) $this->Config()->Get('logs', 'time_offset', 0);
+ $sLine = \preg_replace_callback('/\{date:([^}]+)\}/', function ($aMatch) use ($iTimeOffset, $bUrlEncode) {
+ return \RainLoop\Utils::UrlEncode(\MailSo\Log\Logger::DateHelper($aMatch[1], $iTimeOffset), $bUrlEncode);
+ }, $sLine);
+
+ $sLine = \preg_replace('/\{date:([^}]*)\}/', 'date', $sLine);
+ }
+
+ if (false !== \strpos($sLine, '{imap:') || false !== \strpos($sLine, '{smtp:'))
+ {
+ if (!$oAccount)
+ {
+ $this->ParseQueryAuthString();
+ $oAccount = $this->getAccountFromToken(false);
+ }
+
+ if ($oAccount)
+ {
+ $sLine = \str_replace('{imap:login}', \RainLoop\Utils::UrlEncode($oAccount->IncLogin(), $bUrlEncode), $sLine);
+ $sLine = \str_replace('{imap:host}', \RainLoop\Utils::UrlEncode($oAccount->DomainIncHost(), $bUrlEncode), $sLine);
+ $sLine = \str_replace('{imap:port}', \RainLoop\Utils::UrlEncode($oAccount->DomainIncPort(), $bUrlEncode), $sLine);
+
+ $sLine = \str_replace('{smtp:login}', \RainLoop\Utils::UrlEncode($oAccount->OutLogin(), $bUrlEncode), $sLine);
+ $sLine = \str_replace('{smtp:host}', \RainLoop\Utils::UrlEncode($oAccount->DomainOutHost(), $bUrlEncode), $sLine);
+ $sLine = \str_replace('{smtp:port}', \RainLoop\Utils::UrlEncode($oAccount->DomainOutPort(), $bUrlEncode), $sLine);
+ }
+
+ $sLine = \preg_replace('/\{imap:([^}]*)\}/i', 'imap', $sLine);
+ $sLine = \preg_replace('/\{smtp:([^}]*)\}/i', 'smtp', $sLine);
+ }
+
+ if (false !== \strpos($sLine, '{request:'))
+ {
+ if (false !== \strpos($sLine, '{request:ip}'))
+ {
+ $sLine = \str_replace('{request:ip}', \RainLoop\Utils::UrlEncode($this->Http()->GetClientIp(
+ $this->Config()->Get('labs', 'http_client_ip_check_proxy', false)), $bUrlEncode), $sLine);
+ }
+
+ if (false !== \strpos($sLine, '{request:domain}'))
+ {
+ $sLine = \str_replace('{request:domain}',
+ \RainLoop\Utils::UrlEncode($this->Http()->GetHost(false, true, true), $bUrlEncode), $sLine);
+ }
+
+ if (false !== \strpos($sLine, '{request:domain-clear}'))
+ {
+ $sLine = \str_replace('{request:domain-clear}',
+ \RainLoop\Utils::UrlEncode(
+ \MailSo\Base\Utils::GetClearDomainName($this->Http()->GetHost(false, true, true)), $bUrlEncode), $sLine);
+ }
+
+ $sLine = \preg_replace('/\{request:([^}]*)\}/i', 'request', $sLine);
+ }
+
+ if (false !== \strpos($sLine, '{user:'))
+ {
+ if (false !== \strpos($sLine, '{user:uid}'))
+ {
+ $sLine = \str_replace('{user:uid}',
+ \RainLoop\Utils::UrlEncode(\base_convert(\sprintf('%u',
+ \crc32(\md5(\RainLoop\Utils::GetConnectionToken()))), 10, 32), $bUrlEncode),
+ $sLine
+ );
+ }
+
+ if (false !== \strpos($sLine, '{user:ip}'))
+ {
+ $sLine = \str_replace('{user:ip}', \RainLoop\Utils::UrlEncode($this->Http()->GetClientIp(
+ $this->Config()->Get('labs', 'http_client_ip_check_proxy', false)), $bUrlEncode), $sLine);
+ }
+
+ if (\preg_match('/\{user:(email|login|domain)\}/i', $sLine))
+ {
+ if (!$oAccount)
+ {
+ $this->ParseQueryAuthString();
+ $oAccount = $this->getAccountFromToken(false);
+ }
+
+ if ($oAccount)
+ {
+ $sEmail = $oAccount->Email();
+
+ $sLine = \str_replace('{user:email}', \RainLoop\Utils::UrlEncode($sEmail, $bUrlEncode), $sLine);
+ $sLine = \str_replace('{user:login}', \RainLoop\Utils::UrlEncode(
+ \MailSo\Base\Utils::GetAccountNameFromEmail($sEmail), $bUrlEncode), $sLine);
+ $sLine = \str_replace('{user:domain}', \RainLoop\Utils::UrlEncode(
+ \MailSo\Base\Utils::GetDomainFromEmail($sEmail), $bUrlEncode), $sLine);
+ $sLine = \str_replace('{user:domain-clear}', \RainLoop\Utils::UrlEncode(
+ \MailSo\Base\Utils::GetClearDomainName(
+ \MailSo\Base\Utils::GetDomainFromEmail($sEmail)), $bUrlEncode), $sLine);
+ }
+ }
+
+ $sLine = \preg_replace('/\{user:([^}]*)\}/i', 'unknown', $sLine);
+ }
+
+ if (false !== \strpos($sLine, '{labs:'))
+ {
+ $sLine = \preg_replace_callback('/\{labs:rand:([1-9])\}/', function ($aMatch) {
+ return \rand(\pow(10, $aMatch[1] - 1), \pow(10, $aMatch[1]) - 1);
+ }, $sLine);
+
+ $sLine = \preg_replace('/\{labs:([^}]*)\}/', 'labs', $sLine);
+ }
+
+ return $sLine;
+ }
+
+ /**
+ * @param string $sFileName
+ *
+ * @return string
+ */
+ private function compileLogFileName($sFileName)
+ {
+ $sFileName = \trim($sFileName);
+
+ if (0 !== \strlen($sFileName))
+ {
+ $sFileName = $this->compileLogParams($sFileName);
+
+ $sFileName = \preg_replace('/[\/]+/', '/', \preg_replace('/[.]+/', '.', $sFileName));
+ $sFileName = \preg_replace('/[^a-zA-Z0-9@_+=\-\.\/!()\[\]]/', '', $sFileName);
+ }
+
+ if (0 === \strlen($sFileName))
+ {
+ $sFileName = 'rainloop-log.txt';
+ }
+
+ return $sFileName;
+ }
+
+ /**
+ * @return void
+ */
+ public function SetAuthLogoutToken()
+ {
+ @\header('X-RainLoop-Action: Logout');
+ \RainLoop\Utils::SetCookie(self::AUTH_SPEC_LOGOUT_TOKEN_KEY, \md5(APP_START_TIME), 0);
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ *
+ * @return void
+ */
+ public function SetAuthToken($oAccount)
+ {
+ if ($oAccount)
+ {
+ $sSpecAuthToken = '_'.$oAccount->GetAuthTokenQ();
+
+ $this->SetSpecAuthToken($sSpecAuthToken);
+ \RainLoop\Utils::SetCookie(self::AUTH_SPEC_TOKEN_KEY, $sSpecAuthToken, 0);
+
+ if ($oAccount->SignMe() && 0 < \strlen($oAccount->SignMeToken()))
+ {
+ \RainLoop\Utils::SetCookie(self::AUTH_SIGN_ME_TOKEN_KEY,
+ \RainLoop\Utils::EncodeKeyValuesQ(array(
+ 'e' => $oAccount->Email(),
+ 't' => $oAccount->SignMeToken()
+ )),
+ \time() + 60 * 60 * 24 * 30);
+
+ $this->StorageProvider()->Put($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'sign_me',
+ \RainLoop\Utils::EncodeKeyValuesQ(array(
+ 'Time' => \time(),
+ 'AuthToken' => $oAccount->GetAuthTokenQ(),
+ 'SignMetToken' => $oAccount->SignMeToken()
+ ))
+ );
+ }
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function GetSpecAuthTokenWithDeletion()
+ {
+ $sResult = \RainLoop\Utils::GetCookie(self::AUTH_SPEC_TOKEN_KEY, '');
+ if (0 < strlen($sResult))
+ {
+ \RainLoop\Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY);
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetSpecAuthLogoutTokenWithDeletion()
+ {
+ $sResult = \RainLoop\Utils::GetCookie(self::AUTH_SPEC_LOGOUT_TOKEN_KEY, '');
+ if (0 < strlen($sResult))
+ {
+ \RainLoop\Utils::ClearCookie(self::AUTH_SPEC_LOGOUT_TOKEN_KEY);
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function GetSpecLogoutCustomMgsWithDeletion()
+ {
+ $sResult = \RainLoop\Utils::GetCookie(self::AUTH_SPEC_LOGOUT_CUSTOM_MSG_KEY, '');
+ if (0 < strlen($sResult))
+ {
+ \RainLoop\Utils::ClearCookie(self::AUTH_SPEC_LOGOUT_CUSTOM_MSG_KEY);
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function SetSpecLogoutCustomMgsWithDeletion($sMessage)
+ {
+ \RainLoop\Utils::SetCookie(self::AUTH_SPEC_LOGOUT_CUSTOM_MSG_KEY, $sMessage, 0);
+ }
+
+ /**
+ * @return void
+ */
+ private function setAdminAuthToken($sToken)
+ {
+ \RainLoop\Utils::SetCookie(self::AUTH_ADMIN_TOKEN_KEY, $sToken, 0);
+ }
+
+ /**
+ * @return string
+ */
+ private function getLocalAuthToken()
+ {
+ $sToken = $this->GetSpecAuthToken();
+ return !empty($sToken) && '_' === \substr($sToken, 0, 1) ? \substr($sToken, 1) : '';
+ }
+
+ /**
+ * @return string
+ */
+ private function getAdminAuthToken()
+ {
+ return \RainLoop\Utils::GetCookie(self::AUTH_ADMIN_TOKEN_KEY, '');
+ }
+
+ /**
+ * @return void
+ */
+ public function ClearAdminAuthToken()
+ {
+ $aAdminHash = \RainLoop\Utils::DecodeKeyValuesQ($this->getAdminAuthToken());
+ if (
+ !empty($aAdminHash[0]) && !empty($aAdminHash[1]) && !empty($aAdminHash[2]) &&
+ 'token' === $aAdminHash[0] && \md5(APP_SALT) === $aAdminHash[1]
+ )
+ {
+ $this->Cacher(null, true)->Delete(\RainLoop\KeyPathHelper::SessionAdminKey($aAdminHash[2]));
+ }
+
+ \RainLoop\Utils::ClearCookie(self::AUTH_ADMIN_TOKEN_KEY);
+ }
+
+ /**
+ * @param bool $bThrowExceptionOnFalse = false
+ *
+ * @return \RainLoop\Model\Account|bool
+ * @throws \RainLoop\Exceptions\ClientException
+ */
+ public function GetAccount($bThrowExceptionOnFalse = false)
+ {
+ return $this->getAccountFromToken($bThrowExceptionOnFalse);
+ }
+
+ /**
+ * @return \MailSo\Base\Http
+ */
+ public function Http()
+ {
+ if (null === $this->oHttp)
+ {
+ $this->oHttp = \MailSo\Base\Http::SingletonInstance();
+ }
+
+ return $this->oHttp;
+ }
+
+ /**
+ * @return \RainLoop\Social
+ */
+ public function Social()
+ {
+ if (null === $this->oSocial)
+ {
+ $this->oSocial = new \RainLoop\Social($this->Http(), $this);
+ }
+
+ return $this->oSocial;
+ }
+
+ /**
+ * @return \MailSo\Mail\MailClient
+ */
+ public function MailClient()
+ {
+ if (null === $this->oMailClient)
+ {
+ $this->oMailClient = \MailSo\Mail\MailClient::NewInstance();
+ $this->oMailClient->SetLogger($this->Logger());
+ }
+
+ return $this->oMailClient;
+ }
+
+ /**
+ * @return \RainLoop\Providers\Filters
+ */
+ public function FiltersProvider()
+ {
+ if (null === $this->oFiltersProvider)
+ {
+ $this->oFiltersProvider = new \RainLoop\Providers\Filters(
+ $this->fabrica('filters'));
+ }
+
+ return $this->oFiltersProvider;
+ }
+
+ /**
+ * @return \RainLoop\Providers\ChangePassword
+ */
+ public function ChangePasswordProvider()
+ {
+ if (null === $this->oChangePasswordProvider)
+ {
+ $this->oChangePasswordProvider = new \RainLoop\Providers\ChangePassword(
+ $this, $this->fabrica('change-password'), !!$this->Config()->Get('labs', 'check_new_password_strength', true)
+ );
+ }
+
+ return $this->oChangePasswordProvider;
+ }
+
+ /**
+ * @return \RainLoop\Providers\TwoFactorAuth
+ */
+ public function TwoFactorAuthProvider()
+ {
+ if (null === $this->oTwoFactorAuthProvider)
+ {
+ $this->oTwoFactorAuthProvider = new \RainLoop\Providers\TwoFactorAuth(
+ $this->Config()->Get('security', 'allow_two_factor_auth', false) ? $this->fabrica('two-factor-auth') : null
+ );
+ }
+
+ return $this->oTwoFactorAuthProvider;
+ }
+
+ /**
+ * @return \RainLoop\Providers\Prem
+ */
+ public function PremProvider()
+ {
+ if (null === $this->oPremProvider)
+ {
+ if (\file_exists(APP_VERSION_ROOT_PATH.'app/libraries/RainLoop/Prem/Provider.php'))
+ {
+ $this->oPremProvider = new \RainLoop\Prem\Provider(
+ $this->Config(), $this->Logger(), $this->Cacher(null, true)
+ );
+ }
+ else
+ {
+ $this->oPremProvider = false;
+ }
+ }
+
+ return $this->oPremProvider;
+ }
+
+ /**
+ * @param bool $bLocal = false
+ *
+ * @return \RainLoop\Providers\Storage
+ */
+ public function StorageProvider($bLocal = false)
+ {
+ if ($bLocal)
+ {
+ if (null === $this->oLocalStorageProvider)
+ {
+ $this->oLocalStorageProvider = new \RainLoop\Providers\Storage(
+ $this->fabrica('storage-local'));
+ }
+
+ return $this->oLocalStorageProvider;
+ }
+ else
+ {
+ if (null === $this->oStorageProvider)
+ {
+ $this->oStorageProvider = new \RainLoop\Providers\Storage(
+ $this->fabrica('storage'));
+ }
+
+ return $this->oStorageProvider;
+ }
+
+ return null;
+ }
+
+ /**
+ * @return \RainLoop\Providers\Settings
+ */
+ public function SettingsProvider($bLocal = false)
+ {
+ if ($bLocal)
+ {
+ if (null === $this->oLocalSettingsProvider)
+ {
+ $this->oLocalSettingsProvider = new \RainLoop\Providers\Settings(
+ $this->fabrica('settings-local'));
+ }
+
+ return $this->oLocalSettingsProvider;
+ }
+ else
+ {
+ if (null === $this->oSettingsProvider)
+ {
+ $this->oSettingsProvider = new \RainLoop\Providers\Settings(
+ $this->fabrica('settings'));
+ }
+
+ return $this->oSettingsProvider;
+ }
+
+ return null;
+ }
+
+ /**
+ * @return \RainLoop\Providers\Files
+ */
+ public function FilesProvider()
+ {
+ if (null === $this->oFilesProvider)
+ {
+ $this->oFilesProvider = new \RainLoop\Providers\Files(
+ $this->fabrica('files'));
+ }
+
+ return $this->oFilesProvider;
+ }
+
+ /**
+ * @return \RainLoop\Providers\Domain
+ */
+ public function DomainProvider()
+ {
+ if (null === $this->oDomainProvider)
+ {
+ $this->oDomainProvider = new \RainLoop\Providers\Domain(
+ $this->fabrica('domain'), $this->Plugins());
+ }
+
+ return $this->oDomainProvider;
+ }
+
+ /**
+ * @return \RainLoop\Providers\Suggestions
+ */
+ public function SuggestionsProvider()
+ {
+ if (null === $this->oSuggestionsProvider)
+ {
+ $this->oSuggestionsProvider = new \RainLoop\Providers\Suggestions(
+ $this->fabrica('suggestions'));
+ }
+
+ return $this->oSuggestionsProvider;
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount = null
+ * @param bool $bForceEnable = false
+ *
+ * @return \RainLoop\Providers\AddressBook
+ */
+ public function AddressBookProvider($oAccount = null, $bForceEnable = false)
+ {
+ if (null === $this->oAddressBookProvider)
+ {
+ $oDriver = null;
+ if ($this->GetCapa(false, false, \RainLoop\Enumerations\Capa::CONTACTS, $oAccount))
+ {
+ if ($this->Config()->Get('contacts', 'enable', false) || $bForceEnable)
+ {
+ $oDriver = $this->fabrica('address-book', $oAccount);
+ }
+ }
+
+ $this->oAddressBookProvider = new \RainLoop\Providers\AddressBook($oDriver);
+ $this->oAddressBookProvider->SetLogger($this->Logger());
+ }
+
+ return $this->oAddressBookProvider;
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount = null
+ * @param bool $bForceFile = false
+ *
+ * @return \MailSo\Cache\CacheClient
+ */
+ public function Cacher($oAccount = null, $bForceFile = false)
+ {
+ $sKey = '';
+ if ($oAccount)
+ {
+ $sKey = $oAccount->ParentEmailHelper();
+ }
+
+ $sIndexKey = empty($sKey) ? '_default_' : $sKey;
+ if ($bForceFile)
+ {
+ $sIndexKey .= '/_files_';
+ }
+
+ if (!isset($this->aCachers[$sIndexKey]))
+ {
+ $this->aCachers[$sIndexKey] = \MailSo\Cache\CacheClient::NewInstance();
+
+ $oDriver = null;
+ $sDriver = \strtoupper(\trim($this->Config()->Get('cache', 'fast_cache_driver', 'files')));
+
+ switch (true)
+ {
+ default:
+ case $bForceFile:
+ $oDriver = \MailSo\Cache\Drivers\File::NewInstance(APP_PRIVATE_DATA.'cache', $sKey);
+ break;
+
+ case ('APC' === $sDriver || 'APCU' === $sDriver) &&
+ \MailSo\Base\Utils::FunctionExistsAndEnabled(array(
+ 'apc_store', 'apc_fetch', 'apc_delete', 'apc_clear_cache')):
+
+ $oDriver = \MailSo\Cache\Drivers\APC::NewInstance($sKey);
+ break;
+
+ case ('MEMCACHE' === $sDriver || 'MEMCACHED' === $sDriver) &&
+ \MailSo\Base\Utils::FunctionExistsAndEnabled('memcache_connect'):
+
+ $oDriver = \MailSo\Cache\Drivers\Memcache::NewInstance(
+ $this->Config()->Get('labs', 'fast_cache_memcache_host', '127.0.0.1'),
+ (int) $this->Config()->Get('labs', 'fast_cache_memcache_port', 11211),
+ 43200, $sKey
+ );
+ break;
+ }
+
+ if ($oDriver)
+ {
+ $this->aCachers[$sIndexKey]->SetDriver($oDriver);
+ }
+
+ $this->aCachers[$sIndexKey]->SetCacheIndex($this->Config()->Get('cache', 'fast_cache_index', ''));
+ }
+
+ return $this->aCachers[$sIndexKey];
+ }
+
+ /**
+ * @return \RainLoop\Plugins\Manager
+ */
+ public function Plugins()
+ {
+ if (null === $this->oPlugins)
+ {
+ $this->oPlugins = new \RainLoop\Plugins\Manager($this);
+ $this->oPlugins->SetLogger($this->Logger());
+ }
+
+ return $this->oPlugins;
+ }
+
+ /**
+ * @return \MailSo\Log\Logger
+ */
+ public function Logger()
+ {
+ if (null === $this->oLogger)
+ {
+ $this->oLogger = \MailSo\Log\Logger::SingletonInstance();
+
+ if (!!$this->Config()->Get('logs', 'enable', false))
+ {
+ $sSessionFilter = (string) $this->Config()->Get('logs', 'session_filter', '');
+ if (!empty($sSessionFilter))
+ {
+ $aSessionParts = \explode(':', $sSessionFilter, 2);
+
+ if (empty($aSessionParts[0]) || empty($aSessionParts[1]) ||
+ (string) $aSessionParts[1] !== (string) \RainLoop\Utils::GetCookie($aSessionParts[0], ''))
+ {
+ return $this->oLogger;
+ }
+ }
+
+ $iTimeOffset = (int) $this->Config()->Get('logs', 'time_offset', 0);
+
+ $this->oLogger->SetShowSecter(!$this->Config()->Get('logs', 'hide_passwords', true));
+
+ $sLogFileFullPath = \APP_PRIVATE_DATA.'logs/'.$this->compileLogFileName(
+ $this->Config()->Get('logs', 'filename', ''));
+
+ $sLogFileDir = \dirname($sLogFileFullPath);
+
+ if (!@is_dir($sLogFileDir))
+ {
+ @mkdir($sLogFileDir, 0755, true);
+ }
+
+ $this->oLogger->Add(
+ \MailSo\Log\Drivers\File::NewInstance($sLogFileFullPath)
+ ->WriteOnErrorOnly($this->Config()->Get('logs', 'write_on_error_only', false))
+ ->WriteOnPhpErrorOnly($this->Config()->Get('logs', 'write_on_php_error_only', false))
+ ->WriteOnTimeoutOnly($this->Config()->Get('logs', 'write_on_timeout_only', 0))
+ ->SetTimeOffset($iTimeOffset)
+ );
+
+ if (!$this->Config()->Get('debug', 'enable', false))
+ {
+ $this->oLogger->AddForbiddenType(\MailSo\Log\Enumerations\Type::TIME);
+ }
+
+ $this->oLogger->WriteEmptyLine();
+
+ $oHttp = $this->Http();
+
+ $this->oLogger->Write('[DATE:'.\MailSo\Log\Logger::DateHelper('d.m.y', $iTimeOffset).
+ (0 !== $iTimeOffset ? '][OFFSET:'.(0 < $iTimeOffset ? '+' : '-').
+ \str_pad((string) \abs($iTimeOffset), 2, '0', STR_PAD_LEFT) : '').
+ '][RL:'.APP_VERSION.'][PHP:'.PHP_VERSION.'][IP:'.
+ $oHttp->GetClientIp($this->Config()->Get('labs', 'http_client_ip_check_proxy', false)).'][PID:'.
+ (\MailSo\Base\Utils::FunctionExistsAndEnabled('getmypid') ? \getmypid() : 'unknown').']['.
+ $oHttp->GetServer('SERVER_SOFTWARE', '~').']['.
+ (\MailSo\Base\Utils::FunctionExistsAndEnabled('php_sapi_name') ? \php_sapi_name() : '~' ).']'
+ );
+
+ $sPdo = (\class_exists('PDO') ? \implode(',', \PDO::getAvailableDrivers()) : 'off');
+ $sPdo = empty($sPdo) ? '~' : $sPdo;
+
+ $this->oLogger->Write('['.
+ 'Suhosin:'.(\extension_loaded('suhosin') || @\ini_get('suhosin.get.max_value_length') ? 'on' : 'off').
+ '][APC:'.(\MailSo\Base\Utils::FunctionExistsAndEnabled('apc_fetch') ? 'on' : 'off').
+ '][MB:'.(\MailSo\Base\Utils::FunctionExistsAndEnabled('mb_convert_encoding') ? 'on' : 'off').
+ '][PDO:'.$sPdo.
+ (\RainLoop\Utils::IsOwnCloud() ? '][ownCloud:true' : '').
+ '][Streams:'.\implode(',', \stream_get_transports()).
+ ']');
+
+ $this->oLogger->Write(
+ '['.$oHttp->GetMethod().'] '.$oHttp->GetScheme().'://'.$oHttp->GetHost(false, false).$oHttp->GetServer('REQUEST_URI', ''),
+ \MailSo\Log\Enumerations\Type::NOTE, 'REQUEST');
+ }
+ }
+
+ return $this->oLogger;
+ }
+
+ /**
+ * @return \MailSo\Log\Logger
+ */
+ public function LoggerAuth()
+ {
+ if (null === $this->oLoggerAuth)
+ {
+ $this->oLoggerAuth = \MailSo\Log\Logger::NewInstance(false);
+
+ if (!!$this->Config()->Get('logs', 'auth_logging', false))
+ {
+ $sAuthLogFileFullPath = \APP_PRIVATE_DATA.'logs/'.$this->compileLogFileName(
+ $this->Config()->Get('logs', 'auth_logging_filename', ''));
+
+ $sLogFileDir = \dirname($sAuthLogFileFullPath);
+
+ if (!@is_dir($sLogFileDir))
+ {
+ @mkdir($sLogFileDir, 0755, true);
+ }
+
+ $this->oLoggerAuth->AddForbiddenType(\MailSo\Log\Enumerations\Type::MEMORY);
+ $this->oLoggerAuth->AddForbiddenType(\MailSo\Log\Enumerations\Type::TIME);
+ $this->oLoggerAuth->AddForbiddenType(\MailSo\Log\Enumerations\Type::TIME_DELTA);
+
+ $oDriver = \MailSo\Log\Drivers\File::NewInstance($sAuthLogFileFullPath);
+
+ $oDriver->DisableTimePrefix();
+ $oDriver->DisableGuidPrefix();
+ $oDriver->DisableTypedPrefix();
+
+ $this->oLoggerAuth->Add($oDriver);
+ }
+ }
+
+ return $this->oLoggerAuth;
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ */
+ public function LoggerAuthHelper($oAccount = null)
+ {
+ $sLine = $this->Config()->Get('logs', 'auth_logging_format', '');
+ if (!empty($sLine))
+ {
+ $this->LoggerAuth()->Write($this->compileLogParams($sLine, $oAccount));
+ }
+ }
+
+ /**
+ * @return string
+ */
+ private function getAdminToken()
+ {
+ $sRand = \MailSo\Base\Utils::Md5Rand();
+ if (!$this->Cacher(null, true)->Set(\RainLoop\KeyPathHelper::SessionAdminKey($sRand), \time()))
+ {
+ $this->oLogger->Write('Cannot store an admin token',
+ \MailSo\Log\Enumerations\Type::WARNING);
+
+ $sRand = '';
+ }
+
+ return '' === $sRand ? '' : \RainLoop\Utils::EncodeKeyValuesQ(array('token', \md5(APP_SALT), $sRand));
+ }
+
+ /**
+ * @param bool $bThrowExceptionOnFalse = true
+ *
+ * @return bool
+ */
+ public function IsAdminLoggined($bThrowExceptionOnFalse = true)
+ {
+ $bResult = false;
+ if ($this->Config()->Get('security', 'allow_admin_panel', true))
+ {
+ $aAdminHash = \RainLoop\Utils::DecodeKeyValuesQ($this->getAdminAuthToken());
+ if (!empty($aAdminHash[0]) && !empty($aAdminHash[1]) && !empty($aAdminHash[2]) &&
+ 'token' === $aAdminHash[0] && \md5(APP_SALT) === $aAdminHash[1] &&
+ '' !== $this->Cacher(null, true)->Get(\RainLoop\KeyPathHelper::SessionAdminKey($aAdminHash[2]), '')
+ )
+ {
+ $bResult = true;
+ }
+ }
+
+ if (!$bResult && $bThrowExceptionOnFalse)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @param string $sTo
+ */
+ public function SetMailtoRequest($sTo)
+ {
+ if (!empty($sTo))
+ {
+ \RainLoop\Utils::SetCookie(self::AUTH_MAILTO_TOKEN_KEY,
+ \RainLoop\Utils::EncodeKeyValuesQ(array(
+ 'Time' => \microtime(true),
+ 'MailTo' => 'MailTo',
+ 'To' => $sTo
+ )), 0);
+ }
+ }
+
+ /**
+ * @param string $sEmail
+ * @param string $sLogin
+ * @param string $sPassword
+ * @param string $sSignMeToken = ''
+ * @param bool $bThrowProvideException = false
+ *
+ * @return \RainLoop\Model\Account|null
+ */
+ public function LoginProvide($sEmail, $sLogin, $sPassword, $sSignMeToken = '', $bThrowProvideException = false)
+ {
+ $oAccount = null;
+ if (0 < \strlen($sEmail) && 0 < \strlen($sLogin) && 0 < \strlen($sPassword))
+ {
+ $oDomain = $this->DomainProvider()->Load(\MailSo\Base\Utils::GetDomainFromEmail($sEmail), true);
+ if ($oDomain instanceof \RainLoop\Model\Domain)
+ {
+ if ($oDomain->ValidateWhiteList($sEmail, $sLogin))
+ {
+ $oAccount = \RainLoop\Model\Account::NewInstance($sEmail, $sLogin, $sPassword, $oDomain, $sSignMeToken);
+ $this->Plugins()->RunHook('filter.acount', array(&$oAccount));
+
+ if ($bThrowProvideException && !($oAccount instanceof \RainLoop\Model\Account))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
+ }
+ }
+ else if ($bThrowProvideException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AccountNotAllowed);
+ }
+ }
+ else if ($bThrowProvideException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::DomainNotAllowed);
+ }
+ }
+
+ return $oAccount;
+ }
+
+ /**
+ * @param string $sToken
+ * @param bool $bThrowExceptionOnFalse = true
+ * @param bool $bValidateShortToken = true
+ * @param bool $bQ = false
+ *
+ * @return \RainLoop\Model\Account|bool
+ * @throws \RainLoop\Exceptions\ClientException
+ */
+ public function GetAccountFromCustomToken($sToken, $bThrowExceptionOnFalse = true, $bValidateShortToken = true, $bQ = false)
+ {
+ $oResult = false;
+ if (!empty($sToken))
+ {
+ $aAccountHash = $bQ ? \RainLoop\Utils::DecodeKeyValuesQ($sToken) : \RainLoop\Utils::DecodeKeyValues($sToken);
+ if (!empty($aAccountHash[0]) && 'token' === $aAccountHash[0] && // simple token validation
+ 8 <= \count($aAccountHash) && // length checking
+ !empty($aAccountHash[7]) && // does short token exist
+ (!$bValidateShortToken || \RainLoop\Utils::GetShortToken() === $aAccountHash[7] || // check short token if needed
+ (isset($aAccountHash[10]) && 0 < $aAccountHash[10] && \time() < $aAccountHash[10]))
+ )
+ {
+ $oAccount = $this->LoginProvide($aAccountHash[1], $aAccountHash[2], $aAccountHash[3],
+ empty($aAccountHash[5]) ? '' : $aAccountHash[5], $bThrowExceptionOnFalse);
+
+ if ($oAccount instanceof \RainLoop\Model\Account)
+ {
+ if (!empty($aAccountHash[8]) && !empty($aAccountHash[9])) // init proxy user/password
+ {
+ $oAccount->SetProxyAuthUser($aAccountHash[8]);
+ $oAccount->SetProxyAuthPassword($aAccountHash[9]);
+ }
+
+ $this->Logger()->AddSecret($oAccount->Password());
+ $this->Logger()->AddSecret($oAccount->ProxyAuthPassword());
+
+ $oAccount->SetParentEmail($aAccountHash[6]);
+ $oResult = $oAccount;
+ }
+ }
+ else if ($bThrowExceptionOnFalse)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
+ }
+ }
+
+ if ($bThrowExceptionOnFalse && !($oResult instanceof \RainLoop\Model\Account))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
+ }
+
+ return $oResult;
+ }
+
+ /**
+ * @return \RainLoop\Model\Account|bool
+ */
+ public function GetAccountFromSignMeToken()
+ {
+ $oAccount = false;
+
+ $sSignMeToken = \RainLoop\Utils::GetCookie(\RainLoop\Actions::AUTH_SIGN_ME_TOKEN_KEY, '');
+ if (!empty($sSignMeToken))
+ {
+ $aTokenData = \RainLoop\Utils::DecodeKeyValuesQ($sSignMeToken);
+ if (\is_array($aTokenData) && !empty($aTokenData['e']) && !empty($aTokenData['t']))
+ {
+ $sTokenSettings = $this->StorageProvider()->Get($aTokenData['e'],
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'sign_me'
+ );
+
+ if (!empty($sTokenSettings))
+ {
+ $aSignMeData = \RainLoop\Utils::DecodeKeyValuesQ($sTokenSettings);
+ if (\is_array($aSignMeData) &&
+ !empty($aSignMeData['AuthToken']) &&
+ !empty($aSignMeData['SignMetToken']) &&
+ $aSignMeData['SignMetToken'] === $aTokenData['t'])
+ {
+ $oAccount = $this->GetAccountFromCustomToken($aSignMeData['AuthToken'], false, false, true);
+ }
+ }
+ }
+ }
+ else
+ {
+ \RainLoop\Utils::ClearCookie(\RainLoop\Actions::AUTH_SIGN_ME_TOKEN_KEY);
+ }
+
+ return $oAccount;
+ }
+
+ /**
+ * @param bool $bThrowExceptionOnFalse = true
+ *
+ * @return \RainLoop\Model\Account|bool
+ * @throws \RainLoop\Exceptions\ClientException
+ */
+ public function getAccountFromToken($bThrowExceptionOnFalse = true)
+ {
+ return $this->GetAccountFromCustomToken($this->getLocalAuthToken(), $bThrowExceptionOnFalse, true, true);
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsOpen()
+ {
+ return !$this->PremProvider();
+ }
+
+ /**
+ * @param bool $bAdmin = false
+ * @param bool $bMobile = false
+ * @param bool $bMobileDevice = false
+ *
+ * @return array
+ */
+ public function AppDataSystem($bAdmin = false, $bMobile = false, $bMobileDevice = false)
+ {
+ $oConfig = $this->Config();
+
+ $sRsaPublicKey = '';
+ if ($oConfig->Get('security', 'use_rsa_encryption', false) &&
+ \file_exists(APP_PRIVATE_DATA.'rsa/public') && \file_exists(APP_PRIVATE_DATA.'rsa/private'))
+ {
+ $sRsaPublicKey = @\file_get_contents(APP_PRIVATE_DATA.'rsa/public') || '';
+ if (false === \strpos($sRsaPublicKey, 'PUBLIC KEY'))
+ {
+ $sRsaPublicKey = '';
+ }
+ }
+
+ $aAttachmentsActions = array();
+ if ($this->GetCapa(false, $bMobile, \RainLoop\Enumerations\Capa::ATTACHMENTS_ACTIONS))
+ {
+ if (!!\class_exists('ZipArchive'))
+ {
+ $aAttachmentsActions[] = 'zip';
+ }
+
+ if (\RainLoop\Utils::IsOwnCloudLoggedIn() && \class_exists('OCP\Files'))
+ {
+ $aAttachmentsActions[] = 'owncloud';
+ }
+
+ if ($oConfig->Get('social', 'dropbox_enable', false) && 0 < \strlen(\trim($oConfig->Get('social', 'dropbox_api_key', ''))))
+ {
+ $aAttachmentsActions[] = 'dropbox';
+ }
+ }
+
+ return \array_merge(array(
+ 'version' => APP_VERSION,
+ 'mobile' => $bMobile,
+ 'mobileDevice' => $bMobileDevice,
+ 'webPath' => \RainLoop\Utils::WebPath(),
+ 'webVersionPath' => \RainLoop\Utils::WebVersionPath(),
+ 'token' => $oConfig->Get('security', 'csrf_protection', false) ? \RainLoop\Utils::GetCsrfToken() : '',
+ 'inIframe' => (bool) $oConfig->Get('labs', 'in_iframe', false),
+ 'allowHtmlEditorSourceButton' => (bool) $oConfig->Get('labs', 'allow_html_editor_source_button', false),
+ 'allowHtmlEditorBitiButtons' => (bool) $oConfig->Get('labs', 'allow_html_editor_biti_buttons', false),
+ 'allowCtrlEnterOnCompose' => (bool) $oConfig->Get('labs', 'allow_ctrl_enter_on_compose', false),
+ 'customLoginLink' => $oConfig->Get('labs', 'custom_login_link', ''),
+ 'customLogoutLink' => $oConfig->Get('labs', 'custom_logout_link', ''),
+ 'forgotPasswordLinkUrl' => \trim($oConfig->Get('login', 'forgot_password_link_url', '')),
+ 'registrationLinkUrl' => \trim($oConfig->Get('login', 'registration_link_url', '')),
+ 'jsHash' => \md5(\RainLoop\Utils::GetConnectionToken()),
+ 'useImapThread' => (bool) $oConfig->Get('labs', 'use_imap_thread', false),
+ 'useImapSubscribe' => (bool) $oConfig->Get('labs', 'use_imap_list_subscribe', true),
+ 'allowAppendMessage' => (bool) $oConfig->Get('labs', 'allow_message_append', false),
+ 'materialDesign' => (bool) $oConfig->Get('labs', 'use_material_design', true),
+ 'folderSpecLimit' => (int) $oConfig->Get('labs', 'folders_spec_limit', 50),
+ 'faviconStatus' => (bool) $oConfig->Get('labs', 'favicon_status', true),
+ 'listPermanentFiltered' => '' !== \trim(\RainLoop\Api::Config()->Get('labs', 'imap_message_list_permanent_filter', '')),
+ 'themes' => $this->GetThemes($bMobile, false),
+ 'languages' => $this->GetLanguages(false),
+ 'languagesAdmin' => $this->GetLanguages(true),
+ 'attachmentsActions' => $aAttachmentsActions,
+ 'rsaPublicKey' => $sRsaPublicKey
+ ), $bAdmin ? array(
+ 'adminPath' => \strtolower($oConfig->Get('security', 'admin_panel_key', 'admin')),
+ 'allowAdminPanel' => (bool) $oConfig->Get('security', 'allow_admin_panel', true),
+ ) : array());
+ }
+
+ /**
+ * @param bool $bAdmin
+ * @param bool $bMobile = false
+ * @param string $sAuthAccountHash = ''
+ *
+ * @return array
+ */
+ public function AppData($bAdmin, $bMobile = false, $bMobileDevice = false, $sAuthAccountHash = '')
+ {
+ if (0 < \strlen($sAuthAccountHash) && \preg_match('/[^_\-\.a-zA-Z0-9]/', $sAuthAccountHash))
+ {
+ $sAuthAccountHash = '';
+ }
+
+ $oAccount = null;
+ $oConfig = $this->Config();
+
+/*
+required by Index.html and rl.js:
+NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBackground PluginsLink AuthAccountHash
+*/
+
+ $aResult = array(
+ 'Auth' => false,
+ 'AccountHash' => '',
+ 'AccountSignMe' => false,
+ 'AuthAccountHash' => '',
+ 'MailToEmail' => '',
+ 'Email' => '',
+ 'DevEmail' => '',
+ 'DevPassword' => '',
+ 'Title' => $oConfig->Get('webmail', 'title', 'RainLoop Webmail'),
+ 'LoadingDescription' => $oConfig->Get('webmail', 'loading_description', 'RainLoop'),
+ 'LoadingDescriptionEsc' => 'RainLoop',
+ 'FaviconUrl' => $oConfig->Get('webmail', 'favicon_url', ''),
+ 'LoginDescription' => '',
+ 'LoginPowered' => true,
+ 'LoginLogo' => '',
+ 'LoginBackground' => '',
+ 'LoginCss' => '',
+ 'UserLogo' => '',
+ 'UserLogoTitle' => '',
+ 'UserLogoMessage' => '',
+ 'UserCss' => '',
+ 'WelcomePageUrl' => '',
+ 'WelcomePageDisplay' => 'none',
+ 'IncludeCss' => '',
+ 'IncludeBackground' => '',
+ 'LoginDefaultDomain' => $oConfig->Get('login', 'default_domain', ''),
+ 'DetermineUserLanguage' => (bool) $oConfig->Get('login', 'determine_user_language', true),
+ 'DetermineUserDomain' => (bool) $oConfig->Get('login', 'determine_user_domain', false),
+ 'UseLoginWelcomePage' => (bool) $oConfig->Get('login', 'welcome_page', false),
+ 'StartupUrl' => \trim(\ltrim(\trim($oConfig->Get('labs', 'startup_url', '')), '#/')),
+ 'ContactsIsAllowed' => false,
+ 'ChangePasswordIsAllowed' => false,
+ 'RequireTwoFactor' => false,
+ 'Community' => true,
+ 'PremType' => false,
+ 'Admin' => array(),
+ 'Capa' => array(),
+ 'Plugins' => array(),
+ 'System' => $this->AppDataSystem($bAdmin, $bMobile, $bMobileDevice)
+ );
+
+ if (0 < \strlen($sAuthAccountHash))
+ {
+ $aResult['AuthAccountHash'] = $sAuthAccountHash;
+ }
+
+ $oPremProvider = $this->PremProvider();
+ if ($oPremProvider)
+ {
+ $oPremProvider->PopulateAppData($aResult);
+ }
+
+ if ('' !== $aResult['LoadingDescription'] && 'RainLoop' !== $aResult['LoadingDescription'])
+ {
+ $aResult['LoadingDescriptionEsc'] = @\htmlspecialchars($aResult['LoadingDescription'], ENT_QUOTES|ENT_IGNORE, 'UTF-8');
+ }
+
+ $oSettings = null;
+
+ if (!$bAdmin)
+ {
+ $oAccount = $this->getAccountFromToken(false);
+ if ($oAccount instanceof \RainLoop\Model\Account)
+ {
+ $aResult['IncludeCss'] = $aResult['UserCss'];
+
+ $oAddressBookProvider = $this->AddressBookProvider($oAccount);
+
+ $aResult['Auth'] = true;
+ $aResult['Email'] = $oAccount->Email();
+ $aResult['IncLogin'] = $oAccount->IncLogin();
+ $aResult['OutLogin'] = $oAccount->OutLogin();
+ $aResult['AccountHash'] = $oAccount->Hash();
+ $aResult['AccountSignMe'] = $oAccount->SignMe();
+ $aResult['ChangePasswordIsAllowed'] = $this->ChangePasswordProvider()->PasswordChangePossibility($oAccount);
+ $aResult['ContactsIsAllowed'] = $oAddressBookProvider->IsActive();
+ $aResult['ContactsSharingIsAllowed'] = $oAddressBookProvider->IsSharingAllowed();
+ $aResult['ContactsSyncIsAllowed'] = (bool) $oConfig->Get('contacts', 'allow_sync', false);
+ $aResult['ContactsSyncInterval'] = (int) $oConfig->Get('contacts', 'sync_interval', 20);
+
+ $aResult['EnableContactsSync'] = false;
+ $aResult['ContactsSyncUrl'] = '';
+ $aResult['ContactsSyncUser'] = '';
+ $aResult['ContactsSyncPassword'] = '';
+
+ if ($aResult['ContactsIsAllowed'] && $aResult['ContactsSyncIsAllowed'])
+ {
+ $mData = $this->getContactsSyncData($oAccount);
+ if (\is_array($mData))
+ {
+ $aResult['EnableContactsSync'] = isset($mData['Enable']) ? !!$mData['Enable'] : false;
+ $aResult['ContactsSyncUrl'] = isset($mData['Url']) ? \trim($mData['Url']) : '';
+ $aResult['ContactsSyncUser'] = isset($mData['User']) ? \trim($mData['User']) : '';
+ $aResult['ContactsSyncPassword'] = APP_DUMMY;
+ }
+ }
+
+ if ($aResult['AccountSignMe'])
+ {
+ $sToken = \RainLoop\Utils::GetCookie(self::AUTH_MAILTO_TOKEN_KEY, null);
+ if (null !== $sToken)
+ {
+ \RainLoop\Utils::ClearCookie(self::AUTH_MAILTO_TOKEN_KEY);
+
+ $mMailToData = \RainLoop\Utils::DecodeKeyValuesQ($sToken);
+ if (\is_array($mMailToData) && !empty($mMailToData['MailTo']) &&
+ 'MailTo' === $mMailToData['MailTo'] && !empty($mMailToData['To']))
+ {
+ $aResult['MailToEmail'] = $mMailToData['To'];
+ }
+ }
+ }
+
+ $oSettings = $this->SettingsProvider()->Load($oAccount);
+
+ if (!$oAccount->IsAdditionalAccount() && !empty($aResult['WelcomePageUrl']) &&
+ ('once' === $aResult['WelcomePageDisplay'] || 'always' === $aResult['WelcomePageDisplay']))
+ {
+ if ('once' === $aResult['WelcomePageDisplay'])
+ {
+ if ($aResult['WelcomePageUrl'] === $oSettings->GetConf('LastWelcomePage', ''))
+ {
+ $aResult['WelcomePageUrl'] = '';
+ $aResult['WelcomePageDisplay'] = '';
+ }
+ }
+ }
+ else
+ {
+ $aResult['WelcomePageUrl'] = '';
+ $aResult['WelcomePageDisplay'] = '';
+ }
+
+ if (!empty($aResult['StartupUrl']))
+ {
+ $aResult['StartupUrl'] = $this->compileLogParams($aResult['StartupUrl'], $oAccount, true);
+ }
+
+ if (!empty($aResult['UserIframeMessage']))
+ {
+ $aResult['UserIframeMessage'] = $this->compileLogParams($aResult['UserIframeMessage'], $oAccount, true);
+ }
+ }
+ else
+ {
+ $oAccount = null;
+
+ $aResult['IncludeBackground'] = $aResult['LoginBackground'];
+ $aResult['IncludeCss'] = $aResult['LoginCss'];
+
+ $aResult['DevEmail'] = $oConfig->Get('labs', 'dev_email', '');
+ $aResult['DevPassword'] = $oConfig->Get('labs', 'dev_password', '');
+
+ $aResult['WelcomePageUrl'] = '';
+ $aResult['WelcomePageDisplay'] = '';
+
+ $aResult['StartupUrl'] = '';
+
+ if (empty($aResult['AdditionalLoginError']))
+ {
+ $aResult['AdditionalLoginError'] = $this->GetSpecLogoutCustomMgsWithDeletion();
+ }
+ }
+
+ $aResult['AllowGoogleSocial'] = (bool) $oConfig->Get('social', 'google_enable', false);
+ $aResult['AllowGoogleSocialAuth'] = (bool) $oConfig->Get('social', 'google_enable_auth', true);
+ $aResult['AllowGoogleSocialAuthFast'] = (bool) $oConfig->Get('social', 'google_enable_auth_fast', true);
+ $aResult['AllowGoogleSocialDrive'] = (bool) $oConfig->Get('social', 'google_enable_drive', true);
+ $aResult['AllowGoogleSocialPreview'] = (bool) $oConfig->Get('social', 'google_enable_preview', true);
+
+ $aResult['GoogleClientID'] = \trim($oConfig->Get('social', 'google_client_id', ''));
+ $aResult['GoogleApiKey'] = \trim($oConfig->Get('social', 'google_api_key', ''));
+
+ if (!$aResult['AllowGoogleSocial'] || ($aResult['AllowGoogleSocial'] && (
+ '' === \trim($oConfig->Get('social', 'google_client_id', '')) || '' === \trim($oConfig->Get('social', 'google_client_secret', '')))))
+ {
+ $aResult['AllowGoogleSocialAuth'] = false;
+ $aResult['AllowGoogleSocialAuthFast'] = false;
+ $aResult['AllowGoogleSocialDrive'] = false;
+ $aResult['GoogleClientID'] = '';
+ $aResult['GoogleApiKey'] = '';
+ }
+
+ if (!$aResult['AllowGoogleSocial'])
+ {
+ $aResult['AllowGoogleSocialPreview'] = false;
+ }
+
+ if ($aResult['AllowGoogleSocial'] &&
+ !$aResult['AllowGoogleSocialAuth'] && !$aResult['AllowGoogleSocialAuthFast'] &&
+ !$aResult['AllowGoogleSocialDrive'] && !$aResult['AllowGoogleSocialPreview'])
+ {
+ $aResult['AllowGoogleSocial'] = false;
+ }
+
+ $aResult['AllowFacebookSocial'] = (bool) $oConfig->Get('social', 'fb_enable', false);
+ if ($aResult['AllowFacebookSocial'] && (
+ '' === \trim($oConfig->Get('social', 'fb_app_id', '')) || '' === \trim($oConfig->Get('social', 'fb_app_secret', ''))))
+ {
+ $aResult['AllowFacebookSocial'] = false;
+ }
+
+ $aResult['AllowTwitterSocial'] = (bool) $oConfig->Get('social', 'twitter_enable', false);
+ if ($aResult['AllowTwitterSocial'] && (
+ '' === \trim($oConfig->Get('social', 'twitter_consumer_key', '')) || '' === \trim($oConfig->Get('social', 'twitter_consumer_secret', ''))))
+ {
+ $aResult['AllowTwitterSocial'] = false;
+ }
+
+ $aResult['AllowDropboxSocial'] = (bool) $oConfig->Get('social', 'dropbox_enable', false);
+ $aResult['DropboxApiKey'] = \trim($oConfig->Get('social', 'dropbox_api_key', ''));
+
+ if (!$aResult['AllowDropboxSocial'])
+ {
+ $aResult['DropboxApiKey'] = '';
+ }
+ else if (0 === strlen($aResult['DropboxApiKey']))
+ {
+ $aResult['AllowDropboxSocial'] = false;
+ }
+
+ $aResult['Capa'] = $this->Capa(false, $bMobile, $oAccount);
+
+ if ($aResult['Auth'] && !$aResult['RequireTwoFactor'])
+ {
+ if ($this->GetCapa(false, $bMobile, \RainLoop\Enumerations\Capa::TWO_FACTOR, $oAccount) &&
+ $this->GetCapa(false, $bMobile, \RainLoop\Enumerations\Capa::TWO_FACTOR_FORCE, $oAccount) &&
+ $this->TwoFactorAuthProvider()->IsActive())
+ {
+ $aData = $this->getTwoFactorInfo($oAccount, true);
+
+ $aResult['RequireTwoFactor'] = !$aData ||
+ !isset($aData['User'], $aData['IsSet'], $aData['Enable']) ||
+ !($aData['IsSet'] && $aData['Enable']);
+ }
+ }
+ }
+ else
+ {
+ $aResult['Auth'] = $this->IsAdminLoggined(false);
+ if ($aResult['Auth'])
+ {
+ $aResult['AdminDomain'] = APP_SITE;
+ $aResult['AdminLogin'] = (string) $oConfig->Get('security', 'admin_login', '');
+ $aResult['UseTokenProtection'] = (bool) $oConfig->Get('security', 'csrf_protection', true);
+ $aResult['EnabledPlugins'] = (bool) $oConfig->Get('plugins', 'enable', false);
+
+ $aResult['VerifySslCertificate'] = (bool) $oConfig->Get('ssl', 'verify_certificate', false);
+ $aResult['AllowSelfSigned'] = (bool) $oConfig->Get('ssl', 'allow_self_signed', true);
+
+ $aDrivers = \class_exists('PDO') ? \PDO::getAvailableDrivers() : null;
+ $aResult['MySqlIsSupported'] = \is_array($aDrivers) ? \in_array('mysql', $aDrivers) : false;
+ $aResult['SQLiteIsSupported'] = \is_array($aDrivers) ? \in_array('sqlite', $aDrivers) : false;
+ $aResult['PostgreSqlIsSupported'] = \is_array($aDrivers) ? \in_array('pgsql', $aDrivers) : false;
+
+ $aResult['ContactsEnable'] = (bool) $oConfig->Get('contacts', 'enable', false);
+ $aResult['ContactsSharing'] = (bool) $oConfig->Get('contacts', 'allow_sharing', false);
+ $aResult['ContactsSync'] = (bool) $oConfig->Get('contacts', 'allow_sync', false);
+ $aResult['ContactsPdoType'] = (string) $this->ValidateContactPdoType(\trim($this->Config()->Get('contacts', 'type', 'sqlite')));
+ $aResult['ContactsPdoDsn'] = (string) $oConfig->Get('contacts', 'pdo_dsn', '');
+ $aResult['ContactsPdoType'] = (string) $oConfig->Get('contacts', 'type', '');
+ $aResult['ContactsPdoUser'] = (string) $oConfig->Get('contacts', 'pdo_user', '');
+ $aResult['ContactsPdoPassword'] = (string) APP_DUMMY;
+
+ $aResult['AllowGoogleSocial'] = (bool) $oConfig->Get('social', 'google_enable', false);
+ $aResult['AllowGoogleSocialAuth'] = (bool) $oConfig->Get('social', 'google_enable_auth', true);
+ $aResult['AllowGoogleSocialAuthFast'] = (bool) $oConfig->Get('social', 'google_enable_auth_fast', true);
+ $aResult['AllowGoogleSocialDrive'] = (bool) $oConfig->Get('social', 'google_enable_drive', true);
+ $aResult['AllowGoogleSocialPreview'] = (bool) $oConfig->Get('social', 'google_enable_preview', true);
+
+ $aResult['GoogleClientID'] = (string) $oConfig->Get('social', 'google_client_id', '');
+ $aResult['GoogleClientSecret'] = (string) $oConfig->Get('social', 'google_client_secret', '');
+ $aResult['GoogleApiKey'] = (string) $oConfig->Get('social', 'google_api_key', '');
+
+ $aResult['AllowFacebookSocial'] = (bool) $oConfig->Get('social', 'fb_enable', false);
+ $aResult['FacebookAppID'] = (string) $oConfig->Get('social', 'fb_app_id', '');
+ $aResult['FacebookAppSecret'] = (string) $oConfig->Get('social', 'fb_app_secret', '');
+
+ $aResult['AllowTwitterSocial'] = (bool) $oConfig->Get('social', 'twitter_enable', false);
+ $aResult['TwitterConsumerKey'] = (string) $oConfig->Get('social', 'twitter_consumer_key', '');
+ $aResult['TwitterConsumerSecret'] = (string) $oConfig->Get('social', 'twitter_consumer_secret', '');
+
+ $aResult['AllowDropboxSocial'] = (bool) $oConfig->Get('social', 'dropbox_enable', false);
+ $aResult['DropboxApiKey'] = (string) $oConfig->Get('social', 'dropbox_api_key', '');
+
+ $aResult['SubscriptionEnabled'] = (bool) \MailSo\Base\Utils::ValidateDomain($aResult['AdminDomain']);
+// || \MailSo\Base\Utils::ValidateIP($aResult['AdminDomain']);
+
+ $aResult['WeakPassword'] = (bool) $oConfig->ValidatePassword('12345');
+ $aResult['CoreAccess'] = (bool) $this->rainLoopCoreAccess();
+
+ $aResult['PhpUploadSizes'] = array(
+ 'upload_max_filesize' => \ini_get('upload_max_filesize'),
+ 'post_max_size' => \ini_get('post_max_size')
+ );
+ }
+
+ $aResult['Capa'] = $this->Capa(true, $bMobile);
+ }
+
+ $aResult['SupportedFacebookSocial'] = (bool) \version_compare(PHP_VERSION, '5.4.0', '>=');
+ if (!$aResult['SupportedFacebookSocial'])
+ {
+ $aResult['AllowFacebookSocial'] = false;
+ $aResult['FacebookAppID'] = '';
+ $aResult['FacebookAppSecret'] = '';
+ }
+
+ $aResult['ProjectHash'] = \md5($aResult['AccountHash'].APP_VERSION.$this->Plugins()->Hash());
+
+ $sLanguage = $oConfig->Get('webmail', 'language', 'en');
+ $sLanguageAdmin = $oConfig->Get('webmail', 'language_admin', 'en');
+ $sTheme = $oConfig->Get('webmail', 'theme', 'Default');
+
+ $aResult['AllowLanguagesOnSettings'] = (bool) $oConfig->Get('webmail', 'allow_languages_on_settings', true);
+ $aResult['AllowLanguagesOnLogin'] = (bool) $oConfig->Get('login', 'allow_languages_on_login', true);
+ $aResult['AttachmentLimit'] = ((int) $oConfig->Get('webmail', 'attachment_size_limit', 10)) * 1024 * 1024;
+ $aResult['SignMe'] = (string) $oConfig->Get('login', 'sign_me_auto', \RainLoop\Enumerations\SignMeType::DEFAILT_OFF);
+ $aResult['UseLocalProxyForExternalImages'] = (bool) $oConfig->Get('labs', 'use_local_proxy_for_external_images', false);
+
+ // user
+ $aResult['ShowImages'] = (bool) $oConfig->Get('defaults', 'show_images', false);
+ $aResult['MPP'] = (int) $oConfig->Get('webmail', 'messages_per_page', 25);
+ $aResult['SoundNotification'] = false;
+ $aResult['DesktopNotifications'] = false;
+ $aResult['Layout'] = (int) $oConfig->Get('defaults', 'view_layout', \RainLoop\Enumerations\Layout::SIDE_PREVIEW);
+ $aResult['EditorDefaultType'] = (string) $oConfig->Get('defaults', 'view_editor_type', '');
+ $aResult['UseCheckboxesInList'] = (bool) $oConfig->Get('defaults', 'view_use_checkboxes', true);
+ $aResult['AutoLogout'] = (int) $oConfig->Get('defaults', 'autologout', 30);
+ $aResult['UseThreads'] = (bool) $oConfig->Get('defaults', 'mail_use_threads', false);
+ $aResult['ReplySameFolder'] = (bool) $oConfig->Get('defaults', 'mail_reply_same_folder', false);
+ $aResult['ContactsAutosave'] = (bool) $oConfig->Get('defaults', 'contacts_autosave', true);
+ $aResult['EnableTwoFactor'] = false;
+ $aResult['ParentEmail'] = '';
+ $aResult['InterfaceAnimation'] = true;
+ $aResult['UserBackgroundName'] = '';
+ $aResult['UserBackgroundHash'] = '';
+
+ if (!$bAdmin && $oAccount instanceof \RainLoop\Model\Account)
+ {
+ $aResult['ParentEmail'] = $oAccount->ParentEmail();
+
+ $oSettingsLocal = $this->SettingsProvider(true)->Load($oAccount);
+
+ if ($oSettingsLocal instanceof \RainLoop\Settings)
+ {
+// if ($this->GetCapa(false, $bMobile, \RainLoop\Enumerations\Capa::FOLDERS, $oAccount))
+
+ $aResult['SentFolder'] = (string) $oSettingsLocal->GetConf('SentFolder', '');
+ $aResult['DraftFolder'] = (string) $oSettingsLocal->GetConf('DraftFolder', '');
+ $aResult['SpamFolder'] = (string) $oSettingsLocal->GetConf('SpamFolder', '');
+ $aResult['TrashFolder'] = (string) $oSettingsLocal->GetConf('TrashFolder', '');
+ $aResult['ArchiveFolder'] = (string) $oSettingsLocal->GetConf('ArchiveFolder', '');
+ $aResult['NullFolder'] = (string) $oSettingsLocal->GetConf('NullFolder', '');
+ }
+
+ if ($this->GetCapa(false, $bMobile, \RainLoop\Enumerations\Capa::SETTINGS, $oAccount))
+ {
+ if ($oSettings instanceof \RainLoop\Settings)
+ {
+ if ($oConfig->Get('webmail', 'allow_languages_on_settings', true))
+ {
+ $sLanguage = (string) $oSettings->GetConf('Language', $sLanguage);
+ }
+
+ $aResult['EditorDefaultType'] = (string) $oSettings->GetConf('EditorDefaultType', $aResult['EditorDefaultType']);
+ $aResult['ShowImages'] = (bool) $oSettings->GetConf('ShowImages', $aResult['ShowImages']);
+ $aResult['ContactsAutosave'] = (bool) $oSettings->GetConf('ContactsAutosave', $aResult['ContactsAutosave']);
+ $aResult['MPP'] = (int) $oSettings->GetConf('MPP', $aResult['MPP']);
+ $aResult['SoundNotification'] = (bool) $oSettings->GetConf('SoundNotification', $aResult['SoundNotification']);
+ $aResult['DesktopNotifications'] = (bool) $oSettings->GetConf('DesktopNotifications', $aResult['DesktopNotifications']);
+ $aResult['UseCheckboxesInList'] = (bool) $oSettings->GetConf('UseCheckboxesInList', $aResult['UseCheckboxesInList']);
+ $aResult['AutoLogout'] = (int) $oSettings->GetConf('AutoLogout', $aResult['AutoLogout']);
+ $aResult['Layout'] = (int) $oSettings->GetConf('Layout', $aResult['Layout']);
+
+ if (!$this->GetCapa(false, $bMobile, \RainLoop\Enumerations\Capa::AUTOLOGOUT, $oAccount))
+ {
+ $aResult['AutoLogout'] = 0;
+ }
+
+ if ($this->GetCapa(false, $bMobile, \RainLoop\Enumerations\Capa::USER_BACKGROUND, $oAccount))
+ {
+ $aResult['UserBackgroundName'] = (string) $oSettings->GetConf('UserBackgroundName', $aResult['UserBackgroundName']);
+ $aResult['UserBackgroundHash'] = (string) $oSettings->GetConf('UserBackgroundHash', $aResult['UserBackgroundHash']);
+// if (!empty($aResult['UserBackgroundName']) && !empty($aResult['UserBackgroundHash']))
+// {
+// $aResult['IncludeBackground'] = './?/Raw/&q[]=/{{USER}}/UserBackground/&q[]=/'.
+// $aResult['UserBackgroundHash'].'/';
+// }
+ }
+
+ $aResult['EnableTwoFactor'] = (bool) $oSettings->GetConf('EnableTwoFactor', $aResult['EnableTwoFactor']);
+ }
+
+ if ($oSettingsLocal instanceof \RainLoop\Settings)
+ {
+ $aResult['UseThreads'] = (bool) $oSettingsLocal->GetConf('UseThreads', $aResult['UseThreads']);
+ $aResult['ReplySameFolder'] = (bool) $oSettingsLocal->GetConf('ReplySameFolder', $aResult['ReplySameFolder']);
+
+ if ($this->GetCapa(false, $bMobile, \RainLoop\Enumerations\Capa::THEMES, $oAccount))
+ {
+ $sTheme = (string) $oSettingsLocal->GetConf('Theme', $sTheme);
+ }
+ }
+ }
+ }
+
+ $sStaticCache = \md5(APP_VERSION.$this->Plugins()->Hash());
+
+ $sTheme = $this->ValidateTheme($sTheme, $bMobile);
+ $sNewThemeLink = './?/Css/0/'.($bAdmin ? 'Admin' : 'User').'/-/'.$sTheme.'/-/'.$sStaticCache.'/Hash/-/';
+
+ if (!$aResult['Auth'])
+ {
+ if (!$bAdmin)
+ {
+ if ($oConfig->Get('login', 'allow_languages_on_login', true) &&
+ $oConfig->Get('login', 'determine_user_language', true))
+ {
+ $sLanguage = $this->ValidateLanguage(
+ $this->detectUserLanguage($bAdmin), $sLanguage, false);
+ }
+ }
+ }
+
+ $sPluginsLink = '';
+ if (0 < $this->Plugins()->Count() && $this->Plugins()->HaveJs($bAdmin))
+ {
+ $sPluginsLink = './?/Plugins/0/'.($bAdmin ? 'Admin' : 'User').'/'.$sStaticCache.'/';
+ }
+
+ $aResult['Theme'] = $sTheme;
+ $aResult['NewThemeLink'] = $sNewThemeLink;
+
+ $aResult['Language'] = $this->ValidateLanguage($sLanguage, '', false);
+ $aResult['LanguageAdmin'] = $this->ValidateLanguage($sLanguageAdmin, '', true);
+
+ $aResult['UserLanguageRaw'] = $this->detectUserLanguage($bAdmin);
+
+ $aResult['UserLanguage'] = $this->ValidateLanguage($aResult['UserLanguageRaw'], '', false, true);
+ $aResult['UserLanguageAdmin'] = $this->ValidateLanguage($aResult['UserLanguageRaw'], '', true, true);
+
+ $aResult['LangLink'] = './?/Lang/0/'.($bAdmin ? 'Admin' : 'App').'/'.
+ ($bAdmin ? $aResult['LanguageAdmin'] : $aResult['Language']).'/'.$sStaticCache.'/';
+
+ $aResult['TemplatesLink'] = './?/Templates/0/'.($bAdmin ? 'Admin' : 'App').'/'.$sStaticCache.'/';
+ $aResult['PluginsLink'] = $sPluginsLink;
+ $aResult['EditorDefaultType'] = \in_array($aResult['EditorDefaultType'], array('Plain', 'Html', 'HtmlForced', 'PlainForced')) ?
+ $aResult['EditorDefaultType'] : 'Plain';
+
+ // IDN
+ $aResult['Email'] = \MailSo\Base\Utils::IdnToUtf8($aResult['Email']);
+ $aResult['ParentEmail'] = \MailSo\Base\Utils::IdnToUtf8($aResult['ParentEmail']);
+ $aResult['MailToEmail'] = \MailSo\Base\Utils::IdnToUtf8($aResult['MailToEmail']);
+ $aResult['DevEmail'] = \MailSo\Base\Utils::IdnToUtf8($aResult['DevEmail']);
+
+ // Mobile override
+ if ($bMobile)
+ {
+ $aResult['Layout'] = \RainLoop\Enumerations\Layout::NO_PREVIW;
+
+ $aResult['SoundNotification'] = false;
+ $aResult['DesktopNotifications'] = false;
+ $aResult['UseCheckboxesInList'] = true;
+
+ $aResult['UserBackgroundName'] = '';
+ $aResult['UserBackgroundHash'] = '';
+ }
+
+ $this->Plugins()->InitAppData($bAdmin, $aResult, $oAccount);
+
+ return $aResult;
+ }
+
+ /**
+ * @return array
+ */
+ private function getUserLanguagesFromHeader()
+ {
+ $aResult = $aList = array();
+ $sAcceptLang = \strtolower($this->Http()->GetServer('HTTP_ACCEPT_LANGUAGE', 'en'));
+ if (!empty($sAcceptLang) && \preg_match_all('/([a-z]{1,8}(?:-[a-z]{1,8})?)(?:;q=([0-9.]+))?/', $sAcceptLang, $aList))
+ {
+ $aResult = \array_combine($aList[1], $aList[2]);
+ foreach ($aResult as $n => $v)
+ {
+ $aResult[$n] = $v ? $v : 1;
+ }
+
+ \arsort($aResult, SORT_NUMERIC);
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function detectUserLanguage($bAdmin = false)
+ {
+ $sResult = '';
+ $aLangs = $this->getUserLanguagesFromHeader();
+
+ foreach (\array_keys($aLangs) as $sLang)
+ {
+ $sLang = $this->ValidateLanguage($sLang, '', $bAdmin, true);
+ if (!empty($sLang))
+ {
+ $sResult = $sLang;
+ break;
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param int $iWait = 1
+ * @param int $iDelay = 1
+ */
+ private function requestSleep($iWait = 1, $iDelay = 1)
+ {
+ if (0 < $iDelay && 0 < $iWait)
+ {
+ if ($iWait > \time() - APP_START_TIME)
+ {
+ \sleep($iDelay);
+ }
+ }
+ }
+
+ private function loginErrorDelay()
+ {
+ $iDelay = (int) $this->Config()->Get('labs', 'login_fault_delay', 0);
+ if (0 < $iDelay)
+ {
+ $this->requestSleep(1, $iDelay);
+ }
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ */
+ public function AuthToken($oAccount)
+ {
+ if ($oAccount instanceof \RainLoop\Model\Account)
+ {
+ $this->SetAuthToken($oAccount);
+
+ $aAccounts = $this->GetAccounts($oAccount);
+ if (\is_array($aAccounts) && isset($aAccounts[$oAccount->Email()]))
+ {
+ $aAccounts[$oAccount->Email()] = $oAccount->GetAuthToken();
+ $this->SetAccounts($oAccount, $aAccounts);
+ }
+ }
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ * @param bool $bAuthLog = false
+ *
+ * @throws \RainLoop\Exceptions\ClientException
+ */
+ public function CheckMailConnection($oAccount, $bAuthLog = false)
+ {
+ try
+ {
+ $oAccount->IncConnectAndLoginHelper($this->Plugins(), $this->MailClient(), $this->Config());
+ }
+ catch (\RainLoop\Exceptions\ClientException $oException)
+ {
+ throw $oException;
+ }
+ catch (\MailSo\Net\Exceptions\ConnectionException $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ConnectionError, $oException);
+ }
+ catch (\MailSo\Imap\Exceptions\LoginBadCredentialsException $oException)
+ {
+ if ($bAuthLog)
+ {
+ $this->LoggerAuthHelper($oAccount);
+ }
+
+ if ($this->Config()->Get('labs', 'imap_show_login_alert', true))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError,
+ $oException, $oException->getAlertFromStatus());
+ }
+ else
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError, $oException);
+ }
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError, $oException);
+ }
+ }
+
+ /**
+ * @param string $sEmail
+ * @param string $sPassword
+ * @param string $sSignMeToken = ''
+ * @param string $sAdditionalCode = ''
+ * @param string $bAdditionalCodeSignMe = false
+ *
+ * @return \RainLoop\Model\Account
+ * @throws \RainLoop\Exceptions\ClientException
+ */
+ public function LoginProcess(&$sEmail, &$sPassword, $sSignMeToken = '',
+ $sAdditionalCode = '', $bAdditionalCodeSignMe = false)
+ {
+ $this->Plugins()->RunHook('filter.login-credentials.step-1', array(&$sEmail, &$sPassword));
+
+ $sEmail = \MailSo\Base\Utils::StrToLowerIfAscii(\MailSo\Base\Utils::Trim($sEmail));
+
+ if (false === \strpos($sEmail, '@'))
+ {
+ $this->Logger()->Write('The email address "'.$sEmail.'" is not complete', \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
+
+ if (false === \strpos($sEmail, '@') && !!$this->Config()->Get('login', 'determine_user_domain', false))
+ {
+ $sUserHost = \trim($this->Http()->GetHost(false, true, true));
+ $this->Logger()->Write('Determined user domain: '.$sUserHost, \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
+
+ $bAdded = false;
+
+ $iLimit = 14;
+ $aDomainParts = \explode('.', $sUserHost);
+
+ $oDomainProvider = $this->DomainProvider();
+ while (0 < \count($aDomainParts) && 0 < $iLimit)
+ {
+ $sLine = \trim(\implode('.', $aDomainParts), '. ');
+
+ $oDomain = $oDomainProvider->Load($sLine, false);
+ if ($oDomain && $oDomain instanceof \RainLoop\Model\Domain)
+ {
+ $bAdded = true;
+ $this->Logger()->Write('Check "'.$sLine.'": OK ('.$sEmail.' > '.$sEmail.'@'.$sLine.')',
+ \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
+
+ $sEmail = $sEmail.'@'.$sLine;
+ break;
+ }
+ else
+ {
+ $this->Logger()->Write('Check "'.$sLine.'": NO', \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
+ }
+
+ \array_shift($aDomainParts);
+ $iLimit--;
+ }
+
+ if (!$bAdded)
+ {
+ $sLine = $sUserHost;
+ $oDomain = $oDomainProvider->Load($sLine, true);
+ if ($oDomain && $oDomain instanceof \RainLoop\Model\Domain)
+ {
+ $bAdded = true;
+ $this->Logger()->Write('Check "'.$sLine.'" with wildcard: OK ('.$sEmail.' > '.$sEmail.'@'.$sLine.')',
+ \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
+
+ $sEmail = $sEmail.'@'.$sLine;
+ }
+ else
+ {
+ $this->Logger()->Write('Check "'.$sLine.'" with wildcard: NO', \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
+ }
+ }
+
+ if (!$bAdded)
+ {
+ $this->Logger()->Write('Domain was not found!', \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
+ }
+ }
+
+ $sDefDomain = \trim($this->Config()->Get('login', 'default_domain', ''));
+ if (false === \strpos($sEmail, '@') && 0 < \strlen($sDefDomain))
+ {
+ $this->Logger()->Write('Default domain "'.$sDefDomain.'" was used. ('.$sEmail.' > '.$sEmail.'@'.$sDefDomain.')',
+ \MailSo\Log\Enumerations\Type::INFO, 'LOGIN');
+
+ $sEmail = $sEmail.'@'.$sDefDomain;
+ }
+ }
+
+ $this->Plugins()->RunHook('filter.login-credentials.step-2', array(&$sEmail, &$sPassword));
+
+ if (false === \strpos($sEmail, '@') || 0 === \strlen($sPassword))
+ {
+ $this->loginErrorDelay();
+
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidInputArgument);
+ }
+
+ $this->Logger()->AddSecret($sPassword);
+
+ $sLogin = $sEmail;
+ $this->Plugins()->RunHook('filter.login-credentials', array(&$sEmail, &$sLogin, &$sPassword));
+
+ $this->Logger()->AddSecret($sPassword);
+
+ $this->Plugins()->RunHook('event.login-pre-login-provide', array());
+
+ $oAccount = null;
+
+ try
+ {
+ $oAccount = $this->LoginProvide($sEmail, $sLogin, $sPassword, $sSignMeToken, true);
+
+ if (!($oAccount instanceof \RainLoop\Model\Account))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
+ }
+
+ $this->Plugins()->RunHook('event.login-post-login-provide', array(&$oAccount));
+
+ if (!($oAccount instanceof \RainLoop\Model\Account))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->loginErrorDelay();
+
+ $this->LoggerAuthHelper($oAccount);
+
+ throw $oException;
+ }
+
+ // Two factor auth
+ if ($this->TwoFactorAuthProvider()->IsActive())
+ {
+ $aData = $this->getTwoFactorInfo($oAccount);
+ if ($aData && isset($aData['IsSet'], $aData['Enable']) && !empty($aData['Secret']) && $aData['IsSet'] && $aData['Enable'])
+ {
+ $sSecretHash = \md5(APP_SALT.$aData['Secret'].\RainLoop\Utils::Fingerprint());
+ $sSecretCookieHash = \RainLoop\Utils::GetCookie(self::AUTH_TFA_SIGN_ME_TOKEN_KEY, '');
+
+ if (empty($sSecretCookieHash) || $sSecretHash !== $sSecretCookieHash)
+ {
+ $sAdditionalCode = \trim($sAdditionalCode);
+ if (empty($sAdditionalCode))
+ {
+ $this->Logger()->Write('TFA: Required Code for '.$oAccount->ParentEmailHelper().' account.');
+
+ $this->LoggerAuthHelper($oAccount);
+
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AccountTwoFactorAuthRequired);
+ }
+ else
+ {
+ $this->Logger()->Write('TFA: Verify Code for '.$oAccount->ParentEmailHelper().' account.');
+
+ $bGood = false;
+ if (6 < \strlen($sAdditionalCode) && !empty($aData['BackupCodes']))
+ {
+ $aBackupCodes = \explode(' ', \trim(\preg_replace('/[^\d]+/', ' ', $aData['BackupCodes'])));
+ $bGood = \in_array($sAdditionalCode, $aBackupCodes);
+
+ if ($bGood)
+ {
+ $this->removeBackupCodeFromTwoFactorInfo($oAccount->ParentEmailHelper(), $sAdditionalCode);
+ }
+ }
+
+ if ($bAdditionalCodeSignMe)
+ {
+ \RainLoop\Utils::SetCookie(self::AUTH_TFA_SIGN_ME_TOKEN_KEY, $sSecretHash,
+ \time() + 60 * 60 * 24 * 14);
+ }
+
+ if (!$bGood && !$this->TwoFactorAuthProvider()->VerifyCode($aData['Secret'], $sAdditionalCode))
+ {
+ $this->loginErrorDelay();
+
+ $this->LoggerAuthHelper($oAccount);
+
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AccountTwoFactorAuthError);
+ }
+ }
+ }
+ }
+ }
+
+ try
+ {
+ $this->CheckMailConnection($oAccount, true);
+ }
+ catch (\Exception $oException)
+ {
+ $this->loginErrorDelay();
+
+ throw $oException;
+ }
+
+ return $oAccount;
+ }
+
+ /**
+ * @param string $sEncryptedData
+ *
+ * @return string
+ */
+ private function clientRsaDecryptHelper($sEncryptedData)
+ {
+// $aMatch = array();
+// if ('rsa:xxx:' === \substr($sEncryptedData, 0, 8) && $this->Config()->Get('security', 'use_rsa_encryption', false))
+// {
+// $oLogger = $this->Logger();
+// $oLogger->Write('Trying to decode encrypted data', \MailSo\Log\Enumerations\Type::INFO, 'RSA');
+// $oLogger->HideErrorNotices(true);
+//
+// $sData = \trim(\substr($sEncryptedData, 8));
+// $sData = \RainLoop\Utils::DecryptStringRSA(\base64_decode($sData));
+//
+// if (false !== $sData && \preg_match('/^[a-z0-9]{32}:(.+):[a-z0-9]{32}$/', $sData, $aMatch) && isset($aMatch[1]))
+// {
+// $sEncryptedData = $aMatch[1];
+// }
+// else
+// {
+// $oLogger->Write('Invalid decrypted data', \MailSo\Log\Enumerations\Type::WARNING, 'RSA');
+// }
+//
+// $oLogger->HideErrorNotices(false);
+// }
+
+ return $sEncryptedData;
+ }
+
+ /**
+ * @param string $sEmail
+ *
+ * @return string
+ */
+ private function generateSignMeToken($sEmail)
+ {
+ return \MailSo\Base\Utils::Md5Rand(APP_SALT.$sEmail);
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoLogin()
+ {
+ $sEmail = \MailSo\Base\Utils::Trim($this->GetActionParam('Email', ''));
+ $sPassword = $this->GetActionParam('Password', '');
+ $sLanguage = $this->GetActionParam('Language', '');
+ $bSignMe = '1' === (string) $this->GetActionParam('SignMe', '0');
+
+ $sAdditionalCode = $this->GetActionParam('AdditionalCode', '');
+ $bAdditionalCodeSignMe = '1' === (string) $this->GetActionParam('AdditionalCodeSignMe', '0');
+
+ $oAccount = null;
+
+ $sPassword = $this->clientRsaDecryptHelper($sPassword);
+ $this->Logger()->AddSecret($sPassword);
+
+ if (0 < \strlen($sEmail) && 0 < \strlen($sPassword) &&
+ $this->Config()->Get('security', 'allow_universal_login', true) &&
+ $this->Config()->Get('security', 'allow_admin_panel', true) &&
+ $sEmail === $this->Config()->Get('security', 'admin_login', '')
+ )
+ {
+ if ($this->Config()->ValidatePassword($sPassword))
+ {
+ $this->setAdminAuthToken($this->getAdminToken());
+
+ return $this->DefaultResponse(__FUNCTION__, true, array(
+ 'Admin' => true
+ ));
+ }
+ else
+ {
+ $this->loginErrorDelay();
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
+ }
+ }
+ else if ('sleep@sleep.dev' === $sEmail && 0 < \strlen($sPassword) &&
+ \is_numeric($sPassword) && $this->Config()->Get('debug', 'enable', false)
+ )
+ {
+ \sleep((int) $sPassword);
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
+ }
+
+ try
+ {
+ $oAccount = $this->LoginProcess($sEmail, $sPassword,
+ $bSignMe ? $this->generateSignMeToken($sEmail) : '',
+ $sAdditionalCode, $bAdditionalCodeSignMe);
+ }
+ catch (\RainLoop\Exceptions\ClientException $oException)
+ {
+ if ($oException &&
+ \RainLoop\Notifications::AccountTwoFactorAuthRequired === $oException->getCode())
+ {
+ return $this->DefaultResponse(__FUNCTION__, true, array(
+ 'TwoFactorAuth' => true
+ ));
+ }
+ else
+ {
+ throw $oException;
+ }
+ }
+
+ $this->AuthToken($oAccount);
+
+ if ($oAccount && 0 < \strlen($sLanguage))
+ {
+ $oSettings = $this->SettingsProvider()->Load($oAccount);
+ if ($oSettings)
+ {
+ $sLanguage = $this->ValidateLanguage($sLanguage);
+ $sCurrentLanguage = $oSettings->GetConf('Language', '');
+
+ if ($sCurrentLanguage !== $sLanguage)
+ {
+ $oSettings->SetConf('Language', $sLanguage);
+ $this->SettingsProvider()->Save($oAccount, $oSettings);
+ }
+ }
+ }
+
+ return $this->TrueResponse(__FUNCTION__);
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ *
+ * @return array
+ */
+ public function GetAccounts($oAccount)
+ {
+ if ($this->GetCapa(false, false, \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount))
+ {
+ $sAccounts = $this->StorageProvider()->Get($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'accounts'
+ );
+
+ $aAccounts = array();
+ if ('' !== $sAccounts && '{' === \substr($sAccounts, 0, 1))
+ {
+ $aAccounts = @\json_decode($sAccounts, true);
+ }
+
+ if (\is_array($aAccounts) && 0 < \count($aAccounts))
+ {
+ if (1 === \count($aAccounts))
+ {
+ $this->SetAccounts($oAccount, array());
+
+ }
+ else if (1 < \count($aAccounts))
+ {
+ $sOrder = $this->StorageProvider()->Get($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'accounts_identities_order'
+ );
+
+ $aOrder = empty($sOrder) ? array() : @\json_decode($sOrder, true);
+ if (isset($aOrder['Accounts']) && \is_array($aOrder['Accounts']) &&
+ 1 < \count($aOrder['Accounts']))
+ {
+ $aAccounts = \array_merge(\array_flip($aOrder['Accounts']), $aAccounts);
+
+ $aAccounts = \array_filter($aAccounts, function ($sHash) {
+ return 5 < \strlen($sHash);
+ });
+ }
+ }
+
+ return $aAccounts;
+ }
+ }
+
+ $aAccounts = array();
+ if (!$oAccount->IsAdditionalAccount())
+ {
+ $aAccounts[$oAccount->Email()] = $oAccount->GetAuthToken();
+ }
+
+ return $aAccounts;
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ *
+ * @return array
+ */
+ public function GetTemplates($oAccount)
+ {
+ $aTemplates = array();
+ if ($oAccount)
+ {
+ $aData = array();
+
+ $sData = $this->StorageProvider(true)->Get($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'templates'
+ );
+
+ if ('' !== $sData && '[' === \substr($sData, 0, 1))
+ {
+ $aData = @\json_decode($sData, true);
+ }
+
+ if (\is_array($aData) && 0 < \count($aData))
+ {
+ foreach ($aData as $aItem)
+ {
+ $oItem = \RainLoop\Model\Template::NewInstance();
+ $oItem->FromJSON($aItem);
+
+ if ($oItem && $oItem->Validate())
+ {
+ \array_push($aTemplates, $oItem);
+ }
+ }
+ }
+
+ if (1 < \count($aTemplates))
+ {
+ $sOrder = $this->StorageProvider()->Get($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'templates_order'
+ );
+
+ $aOrder = empty($sOrder) ? array() : @\json_decode($sOrder, true);
+ if (\is_array($aOrder) && 1 < \count($aOrder))
+ {
+ \usort($aTemplates, function ($a, $b) use ($aOrder) {
+ return \array_search($a->Id(), $aOrder) < \array_search($b->Id(), $aOrder) ? -1 : 1;
+ });
+ }
+ }
+ }
+
+ return $aTemplates;
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ * @param string $sID
+ *
+ * @return \RainLoop\Model\Identity
+ */
+ public function GetTemplateByID($oAccount, $sID)
+ {
+ $aTemplates = $this->GetTemplates($oAccount);
+ if (\is_array($aTemplates))
+ {
+ foreach ($aTemplates as $oIdentity)
+ {
+ if ($oIdentity && $sID === $oIdentity->Id())
+ {
+ return $oIdentity;
+ }
+ }
+ }
+
+ return isset($aTemplates[0]) ? $aTemplates[0] : null;
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ *
+ * @return array
+ */
+ public function GetIdentities($oAccount)
+ {
+ $bAllowIdentities = $this->GetCapa(false, false,
+ \RainLoop\Enumerations\Capa::IDENTITIES, $oAccount);
+
+ $aIdentities = array();
+ if ($oAccount)
+ {
+ $aSubIdentities = array();
+
+ $sData = $this->StorageProvider(true)->Get($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'identities'
+ );
+
+ if ('' !== $sData && '[' === \substr($sData, 0, 1))
+ {
+ $aSubIdentities = @\json_decode($sData, true);
+ }
+
+ $bHasAccountIdentity = false;
+
+ if (\is_array($aSubIdentities) && 0 < \count($aSubIdentities))
+ {
+ foreach ($aSubIdentities as $aItem)
+ {
+ $oItem = \RainLoop\Model\Identity::NewInstance();
+ $oItem->FromJSON($aItem);
+
+ if ($oItem && $oItem->Validate())
+ {
+ if ($oItem->IsAccountIdentities())
+ {
+ $oItem->SetEmail($oAccount->Email());
+ $bHasAccountIdentity = true;
+
+ \array_push($aIdentities, $oItem);
+ }
+ else if ($bAllowIdentities)
+ {
+ \array_push($aIdentities, $oItem);
+ }
+ }
+ }
+ }
+
+ if (!$bHasAccountIdentity)
+ {
+ \array_unshift($aIdentities,
+ \RainLoop\Model\Identity::NewInstanceFromAccount($oAccount));
+ }
+
+ if (1 < \count($aIdentities) && $bAllowIdentities)
+ {
+ $sOrder = $this->StorageProvider()->Get($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'accounts_identities_order'
+ );
+
+ $aOrder = empty($sOrder) ? array() : @\json_decode($sOrder, true);
+ if (isset($aOrder['Identities']) && \is_array($aOrder['Identities']) &&
+ 1 < \count($aOrder['Identities']))
+ {
+ $aList = $aOrder['Identities'];
+ foreach ($aList as $iIndex => $sItem)
+ {
+ if ('' === $sItem)
+ {
+ $aList[$iIndex] = '---';
+ }
+ }
+
+ \usort($aIdentities, function ($a, $b) use ($aList) {
+ return \array_search($a->Id(true), $aList) < \array_search($b->Id(true), $aList) ? -1 : 1;
+ });
+ }
+ }
+ }
+
+ return $aIdentities;
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ * @param string $sID
+ * @param bool $bFirstOnEmpty = false
+ *
+ * @return \RainLoop\Model\Identity
+ */
+ public function GetIdentityByID($oAccount, $sID, $bFirstOnEmpty = false)
+ {
+ $aIdentities = $this->GetIdentities($oAccount);
+
+ if (\is_array($aIdentities))
+ {
+ foreach ($aIdentities as $oIdentity)
+ {
+ if ($oIdentity && $sID === $oIdentity->Id())
+ {
+ return $oIdentity;
+ }
+ }
+ }
+
+ return $bFirstOnEmpty && \is_array($aIdentities) && isset($aIdentities[0]) ? $aIdentities[0] : null;
+ }
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ *
+ * @return \RainLoop\Model\Identity
+ */
+ public function GetAccountIdentity($oAccount)
+ {
+ return $this->GetIdentityByID($oAccount, '', true);
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ * @param array $aAccounts = array()
+ *
+ * @return array
+ */
+ public function SetAccounts($oAccount, $aAccounts = array())
+ {
+ $sParentEmail = $oAccount->ParentEmailHelper();
+ if (!\is_array($aAccounts) || 0 >= \count($aAccounts) ||
+ (1 === \count($aAccounts) && !empty($aAccounts[$sParentEmail])))
+ {
+ $this->StorageProvider()->Clear($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'accounts'
+ );
+ }
+ else
+ {
+ $this->StorageProvider()->Put($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'accounts',
+ @\json_encode($aAccounts)
+ );
+ }
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ * @param array $aIdentities = array()
+ *
+ * @return array
+ */
+ public function SetIdentities($oAccount, $aIdentities = array())
+ {
+ $bAllowIdentities = $this->GetCapa(false, false, \RainLoop\Enumerations\Capa::IDENTITIES, $oAccount);
+
+ $aResult = array();
+ foreach ($aIdentities as $oItem)
+ {
+ if (!$bAllowIdentities && $oItem && !$oItem->IsAccountIdentities())
+ {
+ continue;
+ }
+
+ $aResult[] = $oItem->ToSimpleJSON(false);
+ }
+
+ return $this->StorageProvider(true)->Put($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'identities',
+ @\json_encode($aResult)
+ );
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ * @param array $aTemplates = array()
+ *
+ * @return array
+ */
+ public function SetTemplates($oAccount, $aTemplates = array())
+ {
+ $aResult = array();
+ foreach ($aTemplates as $oItem)
+ {
+ $aResult[] = $oItem->ToSimpleJSON(false);
+ }
+
+ return $this->StorageProvider(true)->Put($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'templates',
+ @\json_encode($aResult)
+ );
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoFilters()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FILTERS, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $aFakeFilters = null;
+
+ $this->Plugins()
+ ->RunHook('filter.filters-fake', array($oAccount, &$aFakeFilters))
+ ;
+
+ if ($aFakeFilters)
+ {
+ return $this->DefaultResponse(__FUNCTION__, $aFakeFilters);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__,
+ $this->FiltersProvider()->Load($oAccount, $oAccount->DomainSieveAllowRaw()));
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoFiltersSave()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FILTERS, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $aIncFilters = $this->GetActionParam('Filters', array());
+
+ $sRaw = $this->GetActionParam('Raw', '');
+ $bRawIsActive = '1' === (string) $this->GetActionParam('RawIsActive', '0');
+
+ $aFilters = array();
+ foreach ($aIncFilters as $aFilter)
+ {
+ if ($aFilter)
+ {
+ $oFilter = new \RainLoop\Providers\Filters\Classes\Filter();
+ if ($oFilter->FromJSON($aFilter))
+ {
+ $aFilters[] = $oFilter;
+ }
+ }
+ }
+
+ $this->Plugins()
+ ->RunHook('filter.filters-save', array($oAccount, &$aFilters, &$sRaw, &$bRawIsActive))
+ ;
+
+ return $this->DefaultResponse(__FUNCTION__, $this->FiltersProvider()->Save($oAccount,
+ $aFilters, $sRaw, $bRawIsActive));
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoAccountSetup()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $sParentEmail = $oAccount->ParentEmailHelper();
+
+ $aAccounts = $this->GetAccounts($oAccount);
+ if (!\is_array($aAccounts))
+ {
+ $aAccounts = array();
+ }
+
+ $sEmail = \trim($this->GetActionParam('Email', ''));
+ $sPassword = $this->GetActionParam('Password', '');
+ $bNew = '1' === (string) $this->GetActionParam('New', '1');
+
+ $sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail, true);
+ if ($bNew && ($oAccount->Email() === $sEmail || $sParentEmail === $sEmail || isset($aAccounts[$sEmail])))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AccountAlreadyExists);
+ }
+ else if (!$bNew && !isset($aAccounts[$sEmail]))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AccountDoesNotExist);
+ }
+
+ $oNewAccount = $this->LoginProcess($sEmail, $sPassword);
+ $oNewAccount->SetParentEmail($sParentEmail);
+
+ $aAccounts[$oNewAccount->Email()] = $oNewAccount->GetAuthToken();
+ if (!$oAccount->IsAdditionalAccount())
+ {
+ $aAccounts[$oAccount->Email()] = $oAccount->GetAuthToken();
+ }
+
+ $this->SetAccounts($oAccount, $aAccounts);
+ return $this->TrueResponse(__FUNCTION__);
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoAccountDelete()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $sParentEmail = $oAccount->ParentEmailHelper();
+ $sEmailToDelete = \trim($this->GetActionParam('EmailToDelete', ''));
+ $sEmailToDelete = \MailSo\Base\Utils::IdnToAscii($sEmailToDelete, true);
+
+ $aAccounts = $this->GetAccounts($oAccount);
+
+ if (0 < \strlen($sEmailToDelete) && $sEmailToDelete !== $sParentEmail && \is_array($aAccounts) && isset($aAccounts[$sEmailToDelete]))
+ {
+ unset($aAccounts[$sEmailToDelete]);
+
+ $oAccountToChange = null;
+ if ($oAccount->Email() === $sEmailToDelete && !empty($aAccounts[$sParentEmail]))
+ {
+ $oAccountToChange = $this->GetAccountFromCustomToken($aAccounts[$sParentEmail], false, false);
+ if ($oAccountToChange)
+ {
+ $this->AuthToken($oAccountToChange);
+ }
+ }
+
+ $this->SetAccounts($oAccount, $aAccounts);
+ return $this->TrueResponse(__FUNCTION__, array('Reload' => !!$oAccountToChange));
+ }
+
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoAttachmentsActions()
+ {
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::ATTACHMENTS_ACTIONS))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $oAccount = $this->initMailClientConnection();
+
+ $sAction = $this->GetActionParam('Do', '');
+ $aHashes = $this->GetActionParam('Hashes', null);
+
+ $mResult = false;
+ $bError = false;
+ $aData = false;
+
+ if (\is_array($aHashes) && 0 < \count($aHashes))
+ {
+ $aData = array();
+ foreach ($aHashes as $sZipHash)
+ {
+ $aResult = $this->getMimeFileByHash($oAccount, $sZipHash);
+ if (\is_array($aResult) && !empty($aResult['FileHash']))
+ {
+ $aData[] = $aResult;
+ }
+ else
+ {
+ $bError = true;
+ break;
+ }
+ }
+ }
+
+ $oFilesProvider = $this->FilesProvider();
+ if (!empty($sAction) && !$bError && \is_array($aData) && 0 < \count($aData) &&
+ $oFilesProvider && $oFilesProvider->IsActive())
+ {
+
+ $bError = false;
+ switch (\strtolower($sAction))
+ {
+ case 'zip':
+
+ if (\class_exists('ZipArchive'))
+ {
+ $sZipHash = \MailSo\Base\Utils::Md5Rand();
+ $sZipFileName = $oFilesProvider->GenerateLocalFullFileName($oAccount, $sZipHash);
+
+ if (!empty($sZipFileName))
+ {
+ $oZip = new \ZipArchive();
+ $oZip->open($sZipFileName, \ZIPARCHIVE::CREATE | \ZIPARCHIVE::OVERWRITE);
+ $oZip->setArchiveComment('RainLoop/'.APP_VERSION);
+
+ foreach ($aData as $aItem)
+ {
+ $sFileName = (string) (isset($aItem['FileName']) ? $aItem['FileName'] : 'file.dat');
+ $sFileHash = (string) (isset($aItem['FileHash']) ? $aItem['FileHash'] : '');
+
+ if (!empty($sFileHash))
+ {
+ $sFullFileNameHash = $oFilesProvider->GetFileName($oAccount, $sFileHash);
+ if (!$oZip->addFile($sFullFileNameHash, $sFileName))
+ {
+ $bError = true;
+ }
+ }
+ }
+
+ if (!$bError)
+ {
+ $bError = !$oZip->close();
+ }
+ else
+ {
+ $oZip->close();
+ }
+ }
+
+ foreach ($aData as $aItem)
+ {
+ $sFileHash = (string) (isset($aItem['FileHash']) ? $aItem['FileHash'] : '');
+ if (!empty($sFileHash))
+ {
+ $oFilesProvider->Clear($oAccount, $sFileHash);
+ }
+ }
+
+ if (!$bError)
+ {
+ $mResult = array(
+ 'Files' => array(array(
+ 'FileName' => 'attachments.zip',
+ 'Hash' => \RainLoop\Utils::EncodeKeyValuesQ(array(
+ 'V' => APP_VERSION,
+ 'Account' => $oAccount ? \md5($oAccount->Hash()) : '',
+ 'FileName' => 'attachments.zip',
+ 'MimeType' => 'application/zip',
+ 'FileHash' => $sZipHash
+ ))
+ ))
+ );
+ }
+ }
+ break;
+
+ case 'owncloud':
+
+ $mResult = false;
+
+ if (\RainLoop\Utils::IsOwnCloudLoggedIn() && \class_exists('OCP\Files'))
+ {
+ $sSaveFolder = $this->Config()->Get('labs', 'owncloud_save_folder', '');
+ if (empty($sSaveFolder))
+ {
+ $sSaveFolder = 'Attachments';
+ }
+
+ $oFiles = \OCP\Files::getStorage('files');
+
+ if ($oFilesProvider && $oFiles && $oFilesProvider->IsActive() &&
+ \method_exists($oFiles, 'file_put_contents'))
+ {
+ if (!$oFiles->is_dir($sSaveFolder))
+ {
+ $oFiles->mkdir($sSaveFolder);
+ }
+
+ $mResult = true;
+ foreach ($aData as $aItem)
+ {
+ $sSavedFileName = isset($aItem['FileName']) ? $aItem['FileName'] : 'file.dat';
+ $sSavedFileHash = !empty($aItem['FileHash']) ? $aItem['FileHash'] : '';
+
+ if (!empty($sSavedFileHash))
+ {
+ $fFile = $oFilesProvider->GetFile($oAccount, $sSavedFileHash, 'rb');
+ if (\is_resource($fFile))
+ {
+ $sSavedFileNameFull = \MailSo\Base\Utils::SmartFileExists($sSaveFolder.'/'.$sSavedFileName, function ($sPath) use ($oFiles) {
+ return $oFiles->file_exists($sPath);
+ });
+
+ if (!$oFiles->file_put_contents($sSavedFileNameFull, $fFile))
+ {
+ $mResult = false;
+ }
+
+ if (\is_resource($fFile))
+ {
+ @\fclose($fFile);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ foreach ($aData as $aItem)
+ {
+ $sFileHash = (string) (isset($aItem['FileHash']) ? $aItem['FileHash'] : '');
+ if (!empty($sFileHash))
+ {
+ $oFilesProvider->Clear($oAccount, $sFileHash);
+ }
+ }
+
+ break;
+
+ case 'dropbox':
+
+ $mResult = array(
+ 'ShortLife' => '_'.$this->GetShortLifeSpecAuthToken(),
+ 'Url' => \preg_replace('/\?(.*)$/', '', $this->Http()->GetFullUrl()),
+ 'Files' => array()
+ );
+
+ foreach ($aData as $aItem)
+ {
+ $mResult['Files'][] = array(
+ 'FileName' => isset($aItem['FileName']) ? $aItem['FileName'] : 'file.dat',
+ 'Hash' => \RainLoop\Utils::EncodeKeyValuesQ($aItem)
+ );
+ }
+
+ break;
+ }
+ }
+ else
+ {
+ $bError = true;
+ }
+
+ $this->requestSleep();
+ return $this->DefaultResponse(__FUNCTION__, $bError ? false : $mResult);
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoIdentityUpdate()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ $oIdentity = \RainLoop\Model\Identity::NewInstance();
+ if (!$oIdentity->FromJSON($this->GetActionParams(), true))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidInputArgument);
+ }
+
+ $aIdentities = $this->GetIdentities($oAccount);
+
+ $bAdded = false;
+ $aIdentitiesForSave = array();
+ foreach ($aIdentities as $oItem)
+ {
+ if ($oItem)
+ {
+ if ($oItem->Id() === $oIdentity->Id())
+ {
+ $aIdentitiesForSave[] = $oIdentity;
+ $bAdded = true;
+ }
+ else
+ {
+ $aIdentitiesForSave[] = $oItem;
+ }
+ }
+ }
+
+ if (!$bAdded)
+ {
+ $aIdentitiesForSave[] = $oIdentity;
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $this->SetIdentities($oAccount, $aIdentitiesForSave));
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoIdentityDelete()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::IDENTITIES, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $sId = \trim($this->GetActionParam('IdToDelete', ''));
+ if (empty($sId))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
+ }
+
+ $aNew = array();
+ $aIdentities = $this->GetIdentities($oAccount);
+
+ foreach ($aIdentities as $oItem)
+ {
+ if ($oItem && $sId !== $oItem->Id())
+ {
+ $aNew[] = $oItem;
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $this->SetIdentities($oAccount, $aNew));
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoTemplateSetup()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $oTemplate = \RainLoop\Model\Template::NewInstance();
+ if (!$oTemplate->FromJSON($this->GetActionParams(), true))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidInputArgument);
+ }
+
+ if ('' === $oTemplate->Id())
+ {
+ $oTemplate->GenerateID();
+ }
+
+ $aTemplatesForSave = array();
+ $aTemplates = $this->GetTemplates($oAccount);
+
+
+ foreach ($aTemplates as $oItem)
+ {
+ if ($oItem && $oItem->Id() !== $oTemplate->Id())
+ {
+ $aTemplatesForSave[] = $oItem;
+ }
+ }
+
+ $aTemplatesForSave[] = $oTemplate;
+
+ return $this->DefaultResponse(__FUNCTION__, $this->SetTemplates($oAccount, $aTemplatesForSave));
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoTemplateDelete()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $sId = \trim($this->GetActionParam('IdToDelete', ''));
+ if (empty($sId))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
+ }
+
+ $aNew = array();
+ $aTemplates = $this->GetTemplates($oAccount);
+ foreach ($aTemplates as $oItem)
+ {
+ if ($oItem && $sId !== $oItem->Id())
+ {
+ $aNew[] = $oItem;
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $this->SetTemplates($oAccount, $aNew));
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoTemplateGetByID()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $sId = \trim($this->GetActionParam('ID', ''));
+ if (empty($sId))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
+ }
+
+ $oTemplate = false;
+ $aTemplates = $this->GetTemplates($oAccount);
+
+ foreach ($aTemplates as $oItem)
+ {
+ if ($oItem && $sId === $oItem->Id())
+ {
+ $oTemplate = $oItem;
+ break;
+ }
+ }
+
+ $oTemplate->SetPopulateAlways(true);
+ return $this->DefaultResponse(__FUNCTION__, $oTemplate);
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoAccountsAndIdentitiesSortOrder()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ $aAccounts = $this->GetActionParam('Accounts', null);
+ $aIdentities = $this->GetActionParam('Identities', null);
+
+ if (!\is_array($aAccounts) && !\is_array($aIdentities))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $this->StorageProvider()->Put($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG, 'accounts_identities_order',
+ \json_encode(array(
+ 'Accounts' => \is_array($aAccounts) ? $aAccounts : array(),
+ 'Identities' => \is_array($aIdentities) ? $aIdentities : array()
+ ))
+ ));
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoAccountsAndIdentities()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ $mAccounts = false;
+
+ if ($this->GetCapa(false, false, \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount))
+ {
+ $mAccounts = $this->GetAccounts($oAccount);
+ $mAccounts = \array_keys($mAccounts);
+
+ foreach ($mAccounts as $iIndex => $sName)
+ {
+ $mAccounts[$iIndex] = \MailSo\Base\Utils::IdnToUtf8($sName);
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, array(
+ 'Accounts' => $mAccounts,
+ 'Identities' => $this->GetIdentities($oAccount)
+ ));
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoTemplates()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, array(
+ 'Templates' => $this->GetTemplates($oAccount)
+ ));
+ }
+
+ /**
+ * @param string $sHash
+ *
+ * @return int
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function getAccountUnredCountFromHash($sHash)
+ {
+ $iResult = 0;
+
+ $oAccount = $this->GetAccountFromCustomToken($sHash, false);
+ if ($oAccount)
+ {
+ try
+ {
+ $oMailClient = \MailSo\Mail\MailClient::NewInstance();
+ $oMailClient->SetLogger($this->Logger());
+
+ $oAccount->IncConnectAndLoginHelper($this->Plugins(),$oMailClient, $this->Config());
+
+ $iResult = $oMailClient->InboxUnreadCount();
+
+ $oMailClient->LogoutAndDisconnect();
+ }
+ catch (\Exception $oException)
+ {
+ $this->Logger()->WriteException($oException);
+ }
+ }
+
+ return $iResult;
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoAccountsCounts()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ $bComplete = true;
+ $aCounts = array();
+
+ if ($this->GetCapa(false, false, \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount))
+ {
+ $iLimit = 7;
+ $mAccounts = $this->GetAccounts($oAccount);
+ if (\is_array($mAccounts) && 0 < \count($mAccounts))
+ {
+ if ($iLimit > \count($mAccounts))
+ {
+ $mAccounts = \array_slice($mAccounts, 0, $iLimit);
+ }
+ else
+ {
+ $bComplete = false;
+ }
+
+ if (0 < \count($mAccounts))
+ {
+ foreach ($mAccounts as $sEmail => $sHash)
+ {
+ $aCounts[] = array(\MailSo\Base\Utils::IdnToUtf8($sEmail),
+ $oAccount->Email() === $sEmail ? 0 : $this->getAccountUnredCountFromHash($sHash));
+ }
+ }
+ }
+ }
+ else
+ {
+ $aCounts[] = array(\MailSo\Base\Utils::IdnToUtf8($oAccount->Email()), 0);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, array(
+ 'Complete' => $bComplete,
+ 'Counts' => $aCounts
+ ));
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ */
+ public function ClearSignMeData($oAccount)
+ {
+ if ($oAccount)
+ {
+ \RainLoop\Utils::ClearCookie(\RainLoop\Actions::AUTH_SIGN_ME_TOKEN_KEY);
+
+ $this->StorageProvider()->Clear($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'sign_me'
+ );
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function DoLogout()
+ {
+ $oAccount = $this->getAccountFromToken(false);
+ if ($oAccount)
+ {
+ if ($oAccount->SignMe())
+ {
+ $this->ClearSignMeData($oAccount);
+ }
+
+ if (!$oAccount->IsAdditionalAccount())
+ {
+ \RainLoop\Utils::ClearCookie(\RainLoop\Actions::AUTH_SPEC_TOKEN_KEY);
+ }
+ }
+
+ return $this->TrueResponse(__FUNCTION__);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAppDelayStart()
+ {
+ $this->Plugins()->RunHook('service.app-delay-start-begin');
+
+ \RainLoop\Utils::UpdateConnectionToken();
+
+ $bMainCache = false;
+ $bFilesCache = false;
+ $bVersionsCache = false;
+
+ $iOneDay1 = 60 * 60 * 23;
+ $iOneDay2 = 60 * 60 * 25;
+ $iOneDay3 = 60 * 60 * 30;
+
+ $sTimers = $this->StorageProvider()->Get(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, 'Cache/Timers', '');
+
+ $aTimers = \explode(',', $sTimers);
+
+ $iMainCacheTime = !empty($aTimers[0]) && \is_numeric($aTimers[0]) ? (int) $aTimers[0] : 0;
+ $iFilesCacheTime = !empty($aTimers[1]) && \is_numeric($aTimers[1]) ? (int) $aTimers[1] : 0;
+ $iVersionsCacheTime = !empty($aTimers[2]) && \is_numeric($aTimers[2]) ? (int) $aTimers[2] : 0;
+
+ if (0 === $iMainCacheTime || $iMainCacheTime + $iOneDay1 < \time())
+ {
+ $bMainCache = true;
+ $iMainCacheTime = \time();
+ }
+
+ if (0 === $iFilesCacheTime || $iFilesCacheTime + $iOneDay2 < \time())
+ {
+ $bFilesCache = true;
+ $iFilesCacheTime = \time();
+ }
+
+ if (0 === $iVersionsCacheTime || $iVersionsCacheTime + $iOneDay3 < \time())
+ {
+ $bVersionsCache = true;
+ $iVersionsCacheTime = \time();
+ }
+
+ if ($bMainCache || $bFilesCache || $bVersionsCache)
+ {
+ if (!$this->StorageProvider()->Put(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, 'Cache/Timers',
+ \implode(',', array($iMainCacheTime, $iFilesCacheTime, $iVersionsCacheTime))))
+ {
+ $bMainCache = $bFilesCache = $bVersionsCache = false;
+ }
+ }
+
+ if ($bMainCache)
+ {
+ $this->Logger()->Write('Cacher GC: Begin');
+ $this->Cacher()->GC(48);
+ $this->Logger()->Write('Cacher GC: End');
+ }
+ else if ($bFilesCache)
+ {
+ $this->Logger()->Write('Files GC: Begin');
+ $this->FilesProvider()->GC(48);
+ $this->Logger()->Write('Files GC: End');
+ }
+ else if ($bVersionsCache)
+ {
+ $oPremProvider = $this->PremProvider();
+ if ($oPremProvider)
+ {
+ $oPremProvider->ClearOldVersion();
+ }
+ }
+
+ $this->Plugins()->RunHook('service.app-delay-start-end');
+
+ return $this->TrueResponse(__FUNCTION__);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoSystemFoldersUpdate()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ $oSettingsLocal = $this->SettingsProvider(true)->Load($oAccount);
+
+ $oSettingsLocal->SetConf('SentFolder', $this->GetActionParam('SentFolder', ''));
+ $oSettingsLocal->SetConf('DraftFolder', $this->GetActionParam('DraftFolder', ''));
+ $oSettingsLocal->SetConf('SpamFolder', $this->GetActionParam('SpamFolder', ''));
+ $oSettingsLocal->SetConf('TrashFolder', $this->GetActionParam('TrashFolder', ''));
+ $oSettingsLocal->SetConf('ArchiveFolder', $this->GetActionParam('ArchiveFolder', ''));
+ $oSettingsLocal->SetConf('NullFolder', $this->GetActionParam('NullFolder', ''));
+
+ return $this->DefaultResponse(__FUNCTION__,
+ $this->SettingsProvider(true)->Save($oAccount, $oSettingsLocal));
+ }
+
+ /**
+ * @param \RainLoop\Config\Application $oConfig
+ * @param string $sParamName
+ * @param string $sConfigSector
+ * @param string $sConfigName
+ * @param string $sType = 'string'
+ * @param callable|null $mStringCallback = null
+ */
+ public function setConfigFromParams(&$oConfig, $sParamName, $sConfigSector, $sConfigName, $sType = 'string', $mStringCallback = null)
+ {
+ $sValue = $this->GetActionParam($sParamName, '');
+ if ($this->HasActionParam($sParamName))
+ {
+ switch ($sType)
+ {
+ default:
+ case 'string':
+ $sValue = (string) $sValue;
+ if ($mStringCallback && is_callable($mStringCallback))
+ {
+ $sValue = call_user_func($mStringCallback, $sValue);
+ }
+
+ $oConfig->Set($sConfigSector, $sConfigName, (string) $sValue);
+ break;
+
+ case 'dummy':
+ $sValue = (string) $this->GetActionParam('ContactsPdoPassword', APP_DUMMY);
+ if (APP_DUMMY !== $sValue)
+ {
+ $oConfig->Set($sConfigSector, $sConfigName, (string) $sValue);
+ }
+ break;
+
+ case 'int':
+ $iValue = (int) $sValue;
+ $oConfig->Set($sConfigSector, $sConfigName, $iValue);
+ break;
+
+ case 'bool':
+ $oConfig->Set($sConfigSector, $sConfigName, '1' === (string) $sValue);
+ break;
+ }
+ }
+ }
+
+ /**
+ * @param \RainLoop\Config\Application $oConfig
+ * @param string $sParamName
+ * @param string $sCapa
+ */
+ private function setCapaFromParams(&$oConfig, $sParamName, $sCapa)
+ {
+ switch ($sCapa)
+ {
+ case \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS:
+ $this->setConfigFromParams($oConfig, $sParamName, 'webmail', 'allow_additional_accounts', 'bool');
+ break;
+ case \RainLoop\Enumerations\Capa::IDENTITIES:
+ $this->setConfigFromParams($oConfig, $sParamName, 'webmail', 'allow_additional_identities', 'bool');
+ break;
+ case \RainLoop\Enumerations\Capa::TEMPLATES:
+ $this->setConfigFromParams($oConfig, $sParamName, 'capa', 'x-templates', 'bool');
+ break;
+ case \RainLoop\Enumerations\Capa::TWO_FACTOR:
+ $this->setConfigFromParams($oConfig, $sParamName, 'security', 'allow_two_factor_auth', 'bool');
+ break;
+ case \RainLoop\Enumerations\Capa::TWO_FACTOR_FORCE:
+ $this->setConfigFromParams($oConfig, $sParamName, 'security', 'force_two_factor_auth', 'bool');
+ break;
+ case \RainLoop\Enumerations\Capa::GRAVATAR:
+ $this->setConfigFromParams($oConfig, $sParamName, 'labs', 'allow_gravatar', 'bool');
+ break;
+ case \RainLoop\Enumerations\Capa::ATTACHMENT_THUMBNAILS:
+ $this->setConfigFromParams($oConfig, $sParamName, 'interface', 'show_attachment_thumbnail', 'bool');
+ break;
+ case \RainLoop\Enumerations\Capa::THEMES:
+ $this->setConfigFromParams($oConfig, $sParamName, 'webmail', 'allow_themes', 'bool');
+ break;
+ case \RainLoop\Enumerations\Capa::USER_BACKGROUND:
+ $this->setConfigFromParams($oConfig, $sParamName, 'webmail', 'allow_user_background', 'bool');
+ break;
+ case \RainLoop\Enumerations\Capa::OPEN_PGP:
+ $this->setConfigFromParams($oConfig, $sParamName, 'security', 'openpgp', 'bool');
+ break;
+ }
+ }
+
+ /**
+ * @param \RainLoop\Settings $oSettings
+ * @param string $sConfigName
+ * @param string $sType = 'string'
+ * @param callable|null $mStringCallback = null
+ */
+ private function setSettingsFromParams(&$oSettings, $sConfigName, $sType = 'string', $mStringCallback = null)
+ {
+ if ($this->HasActionParam($sConfigName))
+ {
+ $sValue = $this->GetActionParam($sConfigName, '');
+ switch ($sType)
+ {
+ default:
+ case 'string':
+ $sValue = (string) $sValue;
+ if ($mStringCallback && is_callable($mStringCallback))
+ {
+ $sValue = call_user_func($mStringCallback, $sValue);
+ }
+
+ $oSettings->SetConf($sConfigName, (string) $sValue);
+ break;
+
+ case 'int':
+ $iValue = (int) $sValue;
+ $oSettings->SetConf($sConfigName, $iValue);
+ break;
+
+ case 'bool':
+ $oSettings->SetConf($sConfigName, '1' === (string) $sValue);
+ break;
+ }
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminSettingsUpdate()
+ {
+// sleep(3);
+// return $this->DefaultResponse(__FUNCTION__, false);
+
+ $this->IsAdminLoggined();
+
+ $oConfig = $this->Config();
+
+ $self = $this;
+
+ $this->setConfigFromParams($oConfig, 'Language', 'webmail', 'language', 'string', function ($sLanguage) use ($self) {
+ return $self->ValidateLanguage($sLanguage, '', false);
+ });
+
+ $this->setConfigFromParams($oConfig, 'LanguageAdmin', 'webmail', 'language_admin', 'string', function ($sLanguage) use ($self) {
+ return $self->ValidateLanguage($sLanguage, '', true);
+ });
+
+ $this->setConfigFromParams($oConfig, 'Theme', 'webmail', 'theme', 'string', function ($sTheme) use ($self) {
+ return $self->ValidateTheme($sTheme);
+ });
+
+ $this->setConfigFromParams($oConfig, 'VerifySslCertificate', 'ssl', 'verify_certificate', 'bool');
+ $this->setConfigFromParams($oConfig, 'AllowSelfSigned', 'ssl', 'allow_self_signed', 'bool');
+
+ $this->setConfigFromParams($oConfig, 'UseLocalProxyForExternalImages', 'labs', 'use_local_proxy_for_external_images', 'bool');
+
+ $this->setConfigFromParams($oConfig, 'AllowLanguagesOnSettings', 'webmail', 'allow_languages_on_settings', 'bool');
+ $this->setConfigFromParams($oConfig, 'AllowLanguagesOnLogin', 'login', 'allow_languages_on_login', 'bool');
+ $this->setConfigFromParams($oConfig, 'AttachmentLimit', 'webmail', 'attachment_size_limit', 'int');
+
+ $this->setConfigFromParams($oConfig, 'LoginDefaultDomain', 'login', 'default_domain', 'string');
+
+ $this->setConfigFromParams($oConfig, 'ContactsEnable', 'contacts', 'enable', 'bool');
+ $this->setConfigFromParams($oConfig, 'ContactsSharing', 'contacts', 'allow_sharing', 'bool');
+ $this->setConfigFromParams($oConfig, 'ContactsSync', 'contacts', 'allow_sync', 'bool');
+ $this->setConfigFromParams($oConfig, 'ContactsPdoDsn', 'contacts', 'pdo_dsn', 'string');
+ $this->setConfigFromParams($oConfig, 'ContactsPdoUser', 'contacts', 'pdo_user', 'string');
+ $this->setConfigFromParams($oConfig, 'ContactsPdoPassword', 'contacts', 'pdo_password', 'dummy');
+
+ $this->setConfigFromParams($oConfig, 'ContactsPdoType', 'contacts', 'type', 'string', function ($sType) use ($self) {
+ return $self->ValidateContactPdoType($sType);
+ });
+
+ $this->setCapaFromParams($oConfig, 'CapaAdditionalAccounts', \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS);
+ $this->setCapaFromParams($oConfig, 'CapaIdentities', \RainLoop\Enumerations\Capa::IDENTITIES);
+ $this->setCapaFromParams($oConfig, 'CapaTemplates', \RainLoop\Enumerations\Capa::TEMPLATES);
+ $this->setCapaFromParams($oConfig, 'CapaTwoFactorAuth', \RainLoop\Enumerations\Capa::TWO_FACTOR);
+ $this->setCapaFromParams($oConfig, 'CapaTwoFactorAuthForce', \RainLoop\Enumerations\Capa::TWO_FACTOR_FORCE);
+ $this->setCapaFromParams($oConfig, 'CapaOpenPGP', \RainLoop\Enumerations\Capa::OPEN_PGP);
+ $this->setCapaFromParams($oConfig, 'CapaGravatar', \RainLoop\Enumerations\Capa::GRAVATAR);
+ $this->setCapaFromParams($oConfig, 'CapaThemes', \RainLoop\Enumerations\Capa::THEMES);
+ $this->setCapaFromParams($oConfig, 'CapaUserBackground', \RainLoop\Enumerations\Capa::USER_BACKGROUND);
+ $this->setCapaFromParams($oConfig, 'CapaAttachmentThumbnails', \RainLoop\Enumerations\Capa::ATTACHMENT_THUMBNAILS);
+
+ $this->setConfigFromParams($oConfig, 'DetermineUserLanguage', 'login', 'determine_user_language', 'bool');
+ $this->setConfigFromParams($oConfig, 'DetermineUserDomain', 'login', 'determine_user_domain', 'bool');
+
+ $this->setConfigFromParams($oConfig, 'Title', 'webmail', 'title', 'string');
+ $this->setConfigFromParams($oConfig, 'LoadingDescription', 'webmail', 'loading_description', 'string');
+ $this->setConfigFromParams($oConfig, 'FaviconUrl', 'webmail', 'favicon_url', 'string');
+
+ $this->setConfigFromParams($oConfig, 'TokenProtection', 'security', 'csrf_protection', 'bool');
+ $this->setConfigFromParams($oConfig, 'EnabledPlugins', 'plugins', 'enable', 'bool');
+
+ $this->setConfigFromParams($oConfig, 'GoogleEnable', 'social', 'google_enable', 'bool');
+ $this->setConfigFromParams($oConfig, 'GoogleEnableAuth', 'social', 'google_enable_auth', 'bool');
+ $this->setConfigFromParams($oConfig, 'GoogleEnableAuthFast', 'social', 'google_enable_auth_fast', 'bool');
+ $this->setConfigFromParams($oConfig, 'GoogleEnableDrive', 'social', 'google_enable_drive', 'bool');
+ $this->setConfigFromParams($oConfig, 'GoogleEnablePreview', 'social', 'google_enable_preview', 'bool');
+ $this->setConfigFromParams($oConfig, 'GoogleClientID', 'social', 'google_client_id', 'string');
+ $this->setConfigFromParams($oConfig, 'GoogleClientSecret', 'social', 'google_client_secret', 'string');
+ $this->setConfigFromParams($oConfig, 'GoogleApiKey', 'social', 'google_api_key', 'string');
+
+ $this->setConfigFromParams($oConfig, 'FacebookEnable', 'social', 'fb_enable', 'bool');
+ $this->setConfigFromParams($oConfig, 'FacebookAppID', 'social', 'fb_app_id', 'string');
+ $this->setConfigFromParams($oConfig, 'FacebookAppSecret', 'social', 'fb_app_secret', 'string');
+
+ $this->setConfigFromParams($oConfig, 'TwitterEnable', 'social', 'twitter_enable', 'bool');
+ $this->setConfigFromParams($oConfig, 'TwitterConsumerKey', 'social', 'twitter_consumer_key', 'string');
+ $this->setConfigFromParams($oConfig, 'TwitterConsumerSecret', 'social', 'twitter_consumer_secret', 'string');
+
+ $this->setConfigFromParams($oConfig, 'DropboxEnable', 'social', 'dropbox_enable', 'bool');
+ $this->setConfigFromParams($oConfig, 'DropboxApiKey', 'social', 'dropbox_api_key', 'string');
+
+ $oPremProvider = $this->PremProvider();
+ if ($oPremProvider)
+ {
+ $oPremProvider->PremSection($this, $oConfig);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $oConfig->Save());
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoAdminLogin()
+ {
+ $sLogin = trim($this->GetActionParam('Login', ''));
+ $sPassword = $this->GetActionParam('Password', '');
+
+
+ //$this->Logger()->AddSecret($sPassword);
+ /*
+ if (0 === strlen($sLogin) || 0 === strlen($sPassword) ||
+ !$this->Config()->Get('security', 'allow_admin_panel', true) ||
+ $sLogin !== $this->Config()->Get('security', 'admin_login', '') ||
+ !$this->Config()->ValidatePassword($sPassword))
+ {
+ $this->loginErrorDelay();
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
+ }
+ */
+
+ $ewoMail = new \RainLoop\EwoMail();
+ if(!$ewoMail->is_login_panel($sLogin,$sPassword)){
+ $this->loginErrorDelay();
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
+ }
+
+ $sToken = $this->getAdminToken();
+ $this->setAdminAuthToken($sToken);
+
+ return $this->DefaultResponse(__FUNCTION__, $sToken ? true : false);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminLogout()
+ {
+ $this->ClearAdminAuthToken();
+ return $this->TrueResponse(__FUNCTION__);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminPing()
+ {
+ $this->IsAdminLoggined();
+
+ return $this->DefaultResponse(__FUNCTION__, true);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminContactsTest()
+ {
+ $this->IsAdminLoggined();
+
+ $oConfig = $this->Config();
+
+ $this->setConfigFromParams($oConfig, 'ContactsPdoDsn', 'contacts', 'pdo_dsn', 'string');
+ $this->setConfigFromParams($oConfig, 'ContactsPdoUser', 'contacts', 'pdo_user', 'string');
+ $this->setConfigFromParams($oConfig, 'ContactsPdoPassword', 'contacts', 'pdo_password', 'dummy');
+
+ $self = $this;
+ $this->setConfigFromParams($oConfig, 'ContactsPdoType', 'contacts', 'type', 'string', function ($sType) use ($self) {
+ return $self->ValidateContactPdoType($sType);
+ });
+
+ $sTestMessage = $this->AddressBookProvider(null, true)->Test();
+ return $this->DefaultResponse(__FUNCTION__, array(
+ 'Result' => '' === $sTestMessage,
+ 'Message' => \MailSo\Base\Utils::Utf8Clear($sTestMessage, '?')
+ ));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminLicensing()
+ {
+ $this->IsAdminLoggined();
+
+ $bForce = '1' === (string) $this->GetActionParam('Force', '0');
+
+ $mResult = false;
+ $iErrorCode = -1;
+
+ $oPremProvider = $this->PremProvider();
+
+ if ($oPremProvider && 2 < \strlen(APP_SITE))
+ {
+ $sValue = $oPremProvider->Fetcher($bForce);
+
+ $this->requestSleep();
+
+ $iExpired = 0;
+ if ($oPremProvider->Parser($sValue, $iExpired))
+ {
+ $mResult = array(
+ 'Banned' => false,
+ 'Expired' => $iExpired,
+ );
+ }
+ else if ($sValue === 'NO' || \preg_match('/^EXPIRED:[\d]+$/', $sValue))
+ {
+ $iErrorCode = -1;
+ }
+ else if ($sValue === 'TOO_MANY_CONNECTIONS')
+ {
+ $iErrorCode = -1;
+ }
+ else
+ {
+ $iErrorCode = \RainLoop\Notifications::LicensingServerIsUnavailable;
+ }
+ }
+
+ if (0 < $iErrorCode && !$mResult)
+ {
+ throw new \RainLoop\Exceptions\ClientException($iErrorCode);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $mResult);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminLicensingActivate()
+ {
+ $this->IsAdminLoggined();
+
+ $sDomain = (string) $this->GetActionParam('Domain', '');
+ $sKey = (string) $this->GetActionParam('Key', '');
+
+ $mResult = false;
+ $iErrorCode = -1;
+
+ $oPrem = $this->PremProvider();
+
+ if ($oPrem && 2 < \strlen($sDomain) && 2 < \strlen($sKey) && $sDomain === APP_SITE)
+ {
+ $iCode = 0;
+ $sValue = $oPrem->Activate($sDomain, $sKey, $iCode);
+
+ $this->requestSleep();
+
+ $aMatch = array();
+ if ('OK' === $sValue)
+ {
+ $mResult = true;
+ }
+ else if ('TOO_MANY_CONNECTIONS' === $sValue)
+ {
+ $mResult = 'Too many connections. Please try again later.';
+ }
+ else if (\preg_match('/^ERROR:(.+)$/', $sValue, $aMatch) && !empty($aMatch[1]))
+ {
+ $mResult = trim($aMatch[1]);
+
+ $this->Logger()->Write('Activation error for: '.$sKey.' ('.$sDomain.')', \MailSo\Log\Enumerations\Type::ERROR);
+ $this->Logger()->Write($mResult, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+ else
+ {
+ $iErrorCode = \RainLoop\Notifications::LicensingServerIsUnavailable;
+ }
+ }
+
+ if (0 < $iErrorCode && !$mResult)
+ {
+ throw new \RainLoop\Exceptions\ClientException($iErrorCode);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $mResult);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminPasswordUpdate()
+ {
+ $this->IsAdminLoggined();
+
+ $bResult = false;
+ $oConfig = $this->Config();
+
+ $sLogin = \trim($this->GetActionParam('Login', ''));
+ $sPassword = $this->GetActionParam('Password', '');
+ $this->Logger()->AddSecret($sPassword);
+
+ $sNewPassword = $this->GetActionParam('NewPassword', '');
+ if (0 < \strlen(\trim($sNewPassword)))
+ {
+ $this->Logger()->AddSecret($sNewPassword);
+ }
+
+ if ($oConfig->ValidatePassword($sPassword))
+ {
+ if (0 < \strlen($sLogin))
+ {
+ $oConfig->Set('security', 'admin_login', $sLogin);
+ }
+
+ if (0 < \strlen(\trim($sNewPassword)))
+ {
+ $oConfig->SetPassword($sNewPassword);
+ }
+
+ $bResult = true;
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $bResult ?
+ ($oConfig->Save() ? array('Weak' => $oConfig->ValidatePassword('12345')) : false) : false);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminDomainLoad()
+ {
+ $this->IsAdminLoggined();
+
+ return $this->DefaultResponse(__FUNCTION__,
+ $this->DomainProvider()->Load($this->GetActionParam('Name', ''), false, false));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminDomainList()
+ {
+ $this->IsAdminLoggined();
+
+ $iOffset = (int) $this->GetActionParam('Offset', 0);
+ $iLimit = (int) $this->GetActionParam('Limit', 20);
+ $sSearch = (string) $this->GetActionParam('Search', '');
+
+ $iOffset = 0;
+ $iLimit = 99;
+ $sSearch = '';
+
+ return $this->DefaultResponse(__FUNCTION__,
+ $this->DomainProvider()->GetList($iOffset, $iLimit, $sSearch));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminDomainDelete()
+ {
+ $this->IsAdminLoggined();
+
+ return $this->DefaultResponse(__FUNCTION__,
+ $this->DomainProvider()->Delete((string) $this->GetActionParam('Name', '')));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminDomainDisable()
+ {
+ $this->IsAdminLoggined();
+
+ return $this->DefaultResponse(__FUNCTION__, $this->DomainProvider()->Disable(
+ (string) $this->GetActionParam('Name', ''),
+ '1' === (string) $this->GetActionParam('Disabled', '0')
+ ));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminDomainSave()
+ {
+ $this->IsAdminLoggined();
+
+ $oDomain = $this->DomainProvider()->LoadOrCreateNewFromAction($this);
+
+ return $this->DefaultResponse(__FUNCTION__,
+ $oDomain instanceof \RainLoop\Model\Domain ? $this->DomainProvider()->Save($oDomain) : false);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminDomainTest()
+ {
+ $this->IsAdminLoggined();
+
+ $bImapResult = false;
+ $sImapErrorDesc = '';
+ $bSmtpResult = false;
+ $sSmtpErrorDesc = '';
+ $bSieveResult = false;
+ $sSieveErrorDesc = '';
+
+ $iImapTime = 0;
+ $iSmtpTime = 0;
+ $iSieveTime = 0;
+
+ $iConnectionTimeout = 5;
+
+ $oDomain = $this->DomainProvider()->LoadOrCreateNewFromAction($this, 'domain-test-connection.de');
+ if ($oDomain)
+ {
+ try
+ {
+ $oImapClient = \MailSo\Imap\ImapClient::NewInstance()->SetLogger($this->Logger());
+ $oImapClient->SetTimeOuts($iConnectionTimeout);
+
+ $iTime = \microtime(true);
+ $oImapClient->Connect($oDomain->IncHost(), $oDomain->IncPort(), $oDomain->IncSecure(),
+ !!$this->Config()->Get('ssl', 'verify_certificate', false),
+ !!$this->Config()->Get('ssl', 'allow_self_signed', true)
+ );
+
+ $iImapTime = \microtime(true) - $iTime;
+ $oImapClient->Disconnect();
+ $bImapResult = true;
+ }
+ catch (\MailSo\Net\Exceptions\SocketCanNotConnectToHostException $oException)
+ {
+ $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ $sImapErrorDesc = $oException->getSocketMessage();
+ if (empty($sImapErrorDesc))
+ {
+ $sImapErrorDesc = $oException->getMessage();
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ $sImapErrorDesc = $oException->getMessage();
+ }
+
+ if ($oDomain->OutUsePhpMail())
+ {
+ $bSmtpResult = \MailSo\Base\Utils::FunctionExistsAndEnabled('mail');
+ if (!$bSmtpResult)
+ {
+ $sSmtpErrorDesc = 'PHP: mail() function is undefined';
+ }
+ }
+ else
+ {
+ try
+ {
+ $oSmtpClient = \MailSo\Smtp\SmtpClient::NewInstance()->SetLogger($this->Logger());
+ $oSmtpClient->SetTimeOuts($iConnectionTimeout);
+
+ $iTime = \microtime(true);
+ $oSmtpClient->Connect($oDomain->OutHost(), $oDomain->OutPort(),
+ \MailSo\Smtp\SmtpClient::EhloHelper(), $oDomain->OutSecure(),
+ !!$this->Config()->Get('ssl', 'verify_certificate', false),
+ !!$this->Config()->Get('ssl', 'allow_self_signed', true)
+ );
+
+ $iSmtpTime = \microtime(true) - $iTime;
+ $oSmtpClient->Disconnect();
+ $bSmtpResult = true;
+ }
+ catch (\MailSo\Net\Exceptions\SocketCanNotConnectToHostException $oException)
+ {
+ $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ $sSmtpErrorDesc = $oException->getSocketMessage();
+ if (empty($sSmtpErrorDesc))
+ {
+ $sSmtpErrorDesc = $oException->getMessage();
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ $sSmtpErrorDesc = $oException->getMessage();
+ }
+ }
+
+ if ($oDomain->UseSieve())
+ {
+ try
+ {
+ $oSieveClient = \MailSo\Sieve\ManageSieveClient::NewInstance()->SetLogger($this->Logger());
+ $oSieveClient->SetTimeOuts($iConnectionTimeout);
+
+ $iTime = \microtime(true);
+ $oSieveClient->Connect($oDomain->SieveHost(), $oDomain->SievePort(), $oDomain->SieveSecure(),
+ !!$this->Config()->Get('ssl', 'verify_certificate', false),
+ !!$this->Config()->Get('ssl', 'allow_self_signed', true)
+ );
+
+ $iSieveTime = \microtime(true) - $iTime;
+ $oSieveClient->Disconnect();
+ $bSieveResult = true;
+ }
+ catch (\MailSo\Net\Exceptions\SocketCanNotConnectToHostException $oException)
+ {
+ $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ $sSieveErrorDesc = $oException->getSocketMessage();
+ if (empty($sSieveErrorDesc))
+ {
+ $sSieveErrorDesc = $oException->getMessage();
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ $sSieveErrorDesc = $oException->getMessage();
+ }
+ }
+ else
+ {
+ $bSieveResult = true;
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, array(
+ 'Imap' => $bImapResult ? true : $sImapErrorDesc,
+ 'Smtp' => $bSmtpResult ? true : $sSmtpErrorDesc,
+ 'Sieve' => $bSieveResult ? true : $sSieveErrorDesc
+ ));
+ }
+
+ /**
+ * @return string
+ */
+ private function rainLoopRepo()
+ {
+ $sUrl = APP_REPOSITORY_PATH;
+ if ('' !== $sUrl)
+ {
+ $sUrl = rtrim($sUrl, '\\/').'/';
+ }
+
+ return $sUrl;
+ }
+
+ private function rainLoopUpdatable()
+ {
+ return @file_exists(APP_INDEX_ROOT_PATH.'index.php') &&
+ @is_writable(APP_INDEX_ROOT_PATH.'index.php') &&
+ @is_writable(APP_INDEX_ROOT_PATH.'rainloop/') &&
+ APP_VERSION !== APP_DEV_VERSION
+ ;
+ }
+
+ private function rainLoopCoreAccess()
+ {
+ $sCoreAccess = \strtolower(\preg_replace('/[\s,;]+/', ' ',
+ $this->Config()->Get('security', 'core_install_access_domain', '')));
+
+ return '' === $sCoreAccess || '*' === $sCoreAccess || APP_SITE === $sCoreAccess;
+ }
+
+ /**
+ * @param string $sRepo
+ * @param bool $bReal = false
+ *
+ * @return array
+ */
+ private function getRepositoryDataByUrl($sRepo, &$bReal = false)
+ {
+ $bReal = false;
+ $aRep = null;
+
+ $sRep = '';
+ $sRepoFile = 'repository.json';
+ $iRepTime = 0;
+
+ $oHttp = \MailSo\Base\Http::SingletonInstance();
+
+ $sCacheKey = \RainLoop\KeyPathHelper::RepositoryCacheFile($sRepo, $sRepoFile);
+ $sRep = $this->Cacher()->Get($sCacheKey);
+ if ('' !== $sRep)
+ {
+ $iRepTime = $this->Cacher()->GetTimer($sCacheKey);
+ }
+
+ if ('' === $sRep || 0 === $iRepTime || time() - 3600 > $iRepTime)
+ {
+ $iCode = 0;
+ $sContentType = '';
+
+ $sRepPath = $sRepo.$sRepoFile;
+ $sRep = '' !== $sRepo ? $oHttp->GetUrlAsString($sRepPath, 'RainLoop', $sContentType, $iCode, $this->Logger(), 10,
+ $this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', '')) : false;
+
+ if (false !== $sRep)
+ {
+ $aRep = @\json_decode($sRep);
+ $bReal = \is_array($aRep) && 0 < \count($aRep);
+
+ if ($bReal)
+ {
+ $this->Cacher()->Set($sCacheKey, $sRep);
+ $this->Cacher()->SetTimer($sCacheKey);
+ }
+ }
+ else
+ {
+ $this->Logger()->Write('Cannot read remote repository file: '.$sRepPath, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
+ }
+ }
+ else if ('' !== $sRep)
+ {
+ $aRep = @\json_decode($sRep, false, 10);
+ $bReal = \is_array($aRep) && 0 < \count($aRep);
+ }
+
+ $aResult = array();
+ if (\is_array($aRep))
+ {
+ foreach ($aRep as $oItem)
+ {
+ if ($oItem && isset($oItem->type, $oItem->id, $oItem->name,
+ $oItem->version, $oItem->release, $oItem->file, $oItem->description))
+ {
+ if (!empty($oItem->required) && APP_DEV_VERSION !== APP_VERSION && version_compare(APP_VERSION, $oItem->required, '<'))
+ {
+ continue;
+ }
+
+ if (!empty($oItem->depricated) && APP_DEV_VERSION !== APP_VERSION && version_compare(APP_VERSION, $oItem->depricated, '>='))
+ {
+ continue;
+ }
+
+ if ('plugin' === $oItem->type)
+ {
+ $aResult[] = array(
+ 'type' => $oItem->type,
+ 'id' => $oItem->id,
+ 'name' => $oItem->name,
+ 'installed' => '',
+ 'version' => $oItem->version,
+ 'file' => $oItem->file,
+ 'release' => $oItem->release,
+ 'desc' => $oItem->description
+ );
+ }
+ }
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @return string
+ */
+ private function getCoreChannel()
+ {
+ $sChannel = \trim(\strtolower($this->Config()->Get('labs', 'update_channel', 'stable')));
+ if (empty($sChannel) || !\in_array($sChannel, array('stable', 'beta')))
+ {
+ $sChannel = 'stable';
+ }
+
+ return $sChannel;
+ }
+
+ private function getCoreData(&$bReal)
+ {
+ $bReal = false;
+
+ $sChannel = $this->getCoreChannel();
+
+ $sRepo = \str_replace('{{channel}}', $sChannel, APP_REPO_CORE_FILE);
+
+ $oHttp = \MailSo\Base\Http::SingletonInstance();
+
+ $sCacheKey = \RainLoop\KeyPathHelper::RepositoryCacheCore($sRepo);
+ $sRep = $this->Cacher()->Get($sCacheKey);
+ if ('' !== $sRep)
+ {
+ $iRepTime = $this->Cacher()->GetTimer($sCacheKey);
+ }
+
+ if ('' === $sRep || 0 === $iRepTime || time() - 3600 > $iRepTime)
+ {
+ $iCode = 0;
+ $sContentType = '';
+
+ $sRep = '' !== $sRepo ? $oHttp->GetUrlAsString($sRepo, 'RainLoop', $sContentType, $iCode, $this->Logger(), 10,
+ $this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', '')) : false;
+
+ if (false !== $sRep)
+ {
+ $aRep = @\json_decode($sRep, true, 10);
+ $bReal = \is_array($aRep) && 0 < \count($aRep) && isset($aRep['id']) && 'rainloop' === $aRep['id'];
+
+ if ($bReal)
+ {
+ $this->Cacher()->Set($sCacheKey, $sRep);
+ $this->Cacher()->SetTimer($sCacheKey);
+ }
+ }
+ else
+ {
+ $this->Logger()->Write('Cannot read remote repository file: '.$sRepo, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
+ }
+ }
+ else if ('' !== $sRep)
+ {
+ $aRep = @\json_decode($sRep, true, 10);
+ $bReal = \is_array($aRep) && 0 < \count($aRep) && isset($aRep['id']) && 'rainloop' === $aRep['id'];
+ }
+
+ return $bReal ? $aRep : false;
+ }
+
+ private function getRepositoryData(&$bReal, &$bRainLoopUpdatable)
+ {
+ $bRainLoopUpdatable = $this->rainLoopUpdatable();
+
+ $aResult = $this->getRepositoryDataByUrl($this->rainLoopRepo(), $bReal);
+
+ $aSub = array();
+ if (\is_array($aResult))
+ {
+ foreach ($aResult as $aItem)
+ {
+ if ('plugin' === $aItem['type'])
+ {
+ $aSub[] = $aItem;
+ }
+ }
+
+ $aResult = $aSub;
+ unset($aSub);
+ }
+
+ $aInstalled = $this->Plugins()->InstalledPlugins();
+ if (\is_array($aInstalled))
+ {
+ foreach ($aResult as &$aItem)
+ {
+ if ('plugin' === $aItem['type'])
+ {
+ foreach ($aInstalled as &$aSubItem)
+ {
+ if (\is_array($aSubItem) && isset($aSubItem[0]) && $aSubItem[0] === $aItem['id'])
+ {
+ $aSubItem[2] = true;
+ $aItem['installed'] = $aSubItem[1];
+ }
+ }
+ }
+ }
+
+ foreach ($aInstalled as $aSubItemSec)
+ {
+ if ($aSubItemSec && !isset($aSubItemSec[2]))
+ {
+ \array_push($aResult, array(
+ 'type' => 'plugin',
+ 'id' => $aSubItemSec[0],
+ 'name' => $aSubItemSec[0],
+ 'installed' => $aSubItemSec[1],
+ 'version' => '',
+ 'file' => '',
+ 'release' => '',
+ 'desc' => ''
+ ));
+ }
+ }
+ }
+
+ foreach ($aResult as &$aItem)
+ {
+ $aItem['compare'] = \version_compare($aItem['installed'], $aItem['version'], '<');
+ $aItem['canBeDeleted'] = '' !== $aItem['installed'] && 'plugin' === $aItem['type'];
+ $aItem['canBeUpdated'] = $aItem['compare'];
+ $aItem['canBeInstalled'] = true;
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminPackagesList()
+ {
+ $this->IsAdminLoggined();
+
+ $bReal = false;
+ $bRainLoopUpdatable = false;
+ $aList = $this->getRepositoryData($bReal, $bRainLoopUpdatable);
+
+ return $this->DefaultResponse(__FUNCTION__, array(
+ 'Real' => $bReal,
+ 'MainUpdatable' => $bRainLoopUpdatable,
+ 'List' => $aList
+ ));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminCoreData()
+ {
+ $this->IsAdminLoggined();
+
+ $bReal = false;
+ $aData = array();
+
+ $bRainLoopUpdatable = $this->rainLoopUpdatable();
+ $bRainLoopAccess = $this->rainLoopCoreAccess();
+
+ if ($bRainLoopAccess)
+ {
+ $aData = $this->getCoreData($bReal);
+ }
+
+ $sVersion = empty($aData['version']) ? '' : $aData['version'];
+ $sType = empty($aData['channel']) ? 'stable' : $aData['channel'];
+
+ $sWarnings = empty($aData['warnings']) ? '' : $aData['warnings'];
+ $aWarnings = $sWarnings ? explode('|', $sWarnings) : array();
+
+ $sCurrentVersion = APP_VERSION;
+
+ $bShowWarning = false;
+ if ($sCurrentVersion !== APP_DEV_VERSION)
+ {
+ foreach ($aWarnings as $sWarningVersion)
+ {
+ $sWarningVersion = \trim($sWarningVersion);
+
+ if (\version_compare($sCurrentVersion, $sWarningVersion, '<') &&
+ \version_compare($sVersion, $sWarningVersion, '>='))
+ {
+ $bShowWarning = true;
+ break;
+ }
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, array(
+ 'Real' => $bReal,
+ 'Access' => $bRainLoopAccess,
+ 'Updatable' => $bRainLoopUpdatable,
+ 'Warning' => $bShowWarning,
+ 'Channel' => $this->getCoreChannel(),
+ 'Type' => $sType,
+ 'Version' => $sCurrentVersion,
+ 'RemoteVersion' => $sVersion,
+ 'RemoteRelease' => empty($aData['release']) ? '' : $aData['release'],
+ 'VersionCompare' => \version_compare($sCurrentVersion, $sVersion)
+ ));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminUpdateCoreData()
+ {
+ $this->IsAdminLoggined();
+
+ $bReal = false;
+
+ $bRainLoopUpdatable = $this->rainLoopUpdatable();
+ $bRainLoopAccess = $this->rainLoopCoreAccess();
+ $oPremProvider = $this->PremProvider();
+
+ $aData = array();
+ if ($bRainLoopUpdatable && $bRainLoopAccess)
+ {
+ $aData = $this->getCoreData($bReal);
+ }
+
+ $bResult = false;
+ if ($bReal && $oPremProvider && !empty($aData['file']))
+ {
+ $bResult = $oPremProvider->UpdateCore($this, $aData['file']);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $bResult);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminPackageDelete()
+ {
+ $this->IsAdminLoggined();
+
+ $sId = $this->GetActionParam('Id', '');
+
+ $bReal = false;
+ $bRainLoopUpdatable = false;
+ $aList = $this->getRepositoryData($bReal, $bRainLoopUpdatable);
+
+ $sResultId = '';
+ foreach ($aList as $oItem)
+ {
+ if ($oItem && 'plugin' === $oItem['type'] && $sId === $oItem['id'])
+ {
+ $sResultId = $sId;
+ break;
+ }
+ }
+
+ $bResult = false;
+ if ('' !== $sResultId)
+ {
+ $bResult = \MailSo\Base\Utils::RecRmDir(APP_PLUGINS_PATH.$sResultId);
+ if ($bResult)
+ {
+ $this->pluginEnable($sResultId, false);
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $bResult);
+ }
+
+ /**
+ * @param string $sUrl
+ *
+ * @return string
+ */
+ public function downloadRemotePackageByUrl($sUrl)
+ {
+ $bResult = false;
+ $sTmp = APP_PRIVATE_DATA.\md5(\microtime(true).$sUrl).'.zip';
+ $pDest = @\fopen($sTmp, 'w+b');
+ if ($pDest)
+ {
+ $iCode = 0;
+ $sContentType = '';
+
+ @\set_time_limit(90);
+
+ $oHttp = \MailSo\Base\Http::SingletonInstance();
+ $bResult = $oHttp->SaveUrlToFile($sUrl, $pDest, $sTmp, $sContentType, $iCode, $this->Logger(), 60,
+ $this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', ''));
+
+ if (!$bResult)
+ {
+ $this->Logger()->Write('Cannot save url to temp file: ', \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
+ $this->Logger()->Write($sUrl.' -> '.$sTmp, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
+ }
+
+ @\fclose($pDest);
+ }
+ else
+ {
+ $this->Logger()->Write('Cannot create temp file: '.$sTmp, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
+ }
+
+ return $bResult ? $sTmp : '';
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminPackageInstall()
+ {
+ $this->IsAdminLoggined();
+
+ $sType = $this->GetActionParam('Type', '');
+ $sId = $this->GetActionParam('Id', '');
+ $sFile = $this->GetActionParam('File', '');
+
+ $this->Logger()->Write('Start package install: '.$sFile.' ('.$sType.')', \MailSo\Log\Enumerations\Type::INFO, 'INSTALLER');
+
+ $sRealFile = '';
+
+ $bReal = false;
+ $bRainLoopUpdatable = false;
+ $aList = $this->getRepositoryData($bReal, $bRainLoopUpdatable);
+
+ if ('plugin' === $sType)
+ {
+ foreach ($aList as $oItem)
+ {
+ if ($oItem && $sFile === $oItem['file'] && $sId === $oItem['id'])
+ {
+ $sRealFile = $sFile;
+ break;
+ }
+ }
+ }
+
+ $sTmp = '';
+ $bResult = false;
+ if ('' !== $sRealFile)
+ {
+ $sUrl = $this->rainLoopRepo().$sRealFile;
+ $sTmp = $this->downloadRemotePackageByUrl($sUrl);
+ }
+
+ if ('' !== $sTmp)
+ {
+ include_once APP_VERSION_ROOT_PATH.'app/libraries/pclzip/pclzip.lib.php';
+
+ $oArchive = new \PclZip($sTmp);
+ if ('plugin' === $sType)
+ {
+ $bResult = true;
+ if (\is_dir(APP_PLUGINS_PATH.$sId))
+ {
+ $bResult = \MailSo\Base\Utils::RecRmDir(APP_PLUGINS_PATH.$sId);
+ if (!$bResult)
+ {
+ $this->Logger()->Write('Cannot remove previous plugin folder: '.$sId, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
+ }
+ }
+
+ if ($bResult)
+ {
+ $bResult = 0 !== $oArchive->extract(PCLZIP_OPT_PATH, APP_PLUGINS_PATH);
+ if (!$bResult)
+ {
+ $this->Logger()->Write('Cannot extract package files: '.$oArchive->errorInfo(), \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
+ }
+ }
+ }
+
+ @\unlink($sTmp);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $bResult ?
+ ('plugin' !== $sType ? array('Reload' => true) : true) : false);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminPluginList()
+ {
+ $this->IsAdminLoggined();
+
+ $aResult = array();
+
+ $sEnabledPlugins = $this->Config()->Get('plugins', 'enabled_list', '');
+ $aEnabledPlugins = \explode(',', \strtolower($sEnabledPlugins));
+ $aEnabledPlugins = \array_map('trim', $aEnabledPlugins);
+
+ $aList = $this->Plugins()->InstalledPlugins();
+ foreach ($aList as $aItem)
+ {
+ $aResult[] = array(
+ 'Name' => $aItem[0],
+ 'Enabled' => \in_array(\strtolower($aItem[0]), $aEnabledPlugins),
+ 'Configured' => false
+ );
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $aResult);
+ }
+
+ /**
+ * @param string $sName
+ * @param bool $bEnable = true
+ * @return bool
+ */
+ private function pluginEnable($sName, $bEnable = true)
+ {
+ if (0 === \strlen($sName))
+ {
+ return false;
+ }
+
+ $oConfig = $this->Config();
+
+ $sEnabledPlugins = $oConfig->Get('plugins', 'enabled_list', '');
+ $aEnabledPlugins = \explode(',', \strtolower($sEnabledPlugins));
+ $aEnabledPlugins = \array_map('trim', $aEnabledPlugins);
+
+ $aNewEnabledPlugins = array();
+ if ($bEnable)
+ {
+ $aNewEnabledPlugins = $aEnabledPlugins;
+ $aNewEnabledPlugins[] = $sName;
+ }
+ else
+ {
+ foreach ($aEnabledPlugins as $sPlugin)
+ {
+ if ($sName !== $sPlugin && 0 < \strlen($sPlugin))
+ {
+ $aNewEnabledPlugins[] = $sPlugin;
+ }
+ }
+ }
+
+ $aNewEnabledPlugins = \array_unique($aNewEnabledPlugins);
+ $oConfig->Set('plugins', 'enabled_list', \trim(\implode(',', $aNewEnabledPlugins), ' ,'));
+
+ return $oConfig->Save();
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminPluginDisable()
+ {
+ $this->IsAdminLoggined();
+
+ $sName = (string) $this->GetActionParam('Name', '');
+ $bDisable = '1' === (string) $this->GetActionParam('Disabled', '1');
+
+ if (!$bDisable)
+ {
+ $oPlugin = $this->Plugins()->CreatePluginByName($sName);
+ if ($oPlugin && ($oPlugin instanceof \RainLoop\Plugins\AbstractPlugin))
+ {
+ $sValue = $oPlugin->Supported();
+ if (0 < \strlen($sValue))
+ {
+ return $this->FalseResponse(__FUNCTION__, \RainLoop\Notifications::UnsupportedPluginPackage, $sValue);
+ }
+ }
+ else
+ {
+ return $this->FalseResponse(__FUNCTION__, \RainLoop\Notifications::InvalidPluginPackage);
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $this->pluginEnable($sName, !$bDisable));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminPluginLoad()
+ {
+ $this->IsAdminLoggined();
+
+ $mResult = false;
+ $sName = (string) $this->GetActionParam('Name', '');
+
+ if (!empty($sName))
+ {
+ $oPlugin = $this->Plugins()->CreatePluginByName($sName);
+ if ($oPlugin)
+ {
+ $mResult = array(
+ 'Name' => $sName,
+ 'Readme' => file_exists($oPlugin->Path().'/README') ? file_get_contents($oPlugin->Path().'/README') : '',
+ 'Config' => array()
+ );
+
+ $aMap = $oPlugin->ConfigMap();
+ $oConfig = $oPlugin->Config();
+ if (is_array($aMap) && 0 < count($aMap))
+ {
+ foreach ($aMap as $oItem)
+ {
+ if ($oItem && ($oItem instanceof \RainLoop\Plugins\Property))
+ {
+ $aItem = $oItem->ToArray();
+ $aItem[0] = $oConfig->Get('plugin', $oItem->Name(), '');
+ if (\RainLoop\Enumerations\PluginPropertyType::PASSWORD === $oItem->Type())
+ {
+ $aItem[0] = APP_DUMMY;
+ }
+
+ $mResult['Config'][] = $aItem;
+ }
+ }
+ }
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $mResult);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoAdminPluginSettingsUpdate()
+ {
+ $this->IsAdminLoggined();
+
+ $mResult = false;
+ $sName = (string) $this->GetActionParam('Name', '');
+
+ if (!empty($sName))
+ {
+ $oPlugin = $this->Plugins()->CreatePluginByName($sName);
+ if ($oPlugin)
+ {
+ $oConfig = $oPlugin->Config();
+ $aMap = $oPlugin->ConfigMap();
+ if (is_array($aMap) && 0 < count($aMap))
+ {
+ foreach ($aMap as $oItem)
+ {
+ $sValue = $this->GetActionParam('_'.$oItem->Name(), $oConfig->Get('plugin', $oItem->Name()));
+ if (\RainLoop\Enumerations\PluginPropertyType::PASSWORD !== $oItem->Type() || APP_DUMMY !== $sValue)
+ {
+ $mResultValue = null;
+ switch ($oItem->Type()) {
+ case \RainLoop\Enumerations\PluginPropertyType::INT:
+ $mResultValue = (int) $sValue;
+ break;
+ case \RainLoop\Enumerations\PluginPropertyType::BOOL:
+ $mResultValue = '1' === (string) $sValue;
+ break;
+ case \RainLoop\Enumerations\PluginPropertyType::SELECTION:
+ if (is_array($oItem->DefaultValue()) && in_array($sValue, $oItem->DefaultValue()))
+ {
+ $mResultValue = (string) $sValue;
+ }
+ break;
+ case \RainLoop\Enumerations\PluginPropertyType::PASSWORD:
+ case \RainLoop\Enumerations\PluginPropertyType::STRING:
+ case \RainLoop\Enumerations\PluginPropertyType::STRING_TEXT:
+ $mResultValue = (string) $sValue;
+ break;
+ }
+
+ if (null !== $mResultValue)
+ {
+ $oConfig->Set('plugin', $oItem->Name(), $mResultValue);
+ }
+ }
+ }
+ }
+
+ $mResult = $oConfig->Save();
+ }
+ }
+
+ if (!$mResult)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSavePluginSettings);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, true);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoSettingsUpdate()
+ {
+ $oAccount = $this->getAccountFromToken();
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::SETTINGS, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $self = $this;
+ $oConfig = $this->Config();
+
+ $oSettings = $this->SettingsProvider()->Load($oAccount);
+ $oSettingsLocal = $this->SettingsProvider(true)->Load($oAccount);
+
+ if ($oConfig->Get('webmail', 'allow_languages_on_settings', true))
+ {
+ $this->setSettingsFromParams($oSettings, 'Language', 'string', function ($sLanguage) use ($self) {
+ return $self->ValidateLanguage($sLanguage);
+ });
+ }
+ else
+ {
+ $oSettings->SetConf('Language', $this->ValidateLanguage($oConfig->Get('webmail', 'language', 'en')));
+ }
+
+ if ($this->GetCapa(false, false, \RainLoop\Enumerations\Capa::THEMES, $oAccount))
+ {
+ $this->setSettingsFromParams($oSettingsLocal, 'Theme', 'string', function ($sTheme) use ($self) {
+ return $self->ValidateTheme($sTheme);
+ });
+ }
+ else
+ {
+ $oSettingsLocal->SetConf('Theme', $this->ValidateTheme($oConfig->Get('webmail', 'theme', 'Default')));
+ }
+
+ $this->setSettingsFromParams($oSettings, 'MPP', 'int', function ($iValue) {
+ return (int) (\in_array($iValue, array(10, 20, 30, 50, 100, 150, 200, 300)) ? $iValue : 20);
+ });
+
+ $this->setSettingsFromParams($oSettings, 'Layout', 'int', function ($iValue) {
+ return (int) (\in_array((int) $iValue, array(\RainLoop\Enumerations\Layout::NO_PREVIW,
+ \RainLoop\Enumerations\Layout::SIDE_PREVIEW, \RainLoop\Enumerations\Layout::BOTTOM_PREVIEW)) ?
+ $iValue : \RainLoop\Enumerations\Layout::SIDE_PREVIEW);
+ });
+
+ $this->setSettingsFromParams($oSettings, 'EditorDefaultType', 'string');
+ $this->setSettingsFromParams($oSettings, 'ShowImages', 'bool');
+ $this->setSettingsFromParams($oSettings, 'ContactsAutosave', 'bool');
+ $this->setSettingsFromParams($oSettings, 'DesktopNotifications', 'bool');
+ $this->setSettingsFromParams($oSettings, 'SoundNotification', 'bool');
+ $this->setSettingsFromParams($oSettings, 'UseCheckboxesInList', 'bool');
+ $this->setSettingsFromParams($oSettings, 'AutoLogout', 'int');
+
+ $this->setSettingsFromParams($oSettings, 'EnableTwoFactor', 'bool');
+
+ $this->setSettingsFromParams($oSettingsLocal, 'UseThreads', 'bool');
+ $this->setSettingsFromParams($oSettingsLocal, 'ReplySameFolder', 'bool');
+
+ return $this->DefaultResponse(__FUNCTION__,
+ $this->SettingsProvider()->Save($oAccount, $oSettings) &&
+ $this->SettingsProvider(true)->Save($oAccount, $oSettingsLocal));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoNoop()
+ {
+ $this->initMailClientConnection();
+ return $this->TrueResponse(__FUNCTION__);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoPing()
+ {
+ return $this->DefaultResponse(__FUNCTION__, 'Pong');
+ }
+
+ /**
+ * @return array
+ */
+ public function DoChangePassword()
+ {
+ $mResult = false;
+
+ $oAccount = $this->getAccountFromToken();
+ if ($oAccount)
+ {
+ try
+ {
+ $mResult = $this->ChangePasswordProvider()->ChangePassword(
+ $oAccount,
+ $this->GetActionParam('PrevPassword', ''),
+ $this->GetActionParam('NewPassword', '')
+ );
+ }
+ catch (\Exception $oException)
+ {
+ $this->loginErrorDelay();
+ $this->Logger()->Write('Error: Can\'t change password for '.$oAccount->Email().' account.', \MailSo\Log\Enumerations\Type::NOTICE);
+
+ throw $oException;
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $mResult);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoJsInfo()
+ {
+ $bIsError = '1' === (string) $this->GetActionParam('IsError', '0');
+ $mData = $this->GetActionParam('Data', null);
+
+ $this->Logger()->WriteDump(is_array($mData) ? $mData : array(),
+ $bIsError ? \MailSo\Log\Enumerations\Type::ERROR : \MailSo\Log\Enumerations\Type::INFO, 'JS-INFO');
+
+ return $this->DefaultResponse(__FUNCTION__, true);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoWelcomeClose()
+ {
+ $oAccount = $this->getAccountFromToken();
+ if ($oAccount && !$oAccount->IsAdditionalAccount())
+ {
+ $oSettings = $this->SettingsProvider()->Load($oAccount);
+ $oSettings->SetConf('LastWelcomePage',
+ $this->Config()->Get('branding', 'welcome_page_url', ''));
+
+ return $this->DefaultResponse(__FUNCTION__,
+ $this->SettingsProvider()->Save($oAccount, $oSettings));
+ }
+
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoVersion()
+ {
+ return $this->DefaultResponse(__FUNCTION__,
+ APP_VERSION === (string) $this->GetActionParam('Version', ''));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoJsError()
+ {
+ $sMessage = $this->GetActionParam('Message', '');
+ if (0 < strlen($sMessage))
+ {
+ $sFileName = $this->GetActionParam('FileName', '');
+ $sLineNo = $this->GetActionParam('LineNo', '');
+ $sLocation = $this->GetActionParam('Location', '');
+ $sHtmlCapa = $this->GetActionParam('HtmlCapa', '');
+ $sTimeOnPage = $this->GetActionParam('TimeOnPage', '');
+
+ $oHttp = $this->Http();
+
+ $this->Logger()->Write($sMessage.' ('.$sFileName.' ~ '.$sLineNo.')', \MailSo\Log\Enumerations\Type::ERROR, 'JS');
+ $this->Logger()->WriteDump(array(
+ 'Location' => $sLocation,
+ 'Capability' => $sHtmlCapa,
+ 'TimeOnPage' => $sTimeOnPage,
+ 'HTTP_USER_AGENT' => $oHttp->GetServer('HTTP_USER_AGENT', ''),
+ 'HTTP_ACCEPT_ENCODING' => $oHttp->GetServer('HTTP_ACCEPT_ENCODING', ''),
+ 'HTTP_ACCEPT_LANGUAGE' => $oHttp->GetServer('HTTP_ACCEPT_LANGUAGE', '')
+ ));
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, true);
+ }
+
+ /**
+ * @param \MailSo\Mail\FolderCollection $oFolders
+ * @return array
+ */
+ private function recFoldersNames($oFolders)
+ {
+ $aResult = array();
+ if ($oFolders)
+ {
+ $aFolders =& $oFolders->GetAsArray();
+
+ foreach ($aFolders as $oFolder)
+ {
+ $aResult[] = $oFolder->FullNameRaw()."|".
+ implode("|", $oFolder->Flags()).($oFolder->IsSubscribed() ? '1' : '0');
+
+ $oSub = $oFolder->SubFolders();
+ if ($oSub && 0 < $oSub->Count())
+ {
+ $aResult = \array_merge($aResult, $this->recFoldersNames($oSub));
+ }
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @staticvar array $aCache
+ * @param \RainLoop\Model\Account $oAccount
+ *
+ * @return array
+ */
+ private function systemFoldersNames($oAccount)
+ {
+ static $aCache = null;
+ if (null === $aCache)
+ {
+ $aCache = array(
+
+ 'Sent' => \MailSo\Imap\Enumerations\FolderType::SENT,
+
+ 'Send' => \MailSo\Imap\Enumerations\FolderType::SENT,
+ 'Sent Item' => \MailSo\Imap\Enumerations\FolderType::SENT,
+ 'Sent Items' => \MailSo\Imap\Enumerations\FolderType::SENT,
+ 'Send Item' => \MailSo\Imap\Enumerations\FolderType::SENT,
+ 'Send Items' => \MailSo\Imap\Enumerations\FolderType::SENT,
+ 'Sent Mail' => \MailSo\Imap\Enumerations\FolderType::SENT,
+ 'Sent Mails' => \MailSo\Imap\Enumerations\FolderType::SENT,
+ 'Send Mail' => \MailSo\Imap\Enumerations\FolderType::SENT,
+ 'Send Mails' => \MailSo\Imap\Enumerations\FolderType::SENT,
+
+ 'Drafts' => \MailSo\Imap\Enumerations\FolderType::DRAFTS,
+
+ 'Draft' => \MailSo\Imap\Enumerations\FolderType::DRAFTS,
+ 'Draft Mail' => \MailSo\Imap\Enumerations\FolderType::DRAFTS,
+ 'Draft Mails' => \MailSo\Imap\Enumerations\FolderType::DRAFTS,
+ 'Drafts Mail' => \MailSo\Imap\Enumerations\FolderType::DRAFTS,
+ 'Drafts Mails' => \MailSo\Imap\Enumerations\FolderType::DRAFTS,
+
+ 'Spam' => \MailSo\Imap\Enumerations\FolderType::JUNK,
+
+ 'Junk' => \MailSo\Imap\Enumerations\FolderType::JUNK,
+ 'Bulk Mail' => \MailSo\Imap\Enumerations\FolderType::JUNK,
+ 'Bulk Mails' => \MailSo\Imap\Enumerations\FolderType::JUNK,
+
+ 'Trash' => \MailSo\Imap\Enumerations\FolderType::TRASH,
+ 'Deleted' => \MailSo\Imap\Enumerations\FolderType::TRASH,
+ 'Bin' => \MailSo\Imap\Enumerations\FolderType::TRASH,
+
+ 'Archive' => \MailSo\Imap\Enumerations\FolderType::ALL,
+
+ 'All' => \MailSo\Imap\Enumerations\FolderType::ALL,
+ 'All Mail' => \MailSo\Imap\Enumerations\FolderType::ALL,
+ 'All Mails' => \MailSo\Imap\Enumerations\FolderType::ALL,
+ 'AllMail' => \MailSo\Imap\Enumerations\FolderType::ALL,
+ 'AllMails' => \MailSo\Imap\Enumerations\FolderType::ALL,
+ );
+
+ $this->Plugins()->RunHook('filter.system-folders-names', array($oAccount, &$aCache));
+ }
+
+ return $aCache;
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ * @param \MailSo\Mail\FolderCollection $oFolders
+ * @param array $aResult
+ * @param bool $bListFolderTypes = true
+ */
+ private function recFoldersTypes($oAccount, $oFolders, &$aResult, $bListFolderTypes = true)
+ {
+ if ($oFolders)
+ {
+ $aFolders =& $oFolders->GetAsArray();
+ if (\is_array($aFolders) && 0 < \count($aFolders))
+ {
+ if ($bListFolderTypes)
+ {
+ foreach ($aFolders as $oFolder)
+ {
+ $iFolderListType = $oFolder->GetFolderListType();
+ if (!isset($aResult[$iFolderListType]) && \in_array($iFolderListType, array(
+ \MailSo\Imap\Enumerations\FolderType::SENT,
+ \MailSo\Imap\Enumerations\FolderType::DRAFTS,
+ \MailSo\Imap\Enumerations\FolderType::JUNK,
+ \MailSo\Imap\Enumerations\FolderType::TRASH,
+ \MailSo\Imap\Enumerations\FolderType::ALL
+ )))
+ {
+ $aResult[$iFolderListType] = $oFolder->FullNameRaw();
+ }
+ }
+
+ foreach ($aFolders as $oFolder)
+ {
+ $oSub = $oFolder->SubFolders();
+ if ($oSub && 0 < $oSub->Count())
+ {
+ $this->recFoldersTypes($oAccount, $oSub, $aResult, true);
+ }
+ }
+ }
+
+ $aMap = $this->systemFoldersNames($oAccount);
+ foreach ($aFolders as $oFolder)
+ {
+ $sName = $oFolder->Name();
+ $sFullName = $oFolder->FullName();
+
+ if (isset($aMap[$sName]) || isset($aMap[$sFullName]))
+ {
+ $iFolderType = isset($aMap[$sName]) ? $aMap[$sName] : $aMap[$sFullName];
+ if (!isset($aResult[$iFolderType]) && \in_array($iFolderType, array(
+ \MailSo\Imap\Enumerations\FolderType::SENT,
+ \MailSo\Imap\Enumerations\FolderType::DRAFTS,
+ \MailSo\Imap\Enumerations\FolderType::JUNK,
+ \MailSo\Imap\Enumerations\FolderType::TRASH,
+ \MailSo\Imap\Enumerations\FolderType::ALL
+ )))
+ {
+ $aResult[$iFolderType] = $oFolder->FullNameRaw();
+ }
+ }
+ }
+
+ foreach ($aFolders as $oFolder)
+ {
+ $oSub = $oFolder->SubFolders();
+ if ($oSub && 0 < $oSub->Count())
+ {
+ $this->recFoldersTypes($oAccount, $oSub, $aResult, false);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function DoFolders()
+ {
+ $oAccount = $this->initMailClientConnection();
+
+ $oFolderCollection = null;
+ $this->Plugins()->RunHook('filter.folders-before', array($oAccount, &$oFolderCollection));
+
+ $bUseFolders = $this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FOLDERS, $oAccount);
+
+ if (null === $oFolderCollection)
+ {
+ $oFolderCollection = $this->MailClient()->Folders('',
+ $bUseFolders ? '*' : 'INBOX',
+ !!$this->Config()->Get('labs', 'use_imap_list_subscribe', true),
+ (int) $this->Config()->Get('labs', 'imap_folder_list_limit', 200)
+ );
+ }
+
+ $this->Plugins()->RunHook('filter.folders-post', array($oAccount, &$oFolderCollection));
+
+ if ($oFolderCollection instanceof \MailSo\Mail\FolderCollection)
+ {
+ $oSettingsLocal = $this->SettingsProvider(true)->Load($oAccount);
+
+ $aSystemFolders = array();
+ $this->recFoldersTypes($oAccount, $oFolderCollection, $aSystemFolders);
+ $oFolderCollection->SystemFolders = $aSystemFolders;
+
+ if ($bUseFolders && $this->Config()->Get('labs', 'autocreate_system_folders', true))
+ {
+ $bDoItAgain = false;
+
+ $sNamespace = $oFolderCollection->GetNamespace();
+ $sParent = empty($sNamespace) ? '' : \substr($sNamespace, 0, -1);
+
+ $sDelimiter = $oFolderCollection->FindDelimiter();
+
+ $aList = array();
+ $aMap = $this->systemFoldersNames($oAccount);
+
+ if ('' === $oSettingsLocal->GetConf('SentFolder', ''))
+ {
+ $aList[] = \MailSo\Imap\Enumerations\FolderType::SENT;
+ }
+
+ if ('' === $oSettingsLocal->GetConf('DraftFolder', ''))
+ {
+ $aList[] = \MailSo\Imap\Enumerations\FolderType::DRAFTS;
+ }
+
+ if ('' === $oSettingsLocal->GetConf('SpamFolder', ''))
+ {
+ $aList[] = \MailSo\Imap\Enumerations\FolderType::JUNK;
+ }
+
+ if ('' === $oSettingsLocal->GetConf('TrashFolder', ''))
+ {
+ $aList[] = \MailSo\Imap\Enumerations\FolderType::TRASH;
+ }
+
+ if ('' === $oSettingsLocal->GetConf('ArchiveFolder', ''))
+ {
+ $aList[] = \MailSo\Imap\Enumerations\FolderType::ALL;
+ }
+
+ $this->Plugins()->RunHook('filter.folders-system-types', array($oAccount, &$aList));
+
+ foreach ($aList as $iType)
+ {
+ if (!isset($aSystemFolders[$iType]))
+ {
+ $mFolderNameToCreate = \array_search($iType, $aMap);
+ if (!empty($mFolderNameToCreate))
+ {
+ $iPos = \strrpos($mFolderNameToCreate, $sDelimiter);
+ if (false !== $iPos)
+ {
+ $mNewParent = \substr($mFolderNameToCreate, 0, $iPos);
+ $mNewFolderNameToCreate = \substr($mFolderNameToCreate, $iPos + 1);
+ if (0 < \strlen($mNewFolderNameToCreate))
+ {
+ $mFolderNameToCreate = $mNewFolderNameToCreate;
+ }
+
+ if (0 < \strlen($mNewParent))
+ {
+ $sParent = 0 < \strlen($sParent) ? $sParent.$sDelimiter.$mNewParent : $mNewParent;
+ }
+ }
+
+ $sFullNameToCheck = \MailSo\Base\Utils::ConvertEncoding($mFolderNameToCreate,
+ \MailSo\Base\Enumerations\Charset::UTF_8, \MailSo\Base\Enumerations\Charset::UTF_7_IMAP);
+
+ if (0 < \strlen(\trim($sParent)))
+ {
+ $sFullNameToCheck = $sParent.$sDelimiter.$sFullNameToCheck;
+ }
+
+ if (!$oFolderCollection->GetByFullNameRaw($sFullNameToCheck))
+ {
+ try
+ {
+ if ($this->MailClient()->FolderCreate($mFolderNameToCreate, $sParent, true, $sDelimiter))
+ {
+ $bDoItAgain = true;
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->Logger()->WriteException($oException);
+ }
+ }
+ }
+ }
+ }
+
+ if ($bDoItAgain)
+ {
+ $oFolderCollection = $this->MailClient()->Folders('', '*',
+ !!$this->Config()->Get('labs', 'use_imap_list_subscribe', true),
+ (int) $this->Config()->Get('labs', 'imap_folder_list_limit', 200)
+ );
+
+ if ($oFolderCollection)
+ {
+ $aSystemFolders = array();
+ $this->recFoldersTypes($oAccount, $oFolderCollection, $aSystemFolders);
+ $oFolderCollection->SystemFolders = $aSystemFolders;
+ }
+ }
+ }
+
+ if ($oFolderCollection)
+ {
+ $oFolderCollection->FoldersHash = \md5(\implode("\x0", $this->recFoldersNames($oFolderCollection)));
+ }
+ }
+
+ $this->Plugins()->RunHook('filter.folders-complete', array($oAccount, &$oFolderCollection));
+
+ return $this->DefaultResponse(__FUNCTION__, $oFolderCollection);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoFolderCreate()
+ {
+ $oAccount = $this->initMailClientConnection();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FOLDERS, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ try
+ {
+ $sFolderNameInUtf = $this->GetActionParam('Folder', '');
+ $sFolderParentFullNameRaw = $this->GetActionParam('Parent', '');
+
+ $this->MailClient()->FolderCreate($sFolderNameInUtf, $sFolderParentFullNameRaw,
+ !!$this->Config()->Get('labs', 'use_imap_list_subscribe', true));
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantCreateFolder, $oException);
+ }
+
+ return $this->TrueResponse(__FUNCTION__);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoFolderSubscribe()
+ {
+ $oAccount = $this->initMailClientConnection();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FOLDERS, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $sFolderFullNameRaw = $this->GetActionParam('Folder', '');
+ $bSubscribe = '1' === (string) $this->GetActionParam('Subscribe', '0');
+
+ try
+ {
+ $this->MailClient()->FolderSubscribe($sFolderFullNameRaw, !!$bSubscribe);
+ }
+ catch (\Exception $oException)
+ {
+ if ($bSubscribe)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSubscribeFolder, $oException);
+ }
+ else
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantUnsubscribeFolder, $oException);
+ }
+ }
+
+ return $this->TrueResponse(__FUNCTION__);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoFolderCheckable()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FOLDERS, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $sFolderFullNameRaw = $this->GetActionParam('Folder', '');
+ $bCheckable = '1' === (string) $this->GetActionParam('Checkable', '0');
+
+ $oSettingsLocal = $this->SettingsProvider(true)->Load($oAccount);
+
+ $sCheckableFolder = $oSettingsLocal->GetConf('CheckableFolder', '[]');
+ $aCheckableFolder = @\json_decode($sCheckableFolder);
+
+ if (!\is_array($aCheckableFolder))
+ {
+ $aCheckableFolder = array();
+ }
+
+ if ($bCheckable)
+ {
+ $aCheckableFolder[] = $sFolderFullNameRaw;
+ }
+ else
+ {
+ $aCheckableFolderNew = array();
+ foreach ($aCheckableFolder as $sFolder)
+ {
+ if ($sFolder !== $sFolderFullNameRaw)
+ {
+ $aCheckableFolderNew[] = $sFolder;
+ }
+ }
+ $aCheckableFolder = $aCheckableFolderNew;
+ }
+
+ $aCheckableFolder = \array_unique($aCheckableFolder);
+
+ $oSettingsLocal->SetConf('CheckableFolder', @\json_encode($aCheckableFolder));
+
+ return $this->DefaultResponse(__FUNCTION__,
+ $this->SettingsProvider(true)->Save($oAccount, $oSettingsLocal));
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoFolderRename()
+ {
+ $oAccount = $this->initMailClientConnection();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FOLDERS, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $sPrevFolderFullNameRaw = $this->GetActionParam('Folder', '');
+ $sNewTopFolderNameInUtf = $this->GetActionParam('NewFolderName', '');
+
+ try
+ {
+ $this->MailClient()->FolderRename($sPrevFolderFullNameRaw, $sNewTopFolderNameInUtf,
+ !!$this->Config()->Get('labs', 'use_imap_list_subscribe', true));
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantRenameFolder, $oException);
+ }
+
+ return $this->TrueResponse(__FUNCTION__);
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoFolderDelete()
+ {
+ $oAccount = $this->initMailClientConnection();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::FOLDERS, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $sFolderFullNameRaw = $this->GetActionParam('Folder', '');
+
+ try
+ {
+ $this->MailClient()->FolderDelete($sFolderFullNameRaw,
+ !!$this->Config()->Get('labs', 'use_imap_list_subscribe', true));
+ }
+ catch (\MailSo\Mail\Exceptions\NonEmptyFolder $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantDeleteNonEmptyFolder, $oException);
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantDeleteFolder, $oException);
+ }
+
+ return $this->TrueResponse(__FUNCTION__);
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoFolderClear()
+ {
+ $this->initMailClientConnection();
+
+ $sFolderFullNameRaw = $this->GetActionParam('Folder', '');
+
+ try
+ {
+ $this->MailClient()->FolderClear($sFolderFullNameRaw);
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::MailServerError, $oException);
+ }
+
+ return $this->TrueResponse(__FUNCTION__);
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoFolderInformation()
+ {
+ $sFolder = $this->GetActionParam('Folder', '');
+ $sPrevUidNext = $this->GetActionParam('UidNext', '');
+ $aFlagsUids = array();
+ $sFlagsUids = (string) $this->GetActionParam('FlagsUids', '');
+
+ $aFlagsFilteredUids = array();
+ if (0 < strlen($sFlagsUids))
+ {
+ $aFlagsUids = explode(',', $sFlagsUids);
+ $aFlagsFilteredUids = array_filter($aFlagsUids, function (&$sUid) {
+ $sUid = (int) trim($sUid);
+ return 0 < (int) trim($sUid);
+ });
+ }
+
+ $this->initMailClientConnection();
+
+ $sForwardedFlag = $this->Config()->Get('labs', 'imap_forwarded_flag', '');
+ $sReadReceiptFlag = $this->Config()->Get('labs', 'imap_read_receipt_flag', '');
+ try
+ {
+ $aInboxInformation = $this->MailClient()->FolderInformation(
+ $sFolder, $sPrevUidNext, $aFlagsFilteredUids
+ );
+
+ if (\is_array($aInboxInformation) && isset($aInboxInformation['Flags']) && \is_array($aInboxInformation['Flags']))
+ {
+ foreach ($aInboxInformation['Flags'] as $iUid => $aFlags)
+ {
+ $aLowerFlags = array_map('strtolower', $aFlags);
+ $aInboxInformation['Flags'][$iUid] = array(
+ 'IsSeen' => in_array('\\seen', $aLowerFlags),
+ 'IsFlagged' => in_array('\\flagged', $aLowerFlags),
+ 'IsAnswered' => in_array('\\answered', $aLowerFlags),
+ 'IsDeleted' => in_array('\\deleted', $aLowerFlags),
+ 'IsForwarded' => 0 < strlen($sForwardedFlag) && in_array(strtolower($sForwardedFlag), $aLowerFlags),
+ 'IsReadReceipt' => 0 < strlen($sReadReceiptFlag) && in_array(strtolower($sReadReceiptFlag), $aLowerFlags)
+ );
+ }
+ }
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::MailServerError, $oException);
+ }
+
+ if (\is_array($aInboxInformation))
+ {
+ $aInboxInformation['Version'] = APP_VERSION;
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $aInboxInformation);
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoFolderInformationMultiply()
+ {
+ $aResult = array(
+ 'List' => array(),
+ 'Version' => APP_VERSION
+ );
+
+ $aFolders = $this->GetActionParam('Folders', null);
+ if (\is_array($aFolders))
+ {
+ $this->initMailClientConnection();
+
+ $aFolders = \array_unique($aFolders);
+ foreach ($aFolders as $sFolder)
+ {
+ if (0 < \strlen(\trim($sFolder)) && 'INBOX' !== \strtoupper($sFolder))
+ {
+ try
+ {
+ $aInboxInformation = $this->MailClient()->FolderInformation($sFolder, '', array());
+ if (\is_array($aInboxInformation) && isset($aInboxInformation['Folder']))
+ {
+ $aResult['List'][] = $aInboxInformation;
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->Logger()->WriteException($oException);
+ }
+ }
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $aResult);
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoMessageList()
+ {
+// \sleep(1);
+// throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList);
+
+ $sFolder = '';
+ $iOffset = 0;
+ $iLimit = 20;
+ $sSearch = '';
+ $sUidNext = '';
+ $bUseThreads = false;
+ $sThreadUid = '';
+
+ $sRawKey = $this->GetActionParam('RawKey', '');
+ $aValues = $this->getDecodedClientRawKeyValue($sRawKey, 9);
+
+ if (\is_array($aValues) && 7 < \count($aValues))
+ {
+ $sFolder =(string) $aValues[0];
+ $iOffset = (int) $aValues[1];
+ $iLimit = (int) $aValues[2];
+ $sSearch = (string) $aValues[3];
+ $sUidNext = (string) $aValues[6];
+ $bUseThreads = (bool) $aValues[7];
+
+ if ($bUseThreads)
+ {
+ $sThreadUid = isset($aValues[8]) ? (string) $aValues[8] : '';
+ }
+
+ $this->verifyCacheByKey($sRawKey);
+ }
+ else
+ {
+ $sFolder = $this->GetActionParam('Folder', '');
+ $iOffset = (int) $this->GetActionParam('Offset', 0);
+ $iLimit = (int) $this->GetActionParam('Limit', 10);
+ $sSearch = $this->GetActionParam('Search', '');
+ $sUidNext = $this->GetActionParam('UidNext', '');
+ $bUseThreads = '1' === (string) $this->GetActionParam('UseThreads', '0');
+
+ if ($bUseThreads)
+ {
+ $sThreadUid = (string) $this->GetActionParam('ThreadUid', '');
+ }
+ }
+
+ if (0 === strlen($sFolder))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList);
+ }
+
+ $this->initMailClientConnection();
+
+ try
+ {
+ if (!$this->Config()->Get('labs', 'use_imap_thread', false))
+ {
+ $bUseThreads = false;
+ }
+
+ $oMessageList = $this->MailClient()->MessageList(
+ $sFolder, $iOffset, $iLimit, $sSearch, $sUidNext,
+ $this->cacherForUids(),
+ !!$this->Config()->Get('labs', 'use_imap_sort', false),
+ $bUseThreads,
+ $sThreadUid,
+ ''
+ );
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessageList, $oException);
+ }
+
+ if ($oMessageList instanceof \MailSo\Mail\MessageCollection)
+ {
+ $this->cacheByKey($sRawKey);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $oMessageList);
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ * @param bool $bWithDraftInfo = true
+ *
+ * @return \MailSo\Mime\Message
+ */
+ private function buildMessage($oAccount, $bWithDraftInfo = true)
+ {
+ $sIdentityID = $this->GetActionParam('IdentityID', '');
+ $sTo = $this->GetActionParam('To', '');
+ $sCc = $this->GetActionParam('Cc', '');
+ $sBcc = $this->GetActionParam('Bcc', '');
+ $sReplyTo = $this->GetActionParam('ReplyTo', '');
+ $sSubject = $this->GetActionParam('Subject', '');
+ $bTextIsHtml = '1' === $this->GetActionParam('TextIsHtml', '0');
+ $bReadReceiptRequest = '1' === $this->GetActionParam('ReadReceiptRequest', '0');
+ $bMarkAsImportant = '1' === $this->GetActionParam('MarkAsImportant', '0');
+ $sText = $this->GetActionParam('Text', '');
+ $aAttachments = $this->GetActionParam('Attachments', null);
+
+ $aDraftInfo = $this->GetActionParam('DraftInfo', null);
+ $sInReplyTo = $this->GetActionParam('InReplyTo', '');
+ $sReferences = $this->GetActionParam('References', '');
+
+ $oMessage = \MailSo\Mime\Message::NewInstance();
+ $oMessage->RegenerateMessageId();
+
+ $oMessage->SetXMailer('RainLoop/'.APP_VERSION);
+
+ $oFromIdentity = $this->GetIdentityByID($oAccount, $sIdentityID);
+ if ($oFromIdentity)
+ {
+ $oMessage->SetFrom(\MailSo\Mime\Email::NewInstance(
+ $oFromIdentity->Email(), $oFromIdentity->Name()));
+ }
+ else
+ {
+ $oMessage->SetFrom(\MailSo\Mime\Email::Parse($oAccount->Email()));
+ }
+
+ if (!empty($sReplyTo))
+ {
+ $oReplyTo = \MailSo\Mime\EmailCollection::NewInstance($sReplyTo);
+ if ($oReplyTo && 0 < $oReplyTo->Count())
+ {
+ $oMessage->SetReplyTo($oReplyTo);
+ }
+ }
+
+ if ($bReadReceiptRequest)
+ {
+ $oMessage->SetReadReceipt($oAccount->Email());
+ }
+
+ if ($bMarkAsImportant)
+ {
+ $oMessage->SetPriority(\MailSo\Mime\Enumerations\MessagePriority::HIGH);
+ }
+
+ $oMessage->SetSubject($sSubject);
+
+ $oToEmails = \MailSo\Mime\EmailCollection::NewInstance($sTo);
+ if ($oToEmails && $oToEmails->Count())
+ {
+ $oMessage->SetTo($oToEmails);
+ }
+
+ $oCcEmails = \MailSo\Mime\EmailCollection::NewInstance($sCc);
+ if ($oCcEmails && $oCcEmails->Count())
+ {
+ $oMessage->SetCc($oCcEmails);
+ }
+
+ $oBccEmails = \MailSo\Mime\EmailCollection::NewInstance($sBcc);
+ if ($oBccEmails && $oBccEmails->Count())
+ {
+ $oMessage->SetBcc($oBccEmails);
+ }
+
+ if ($bWithDraftInfo && \is_array($aDraftInfo) && !empty($aDraftInfo[0]) && !empty($aDraftInfo[1]) && !empty($aDraftInfo[2]))
+ {
+ $oMessage->SetDraftInfo($aDraftInfo[0], $aDraftInfo[1], $aDraftInfo[2]);
+ }
+
+ if (0 < \strlen($sInReplyTo))
+ {
+ $oMessage->SetInReplyTo($sInReplyTo);
+ }
+
+ if (0 < \strlen($sReferences))
+ {
+ $oMessage->SetReferences($sReferences);
+ }
+
+ $aFoundedCids = array();
+ $mFoundDataURL = array();
+ $aFoundedContentLocationUrls = array();
+
+ $sTextToAdd = $bTextIsHtml ?
+ \MailSo\Base\HtmlUtils::BuildHtml($sText, $aFoundedCids, $mFoundDataURL, $aFoundedContentLocationUrls) : $sText;
+
+ $this->Plugins()->RunHook($bTextIsHtml ? 'filter.message-html' : 'filter.message-plain',
+ array($oAccount, &$oMessage, &$sTextToAdd));
+
+ if ($bTextIsHtml && 0 < \strlen($sTextToAdd))
+ {
+ $sTextConverted = \MailSo\Base\HtmlUtils::ConvertHtmlToPlain($sTextToAdd);
+ $this->Plugins()->RunHook('filter.message-plain', array($oAccount, &$oMessage, &$sTextConverted));
+ $oMessage->AddText($sTextConverted, false);
+ }
+
+ $oMessage->AddText($sTextToAdd, $bTextIsHtml);
+
+ if (\is_array($aAttachments))
+ {
+ foreach ($aAttachments as $sTempName => $aData)
+ {
+ $sFileName = (string) $aData[0];
+ $bIsInline = (bool) $aData[1];
+ $sCID = (string) $aData[2];
+ $sContentLocation = isset($aData[3]) ? (string) $aData[3] : '';
+
+ $rResource = $this->FilesProvider()->GetFile($oAccount, $sTempName);
+ if (\is_resource($rResource))
+ {
+ $iFileSize = $this->FilesProvider()->FileSize($oAccount, $sTempName);
+
+ $oMessage->Attachments()->Add(
+ \MailSo\Mime\Attachment::NewInstance($rResource, $sFileName, $iFileSize, $bIsInline,
+ \in_array(trim(trim($sCID), '<>'), $aFoundedCids),
+ $sCID, array(), $sContentLocation
+ )
+ );
+ }
+ }
+ }
+
+ if ($mFoundDataURL && \is_array($mFoundDataURL) && 0 < \count($mFoundDataURL))
+ {
+ foreach ($mFoundDataURL as $sCidHash => $sDataUrlString)
+ {
+ $aMatch = array();
+ $sCID = '<'.$sCidHash.'>';
+ if (\preg_match('/^data:(image\/[a-zA-Z0-9]+);base64,(.+)$/i', $sDataUrlString, $aMatch) &&
+ !empty($aMatch[1]) && !empty($aMatch[2]))
+ {
+ $sRaw = \MailSo\Base\Utils::Base64Decode($aMatch[2]);
+ $iFileSize = \strlen($sRaw);
+ if (0 < $iFileSize)
+ {
+ $sFileName = \preg_replace('/[^a-z0-9]+/i', '.', $aMatch[1]);
+ $rResource = \MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString($sRaw);
+
+ $sRaw = '';
+ unset($sRaw);
+ unset($aMatch);
+
+ $oMessage->Attachments()->Add(
+ \MailSo\Mime\Attachment::NewInstance($rResource, $sFileName, $iFileSize, true, true, $sCID)
+ );
+ }
+ }
+ }
+ }
+
+ $this->Plugins()->RunHook('filter.build-message', array(&$oMessage));
+ $this->Plugins()->RunHook('filter.build-message[2]', array(&$oMessage, $oAccount));
+
+ return $oMessage;
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ *
+ * @return void
+ */
+ private function deleteMessageAttachmnets($oAccount)
+ {
+ $aAttachments = $this->GetActionParam('Attachments', null);
+
+ if (\is_array($aAttachments))
+ {
+ foreach (\array_keys($aAttachments) as $sTempName)
+ {
+ if ($this->FilesProvider()->FileExists($oAccount, $sTempName))
+ {
+ $this->FilesProvider()->Clear($oAccount, $sTempName);
+ }
+ }
+ }
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ *
+ * @return \MailSo\Mime\Message
+ */
+ private function buildReadReceiptMessage($oAccount)
+ {
+ $sReadReceipt = $this->GetActionParam('ReadReceipt', '');
+ $sSubject = $this->GetActionParam('Subject', '');
+ $sText = $this->GetActionParam('Text', '');
+
+ $oIdentity = $this->GetAccountIdentity($oAccount);
+
+ if (empty($sReadReceipt) || empty($sSubject) || empty($sText) || !$oIdentity)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
+ }
+
+ $oMessage = \MailSo\Mime\Message::NewInstance();
+ $oMessage->RegenerateMessageId();
+
+ $oMessage->SetXMailer('RainLoop/'.APP_VERSION);
+
+ $oMessage->SetFrom(\MailSo\Mime\Email::NewInstance($oIdentity->Email(), $oIdentity->Name()));
+
+ $sReplyTo = $oIdentity->ReplyTo();
+ if (!empty($sReplyTo))
+ {
+ $oReplyTo = \MailSo\Mime\EmailCollection::NewInstance($sReplyTo);
+ if ($oReplyTo && $oReplyTo->Count())
+ {
+ $oMessage->SetReplyTo($oReplyTo);
+ }
+ }
+
+ $oMessage->SetSubject($sSubject);
+
+ $oToEmails = \MailSo\Mime\EmailCollection::NewInstance($sReadReceipt);
+ if ($oToEmails && $oToEmails->Count())
+ {
+ $oMessage->SetTo($oToEmails);
+ }
+
+ $this->Plugins()->RunHook('filter.read-receipt-message-plain', array($oAccount, &$oMessage, &$sText));
+
+ $oMessage->AddText($sText, false);
+
+ $this->Plugins()->RunHook('filter.build-read-receipt-message', array(&$oMessage, $oAccount));
+
+ return $oMessage;
+ }
+
+ /**
+ * @return array
+ */
+ public function DoSaveMessage()
+ {
+ $oAccount = $this->initMailClientConnection();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::COMPOSER, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $sMessageFolder = $this->GetActionParam('MessageFolder', '');
+ $sMessageUid = $this->GetActionParam('MessageUid', '');
+
+ $sDraftFolder = $this->GetActionParam('DraftFolder', '');
+ if (0 === strlen($sDraftFolder))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
+ }
+
+ $oMessage = $this->buildMessage($oAccount, true);
+
+ $this->Plugins()
+ ->RunHook('filter.save-message', array(&$oMessage))
+ ->RunHook('filter.save-message[2]', array(&$oMessage, $oAccount))
+ ;
+
+ $mResult = false;
+ if ($oMessage)
+ {
+ $rMessageStream = \MailSo\Base\ResourceRegistry::CreateMemoryResource();
+
+ $iMessageStreamSize = \MailSo\Base\Utils::MultipleStreamWriter(
+ $oMessage->ToStream(false), array($rMessageStream), 8192, true, true);
+
+ if (false !== $iMessageStreamSize)
+ {
+ $sMessageId = $oMessage->MessageId();
+
+ \rewind($rMessageStream);
+
+ $iNewUid = 0;
+ $this->MailClient()->MessageAppendStream(
+ $rMessageStream, $iMessageStreamSize, $sDraftFolder, array(
+ \MailSo\Imap\Enumerations\MessageFlag::SEEN
+ ), $iNewUid);
+
+ if (!empty($sMessageId) && (null === $iNewUid || 0 === $iNewUid))
+ {
+ $iNewUid = $this->MailClient()->FindMessageUidByMessageId($sDraftFolder, $sMessageId);
+ }
+
+ $mResult = true;
+
+ if (0 < strlen($sMessageFolder) && 0 < strlen($sMessageUid))
+ {
+ $this->MailClient()->MessageDelete($sMessageFolder, array($sMessageUid), true, true);
+ }
+
+ if (null !== $iNewUid && 0 < $iNewUid)
+ {
+ $mResult = array(
+ 'NewFolder' => $sDraftFolder,
+ 'NewUid' => $iNewUid
+ );
+ }
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $mResult);
+ }
+
+ /**
+ *
+ * @param \RainLoop\Model\Account $oAccount
+ * @param \MailSo\Mime\Message $oMessage
+ * @param resource $rMessageStream
+ * @param bool $bDsn = false
+ * @param bool $bAddHiddenRcpt = true
+ *
+ * @throws \RainLoop\Exceptions\ClientException
+ * @throws \MailSo\Net\Exceptions\ConnectionException
+ */
+ private function smtpSendMessage($oAccount, $oMessage,
+ &$rMessageStream, &$iMessageStreamSize, $bDsn = false, $bAddHiddenRcpt = true)
+ {
+ $oRcpt = $oMessage->GetRcpt();
+ if ($oRcpt && 0 < $oRcpt->Count())
+ {
+ $this->Plugins()->RunHook('filter.smtp-message-stream',
+ array($oAccount, &$rMessageStream, &$iMessageStreamSize));
+
+ $this->Plugins()->RunHook('filter.message-rcpt', array($oAccount, &$oRcpt));
+
+ try
+ {
+ $oFrom = $oMessage->GetFrom();
+ $sFrom = $oFrom instanceof \MailSo\Mime\Email ? $oFrom->GetEmail() : '';
+ $sFrom = empty($sFrom) ? $oAccount->Email() : $sFrom;
+
+ $this->Plugins()->RunHook('filter.smtp-from', array($oAccount, $oMessage, &$sFrom));
+
+ $aHiddenRcpt = array();
+ if ($bAddHiddenRcpt)
+ {
+ $this->Plugins()->RunHook('filter.smtp-hidden-rcpt', array($oAccount, $oMessage, &$aHiddenRcpt));
+ }
+
+ $bUsePhpMail = $oAccount->Domain()->OutUsePhpMail();
+
+ $oSmtpClient = \MailSo\Smtp\SmtpClient::NewInstance()->SetLogger($this->Logger());
+ $oSmtpClient->SetTimeOuts(10, (int) \RainLoop\Api::Config()->Get('labs', 'smtp_timeout', 60));
+
+ $bLoggined = $oAccount->OutConnectAndLoginHelper($this->Plugins(), $oSmtpClient, $this->Config(), $bUsePhpMail);
+
+ if ($bUsePhpMail)
+ {
+ if (\MailSo\Base\Utils::FunctionExistsAndEnabled('mail'))
+ {
+ $aToCollection = $oMessage->GetTo();
+ if ($aToCollection && $oFrom)
+ {
+ $sRawBody = @\stream_get_contents($rMessageStream);
+ if (!empty($sRawBody))
+ {
+ $sMailTo = \trim($aToCollection->ToString(true));
+ $sMailSubject = \trim($oMessage->GetSubject());
+ $sMailSubject = 0 === \strlen($sMailSubject) ? '' : \MailSo\Base\Utils::EncodeUnencodedValue(
+ \MailSo\Base\Enumerations\Encoding::BASE64_SHORT, $sMailSubject);
+
+ $sMailHeaders = $sMailBody = '';
+ list($sMailHeaders, $sMailBody) = \explode("\r\n\r\n", $sRawBody, 2);
+ unset($sRawBody);
+
+ if ($this->Config()->Get('labs', 'mail_func_clear_headers', true))
+ {
+ $sMailHeaders = \MailSo\Base\Utils::RemoveHeaderFromHeaders($sMailHeaders, array(
+ \MailSo\Mime\Enumerations\Header::TO_,
+ \MailSo\Mime\Enumerations\Header::SUBJECT
+ ));
+ }
+
+ if ($this->Config()->Get('debug', 'enable', false))
+ {
+ $this->Logger()->WriteDump(array(
+ $sMailTo, $sMailSubject, $sMailBody, $sMailHeaders
+ ));
+ }
+
+ $bR = $this->Config()->Get('labs', 'mail_func_additional_parameters', false) ?
+ \mail($sMailTo, $sMailSubject, $sMailBody, $sMailHeaders, '-f'.$oFrom->GetEmail()) :
+ \mail($sMailTo, $sMailSubject, $sMailBody, $sMailHeaders);
+
+ if (!$bR)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSendMessage);
+ }
+ }
+ }
+ }
+ else
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSendMessage);
+ }
+ }
+ else if ($oSmtpClient->IsConnected())
+ {
+ if (!empty($sFrom))
+ {
+ $oSmtpClient->MailFrom($sFrom, '', $bDsn);
+ }
+
+ $aRcpt =& $oRcpt->GetAsArray();
+ foreach ($aRcpt as /* @var $oEmail \MailSo\Mime\Email */ $oEmail)
+ {
+ $oSmtpClient->Rcpt($oEmail->GetEmail(), $bDsn);
+ }
+
+ if ($bAddHiddenRcpt && \is_array($aHiddenRcpt) && 0 < \count($aHiddenRcpt))
+ {
+ foreach ($aHiddenRcpt as $sEmail)
+ {
+ if (\preg_match('/^[^@\s]+@[^@\s]+$/', $sEmail))
+ {
+ $oSmtpClient->Rcpt($sEmail);
+ }
+ }
+ }
+
+ $oSmtpClient->DataWithStream($rMessageStream);
+
+ if ($bLoggined)
+ {
+ $oSmtpClient->Logout();
+ }
+
+ $oSmtpClient->Disconnect();
+ }
+ }
+ catch (\MailSo\Net\Exceptions\ConnectionException $oException)
+ {
+ if ($this->Config()->Get('labs', 'smtp_show_server_errors'))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ClientViewError, $oException);
+ }
+ else
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ConnectionError, $oException);
+ }
+ }
+ catch (\MailSo\Smtp\Exceptions\LoginException $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError, $oException);
+ }
+ catch (\Exception $oException)
+ {
+ if ($this->Config()->Get('labs', 'smtp_show_server_errors'))
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ClientViewError, $oException);
+ }
+ else
+ {
+ throw $oException;
+ }
+ }
+ }
+ else
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidRecipients);
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function DoSendMessage()
+ {
+ $oAccount = $this->initMailClientConnection();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::COMPOSER, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $oConfig = $this->Config();
+
+ $sDraftFolder = $this->GetActionParam('MessageFolder', '');
+ $sDraftUid = $this->GetActionParam('MessageUid', '');
+ $sSentFolder = $this->GetActionParam('SentFolder', '');
+ $aDraftInfo = $this->GetActionParam('DraftInfo', null);
+ $bDsn = '1' === (string) $this->GetActionParam('Dsn', '0');
+
+ $oMessage = $this->buildMessage($oAccount, false);
+
+ $this->Plugins()
+ ->RunHook('filter.send-message', array(&$oMessage))
+ ->RunHook('filter.send-message[2]', array(&$oMessage, $oAccount))
+ ;
+
+ $mResult = false;
+ try
+ {
+ if ($oMessage)
+ {
+ $rMessageStream = \MailSo\Base\ResourceRegistry::CreateMemoryResource();
+
+ $iMessageStreamSize = \MailSo\Base\Utils::MultipleStreamWriter(
+ $oMessage->ToStream(true), array($rMessageStream), 8192, true, true, true);
+
+ if (false !== $iMessageStreamSize)
+ {
+ $this->smtpSendMessage($oAccount, $oMessage, $rMessageStream, $iMessageStreamSize, $bDsn, true);
+
+ if (\is_array($aDraftInfo) && 3 === \count($aDraftInfo))
+ {
+ $sDraftInfoType = $aDraftInfo[0];
+ $sDraftInfoUid = $aDraftInfo[1];
+ $sDraftInfoFolder = $aDraftInfo[2];
+
+ try
+ {
+ switch (\strtolower($sDraftInfoType))
+ {
+ case 'reply':
+ case 'reply-all':
+ $this->MailClient()->MessageSetFlag($sDraftInfoFolder, array($sDraftInfoUid), true,
+ \MailSo\Imap\Enumerations\MessageFlag::ANSWERED, true);
+ break;
+ case 'forward':
+ $sForwardedFlag = $this->Config()->Get('labs', 'imap_forwarded_flag', '');
+ if (0 < strlen($sForwardedFlag))
+ {
+ $this->MailClient()->MessageSetFlag($sDraftInfoFolder, array($sDraftInfoUid), true,
+ $sForwardedFlag, true);
+ }
+ break;
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+ }
+
+ if (0 < \strlen($sSentFolder))
+ {
+ try
+ {
+ if (!$oMessage->GetBcc())
+ {
+ if (\is_resource($rMessageStream))
+ {
+ \rewind($rMessageStream);
+ }
+
+ $this->Plugins()->RunHook('filter.sent-message-stream',
+ array($oAccount, &$rMessageStream, &$iMessageStreamSize));
+
+ $this->MailClient()->MessageAppendStream(
+ $rMessageStream, $iMessageStreamSize, $sSentFolder, array(
+ \MailSo\Imap\Enumerations\MessageFlag::SEEN
+ )
+ );
+ }
+ else
+ {
+ $rAppendMessageStream = \MailSo\Base\ResourceRegistry::CreateMemoryResource();
+
+ $iAppendMessageStreamSize = \MailSo\Base\Utils::MultipleStreamWriter(
+ $oMessage->ToStream(false), array($rAppendMessageStream), 8192, true, true, true);
+
+ $this->Plugins()->RunHook('filter.sent-message-stream',
+ array($oAccount, &$rAppendMessageStream, &$iAppendMessageStreamSize));
+
+ $this->MailClient()->MessageAppendStream(
+ $rAppendMessageStream, $iAppendMessageStreamSize, $sSentFolder, array(
+ \MailSo\Imap\Enumerations\MessageFlag::SEEN
+ ));
+
+ if (\is_resource($rAppendMessageStream))
+ {
+ @fclose($rAppendMessageStream);
+ }
+ }
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSaveMessage, $oException);
+ }
+ }
+
+ if (\is_resource($rMessageStream))
+ {
+ @\fclose($rMessageStream);
+ }
+
+ $this->deleteMessageAttachmnets($oAccount);
+
+ if (0 < \strlen($sDraftFolder) && 0 < \strlen($sDraftUid))
+ {
+ try
+ {
+ $this->MailClient()->MessageDelete($sDraftFolder, array($sDraftUid), true, true);
+ }
+ catch (\Exception $oException)
+ {
+ $this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+ }
+
+ $mResult = true;
+ }
+ }
+ }
+ catch (\RainLoop\Exceptions\ClientException $oException)
+ {
+ throw $oException;
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSendMessage, $oException);
+ }
+
+ if (false === $mResult)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSendMessage);
+ }
+
+ try
+ {
+ if ($oMessage && $this->AddressBookProvider($oAccount)->IsActive())
+ {
+ $aArrayToFrec = array();
+ $oToCollection = $oMessage->GetTo();
+ if ($oToCollection)
+ {
+ $aTo =& $oToCollection->GetAsArray();
+ foreach ($aTo as /* @var $oEmail \MailSo\Mime\Email */ $oEmail)
+ {
+ $aArrayToFrec[$oEmail->GetEmail(true)] = $oEmail->ToString(false, true);
+ }
+ }
+
+ if (0 < \count($aArrayToFrec))
+ {
+ $oSettings = $this->SettingsProvider()->Load($oAccount);
+
+ $this->AddressBookProvider($oAccount)->IncFrec(
+ $oAccount->ParentEmailHelper(), \array_values($aArrayToFrec),
+ !!$oSettings->GetConf('ContactsAutosave',
+ !!$oConfig->Get('defaults', 'contacts_autosave', true)));
+ }
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->Logger()->WriteException($oException);
+ }
+
+ return $this->TrueResponse(__FUNCTION__);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoSendReadReceiptMessage()
+ {
+ $oAccount = $this->initMailClientConnection();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::COMPOSER, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $oMessage = $this->buildReadReceiptMessage($oAccount);
+
+ $this->Plugins()->RunHook('filter.send-read-receipt-message', array(&$oMessage, $oAccount));
+
+ $mResult = false;
+ try
+ {
+ if ($oMessage)
+ {
+ $rMessageStream = \MailSo\Base\ResourceRegistry::CreateMemoryResource();
+
+ $iMessageStreamSize = \MailSo\Base\Utils::MultipleStreamWriter(
+ $oMessage->ToStream(true), array($rMessageStream), 8192, true, true, true);
+
+ if (false !== $iMessageStreamSize)
+ {
+ $this->smtpSendMessage($oAccount, $oMessage, $rMessageStream, $iMessageStreamSize, false, false);
+
+ if (\is_resource($rMessageStream))
+ {
+ @\fclose($rMessageStream);
+ }
+
+ $mResult = true;
+
+ $sReadReceiptFlag = $this->Config()->Get('labs', 'imap_read_receipt_flag', '');
+ if (!empty($sReadReceiptFlag))
+ {
+ $sFolderFullName = $this->GetActionParam('MessageFolder', '');
+ $sUid = $this->GetActionParam('MessageUid', '');
+
+ $this->Cacher($oAccount)->Set(\RainLoop\KeyPathHelper::ReadReceiptCache($oAccount->Email(), $sFolderFullName, $sUid), '1');
+
+ if (0 < \strlen($sFolderFullName) && 0 < \strlen($sUid))
+ {
+ try
+ {
+ $this->MailClient()->MessageSetFlag($sFolderFullName, array($sUid), true, $sReadReceiptFlag, true, true);
+ }
+ catch (\Exception $oException) {}
+ }
+ }
+ }
+ }
+ }
+ catch (\RainLoop\Exceptions\ClientException $oException)
+ {
+ throw $oException;
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSendMessage, $oException);
+ }
+
+ if (false === $mResult)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSendMessage);
+ }
+
+ return $this->TrueResponse(__FUNCTION__);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoQuota()
+ {
+ $oAccount = $this->initMailClientConnection();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::QUOTA, $oAccount))
+ {
+ return $this->DefaultResponse(__FUNCTION__, array(0, 0, 0, 0));
+ }
+
+ try
+ {
+ $aQuota = $this->MailClient()->Quota();
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::MailServerError, $oException);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $aQuota);
+ }
+
+ private function getContactsSyncData($oAccount)
+ {
+ $mResult = null;
+
+ $sData = $this->StorageProvider()->Get($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'contacts_sync'
+ );
+
+ if (!empty($sData))
+ {
+ $mData = \RainLoop\Utils::DecodeKeyValues($sData);
+ if (\is_array($mData))
+ {
+ $mResult = array(
+ 'Enable' => isset($mData['Enable']) ? !!$mData['Enable'] : false,
+ 'Url' => isset($mData['Url']) ? \trim($mData['Url']) : '',
+ 'User' => isset($mData['User']) ? \trim($mData['User']) : '',
+ 'Password' => isset($mData['Password']) ? $mData['Password'] : ''
+ );
+ }
+ }
+
+ return $mResult;
+ }
+
+ /**
+ * @return array
+ */
+ public function DoSaveContactsSyncData()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ $oAddressBookProvider = $this->AddressBookProvider($oAccount);
+ if (!$oAddressBookProvider || !$oAddressBookProvider->IsActive())
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $bEnabled = '1' === (string) $this->GetActionParam('Enable', '0');
+ $sUrl = $this->GetActionParam('Url', '');
+ $sUser = $this->GetActionParam('User', '');
+ $sPassword = $this->GetActionParam('Password', '');
+
+ $mData = $this->getContactsSyncData($oAccount);
+
+ $bResult = $this->StorageProvider()->Put($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'contacts_sync',
+ \RainLoop\Utils::EncodeKeyValues(array(
+ 'Enable' => $bEnabled,
+ 'User' => $sUser,
+ 'Password' => APP_DUMMY === $sPassword && isset($mData['Password']) ?
+ $mData['Password'] : (APP_DUMMY === $sPassword ? '' : $sPassword),
+ 'Url' => $sUrl
+ ))
+ );
+
+ return $this->DefaultResponse(__FUNCTION__, $bResult);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoContactsSync()
+ {
+ $bResult = false;
+ $oAccount = $this->getAccountFromToken();
+
+ $oAddressBookProvider = $this->AddressBookProvider($oAccount);
+ if ($oAddressBookProvider && $oAddressBookProvider->IsActive())
+ {
+ $mData = $this->getContactsSyncData($oAccount);
+ if (\is_array($mData) && isset($mData['Enable'], $mData['User'], $mData['Password'], $mData['Url']) && $mData['Enable'])
+ {
+ $bResult = $oAddressBookProvider->Sync(
+ $oAccount->ParentEmailHelper(),
+ $mData['Url'], $mData['User'], $mData['Password']);
+ }
+ }
+
+ if (!$bResult)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ContactsSyncError);
+ }
+
+ return $this->TrueResponse(__FUNCTION__);
+ }
+
+ private function getTwoFactorInfo($oAccount, $bRemoveSecret = false)
+ {
+ $sEmail = $oAccount->ParentEmailHelper();
+
+ $mData = null;
+
+ $aResult = array(
+ 'User' => '',
+ 'IsSet' => false,
+ 'Enable' => false,
+ 'Secret' => '',
+ 'Url' => '',
+ 'BackupCodes' => ''
+ );
+
+ if (!empty($sEmail))
+ {
+ $aResult['User'] = $sEmail;
+
+ $sData = $this->StorageProvider()->Get($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'two_factor'
+ );
+
+ if ($sData)
+ {
+ $mData = \RainLoop\Utils::DecodeKeyValues($sData);
+ }
+ }
+
+ if (\is_array($mData) && !empty($aResult['User']) &&
+ !empty($mData['User']) && !empty($mData['Secret']) &&
+ !empty($mData['BackupCodes']) && $sEmail === $mData['User'])
+ {
+ $aResult['IsSet'] = true;
+ $aResult['Enable'] = isset($mData['Enable']) ? !!$mData['Enable'] : false;
+ $aResult['Secret'] = $mData['Secret'];
+ $aResult['BackupCodes'] = $mData['BackupCodes'];
+
+ $aResult['Url'] = $this->TwoFactorAuthProvider()->GetQRCodeGoogleUrl(
+ $aResult['User'], $aResult['Secret'], $this->Config()->Get('webmail', 'title', ''));
+ }
+
+ if ($bRemoveSecret)
+ {
+ if (isset($aResult['Secret']))
+ {
+ unset($aResult['Secret']);
+ }
+
+ if (isset($aResult['Url']))
+ {
+ unset($aResult['Url']);
+ }
+
+ if (isset($aResult['BackupCodes']))
+ {
+ unset($aResult['BackupCodes']);
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ * @param string $sCode
+ *
+ * @return bool
+ */
+ private function removeBackupCodeFromTwoFactorInfo($oAccount, $sCode)
+ {
+ if (!$oAccount || empty($sCode))
+ {
+ return false;
+ }
+
+ $sData = $this->StorageProvider()->Get($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'two_factor'
+ );
+
+ if ($sData)
+ {
+ $mData = \RainLoop\Utils::DecodeKeyValues($sData);
+
+ if (!empty($mData['BackupCodes']))
+ {
+ $sBackupCodes = \preg_replace('/[^\d]+/', ' ', ' '.$mData['BackupCodes'].' ');
+ $sBackupCodes = \str_replace(' '.$sCode.' ', '', $sBackupCodes);
+
+ $mData['BackupCodes'] = \trim(\preg_replace('/[^\d]+/', ' ', $sBackupCodes));
+
+ return $this->StorageProvider()->Put($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'two_factor',
+ \RainLoop\Utils::EncodeKeyValues($mData)
+ );
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @return array
+ */
+ public function DoGetTwoFactorInfo()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->TwoFactorAuthProvider()->IsActive() ||
+ !$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TWO_FACTOR, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__,
+ $this->getTwoFactorInfo($oAccount, true));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoCreateTwoFactorSecret()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->TwoFactorAuthProvider()->IsActive() ||
+ !$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TWO_FACTOR, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $sEmail = $oAccount->ParentEmailHelper();
+
+ $sSecret = $this->TwoFactorAuthProvider()->CreateSecret();
+
+ $aCodes = array();
+ for ($iIndex = 9; $iIndex > 0; $iIndex--)
+ {
+ $aCodes[] = \rand(100000000, 900000000);
+ }
+
+ $this->StorageProvider()->Put($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'two_factor',
+ \RainLoop\Utils::EncodeKeyValues(array(
+ 'User' => $sEmail,
+ 'Enable' => false,
+ 'Secret' => $sSecret,
+ 'BackupCodes' => \implode(' ', $aCodes)
+ ))
+ );
+
+ $this->requestSleep();
+
+ return $this->DefaultResponse(__FUNCTION__,
+ $this->getTwoFactorInfo($oAccount));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoShowTwoFactorSecret()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->TwoFactorAuthProvider()->IsActive() ||
+ !$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TWO_FACTOR, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $aResult = $this->getTwoFactorInfo($oAccount);
+ if (\is_array($aResult))
+ {
+ unset($aResult['BackupCodes']);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $aResult);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoEnableTwoFactor()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->TwoFactorAuthProvider()->IsActive() ||
+ !$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TWO_FACTOR, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $sEmail = $oAccount->ParentEmailHelper();
+
+ $bResult = false;
+ $mData = $this->getTwoFactorInfo($oAccount);
+ if (isset($mData['Secret'], $mData['BackupCodes']))
+ {
+ $bResult = $this->StorageProvider()->Put($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'two_factor',
+ \RainLoop\Utils::EncodeKeyValues(array(
+ 'User' => $sEmail,
+ 'Enable' => '1' === \trim($this->GetActionParam('Enable', '0')),
+ 'Secret' => $mData['Secret'],
+ 'BackupCodes' => $mData['BackupCodes']
+ ))
+ );
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $bResult);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoTestTwoFactorInfo()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->TwoFactorAuthProvider()->IsActive() ||
+ !$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TWO_FACTOR, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $sCode = \trim($this->GetActionParam('Code', ''));
+
+ $aData = $this->getTwoFactorInfo($oAccount);
+ $sSecret = !empty($aData['Secret']) ? $aData['Secret'] : '';
+
+// $this->Logger()->WriteDump(array(
+// $sCode, $sSecret, $aData,
+// $this->TwoFactorAuthProvider()->VerifyCode($sSecret, $sCode)
+// ));
+
+ $this->requestSleep();
+
+ return $this->DefaultResponse(__FUNCTION__,
+ $this->TwoFactorAuthProvider()->VerifyCode($sSecret, $sCode));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoClearTwoFactorInfo()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->TwoFactorAuthProvider()->IsActive() ||
+ !$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::TWO_FACTOR, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $this->StorageProvider()->Clear($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'two_factor'
+ );
+
+ return $this->DefaultResponse(__FUNCTION__,
+ $this->getTwoFactorInfo($oAccount, true));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoContacts()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ $sSearch = \trim($this->GetActionParam('Search', ''));
+ $iOffset = (int) $this->GetActionParam('Offset', 0);
+ $iLimit = (int) $this->GetActionParam('Limit', 20);
+ $iOffset = 0 > $iOffset ? 0 : $iOffset;
+ $iLimit = 0 > $iLimit ? 20 : $iLimit;
+
+ $iResultCount = 0;
+ $mResult = array();
+
+ $oAbp = $this->AddressBookProvider($oAccount);
+ if ($oAbp->IsActive())
+ {
+ $iResultCount = 0;
+ $mResult = $oAbp->GetContacts($oAccount->ParentEmailHelper(),
+ $iOffset, $iLimit, $sSearch, $iResultCount);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, array(
+ 'Offset' => $iOffset,
+ 'Limit' => $iLimit,
+ 'Count' => $iResultCount,
+ 'Search' => $sSearch,
+ 'List' => $mResult
+ ));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoContactsDelete()
+ {
+ $oAccount = $this->getAccountFromToken();
+ $aUids = \explode(',', (string) $this->GetActionParam('Uids', ''));
+
+ $aFilteredUids = \array_filter($aUids, function (&$mUid) {
+ $mUid = (int) \trim($mUid);
+ return 0 < $mUid;
+ });
+
+ $bResult = false;
+ if (0 < \count($aFilteredUids) && $this->AddressBookProvider($oAccount)->IsActive())
+ {
+ $bResult = $this->AddressBookProvider($oAccount)->DeleteContacts($oAccount->ParentEmailHelper(), $aFilteredUids);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $bResult);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoContactSave()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ $bResult = false;
+
+ $oAddressBookProvider = $this->AddressBookProvider($oAccount);
+ $sRequestUid = \trim($this->GetActionParam('RequestUid', ''));
+ if ($oAddressBookProvider && $oAddressBookProvider->IsActive() && 0 < \strlen($sRequestUid))
+ {
+ $sUid = \trim($this->GetActionParam('Uid', ''));
+
+ $oContact = null;
+ if (0 < \strlen($sUid))
+ {
+ $oContact = $oAddressBookProvider->GetContactByID($oAccount->ParentEmailHelper(), $sUid);
+ }
+
+ if (!$oContact)
+ {
+ $oContact = new \RainLoop\Providers\AddressBook\Classes\Contact();
+ if (0 < \strlen($sUid))
+ {
+ $oContact->IdContact = $sUid;
+ }
+ }
+
+ $oContact->Properties = array();
+ $aProperties = $this->GetActionParam('Properties', array());
+ if (\is_array($aProperties))
+ {
+ foreach ($aProperties as $aItem)
+ {
+ if ($aItem && isset($aItem[0], $aItem[1]) && \is_numeric($aItem[0]))
+ {
+ $oProp = new \RainLoop\Providers\AddressBook\Classes\Property();
+ $oProp->Type = (int) $aItem[0];
+ $oProp->Value = $aItem[1];
+ $oProp->TypeStr = empty($aItem[2]) ? '': $aItem[2];
+
+ $oContact->Properties[] = $oProp;
+ }
+ }
+ }
+
+ if (!empty($oContact->Etag))
+ {
+ $oContact->Etag = \md5($oContact->ToVCard());
+ }
+
+ $oContact->PopulateDisplayAndFullNameValue(true);
+
+ $bResult = $oAddressBookProvider->ContactSave($oAccount->ParentEmailHelper(), $oContact);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, array(
+ 'RequestUid' => $sRequestUid,
+ 'ResultID' => $bResult ? $oContact->IdContact : '',
+ 'Result' => $bResult
+ ));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoSuggestions()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ $sQuery = \trim($this->GetActionParam('Query', ''));
+ $iLimit = (int) $this->Config()->Get('contacts', 'suggestions_limit', 20);
+
+ $aResult = array();
+
+ $this->Plugins()->RunHook('ajax.suggestions-input-parameters', array(&$sQuery, &$iLimit, $oAccount));
+
+ $iLimit = (int) $iLimit;
+ if (5 > $iLimit)
+ {
+ $iLimit = 5;
+ }
+
+ $this->Plugins()->RunHook('ajax.suggestions-pre', array(&$aResult, $sQuery, $oAccount, $iLimit));
+
+ if ($iLimit > \count($aResult) && 0 < \strlen($sQuery))
+ {
+ try
+ {
+ // Address Book
+ $oAddressBookProvider = $this->AddressBookProvider($oAccount);
+ if ($oAddressBookProvider && $oAddressBookProvider->IsActive())
+ {
+ $aSuggestions = $oAddressBookProvider->GetSuggestions($oAccount->ParentEmailHelper(), $sQuery, $iLimit);
+ if (0 === \count($aResult))
+ {
+ $aResult = $aSuggestions;
+ }
+ else
+ {
+ $aResult = \array_merge($aResult, $aSuggestions);
+ }
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->Logger()->WriteException($oException);
+ }
+ }
+
+ if ($iLimit > \count($aResult) && 0 < \strlen($sQuery))
+ {
+ $oSuggestionsProvider = $this->SuggestionsProvider();
+ if ($oSuggestionsProvider && $oSuggestionsProvider->IsActive())
+ {
+ $aSuggestionsProviderResult = $oSuggestionsProvider->Process($oAccount, $sQuery, $iLimit);
+ if (\is_array($aSuggestionsProviderResult) && 0 < \count($aSuggestionsProviderResult))
+ {
+ $aResult = \array_merge($aResult, $aSuggestionsProviderResult);
+ }
+ }
+
+ }
+
+ $aResult = \RainLoop\Utils::RemoveSuggestionDuplicates($aResult);
+ if ($iLimit < \count($aResult))
+ {
+ $aResult = \array_slice($aResult, 0, $iLimit);
+ }
+
+ $this->Plugins()->RunHook('ajax.suggestions-post', array(&$aResult, $sQuery, $oAccount, $iLimit));
+
+ $aResult = \RainLoop\Utils::RemoveSuggestionDuplicates($aResult);
+ if ($iLimit < \count($aResult))
+ {
+ $aResult = \array_slice($aResult, 0, $iLimit);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $aResult);
+ }
+
+ /**
+ * @return array
+ */
+ private function messageSetFlag($sActionFunction, $sResponseFunction)
+ {
+ $this->initMailClientConnection();
+
+ $sFolder = $this->GetActionParam('Folder', '');
+ $bSetAction = '1' === (string) $this->GetActionParam('SetAction', '0');
+ $aUids = \explode(',', (string) $this->GetActionParam('Uids', ''));
+ $aFilteredUids = \array_filter($aUids, function (&$sUid) {
+ $sUid = (int) \trim($sUid);
+ return 0 < $sUid;
+ });
+
+ try
+ {
+ $this->MailClient()->{$sActionFunction}($sFolder, $aFilteredUids, true, $bSetAction, true);
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::MailServerError, $oException);
+ }
+
+ return $this->TrueResponse($sResponseFunction);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoMessageSetSeen()
+ {
+ return $this->messageSetFlag('MessageSetSeen', __FUNCTION__);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoMessageSetSeenToAll()
+ {
+ $this->initMailClientConnection();
+
+ $sFolder = $this->GetActionParam('Folder', '');
+ $bSetAction = '1' === (string) $this->GetActionParam('SetAction', '0');
+
+ try
+ {
+ $this->MailClient()->MessageSetSeenToAll($sFolder, $bSetAction);
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::MailServerError, $oException);
+ }
+
+ return $this->TrueResponse(__FUNCTION__);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoMessageSetFlagged()
+ {
+ return $this->messageSetFlag('MessageSetFlagged', __FUNCTION__);
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoMessage()
+ {
+ $sRawKey = (string) $this->GetActionParam('RawKey', '');
+
+ $sFolder = '';
+ $iUid = 0;
+
+ $aValues = $this->getDecodedClientRawKeyValue($sRawKey, 4);
+ if (is_array($aValues) && 4 === count($aValues))
+ {
+ $sFolder = (string) $aValues[0];
+ $iUid = (int) $aValues[1];
+
+ $this->verifyCacheByKey($sRawKey);
+ }
+ else
+ {
+ $sFolder = $this->GetActionParam('Folder', '');
+ $iUid = (int) $this->GetActionParam('Uid', 0);
+ }
+
+ $oAccount = $this->initMailClientConnection();
+
+ try
+ {
+ $oMessage = $this->MailClient()->Message($sFolder, $iUid, true,
+ $this->cacherForThreads(),
+ (int) $this->Config()->Get('labs', 'imap_body_text_limit', 0)
+ );
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetMessage, $oException);
+ }
+
+ if ($oMessage instanceof \MailSo\Mail\Message)
+ {
+ $this->Plugins()
+ ->RunHook('filter.result-message', array(&$oMessage))
+ ->RunHook('filter.result-message[2]', array(&$oMessage, $oAccount))
+ ;
+
+ $this->cacheByKey($sRawKey);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $oMessage);
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoMessageDelete()
+ {
+ $this->initMailClientConnection();
+
+ $sFolder = $this->GetActionParam('Folder', '');
+ $aUids = \explode(',', (string) $this->GetActionParam('Uids', ''));
+
+ $aFilteredUids = \array_filter($aUids, function (&$sUid) {
+ $sUid = (int) \trim($sUid);
+ return 0 < $sUid;
+ });
+
+ try
+ {
+ $this->MailClient()->MessageDelete($sFolder, $aFilteredUids, true, true,
+ !!$this->Config()->Get('labs', 'use_imap_expunge_all_on_delete', false));
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantDeleteMessage, $oException);
+ }
+
+ if ($this->Config()->Get('labs', 'use_imap_unselect', true))
+ {
+ try
+ {
+ $this->MailClient()->FolderUnSelect();
+ }
+ catch (\Exception $oException)
+ {
+ unset($oException);
+ }
+ }
+
+ $sHash = '';
+
+ try
+ {
+ $sHash = $this->MailClient()->FolderHash($sFolder);
+ }
+ catch (\Exception $oException)
+ {
+ unset($oException);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, '' === $sHash ? false : array($sFolder, $sHash));
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoMessageMove()
+ {
+ $this->initMailClientConnection();
+
+ $sFromFolder = $this->GetActionParam('FromFolder', '');
+ $sToFolder = $this->GetActionParam('ToFolder', '');
+ $aUids = \explode(',', (string) $this->GetActionParam('Uids', ''));
+ $bMarkAsRead = '1' === (string) $this->GetActionParam('MarkAsRead', '0');
+
+ $aFilteredUids = \array_filter($aUids, function (&$mUid) {
+ $mUid = (int) \trim($mUid);
+ return 0 < $mUid;
+ });
+
+ if ($bMarkAsRead)
+ {
+ try
+ {
+ $this->MailClient()->MessageSetSeen($sFromFolder, $aFilteredUids, true, true);
+ }
+ catch (\Exception $oException)
+ {
+ unset($oException);
+ }
+ }
+
+ try
+ {
+ $this->MailClient()->MessageMove($sFromFolder, $sToFolder, $aFilteredUids, true,
+ !!$this->Config()->Get('labs', 'use_imap_move', true),
+ !!$this->Config()->Get('labs', 'use_imap_expunge_all_on_delete', false)
+ );
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantMoveMessage, $oException);
+ }
+
+ if ($this->Config()->Get('labs', 'use_imap_unselect', true))
+ {
+ try
+ {
+ $this->MailClient()->FolderUnSelect();
+ }
+ catch (\Exception $oException)
+ {
+ unset($oException);
+ }
+ }
+
+ $sHash = '';
+
+ try
+ {
+ $sHash = $this->MailClient()->FolderHash($sFromFolder);
+ }
+ catch (\Exception $oException)
+ {
+ unset($oException);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, '' === $sHash ? false : array($sFromFolder, $sHash));
+ }
+
+ /**
+ * @return array
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function DoMessageCopy()
+ {
+ $this->initMailClientConnection();
+
+ $sFromFolder = $this->GetActionParam('FromFolder', '');
+ $sToFolder = $this->GetActionParam('ToFolder', '');
+ $aUids = \explode(',', (string) $this->GetActionParam('Uids', ''));
+
+ $aFilteredUids = \array_filter($aUids, function (&$mUid) {
+ $mUid = (int) \trim($mUid);
+ return 0 < $mUid;
+ });
+
+ try
+ {
+ $this->MailClient()->MessageCopy($sFromFolder, $sToFolder,
+ $aFilteredUids, true);
+
+ $sHash = $this->MailClient()->FolderHash($sFromFolder);
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantCopyMessage, $oException);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__,
+ '' === $sHash ? false : array($sFromFolder, $sHash));
+ }
+
+ /**
+ * @param string $sFileName
+ * @param string $sContentType
+ * @param string $sMimeIndex
+ * @param int $iMaxLength = 250
+ *
+ * @return string
+ */
+ public function MainClearFileName($sFileName, $sContentType, $sMimeIndex, $iMaxLength = 250)
+ {
+ $sFileName = 0 === \strlen($sFileName) ? \preg_replace('/[^a-zA-Z0-9]/', '.', (empty($sMimeIndex) ? '' : $sMimeIndex.'.').$sContentType) : $sFileName;
+ $sClearedFileName = \MailSo\Base\Utils::StripSpaces(\preg_replace('/[\.]+/', '.', $sFileName));
+ $sExt = \MailSo\Base\Utils::GetFileExtension($sClearedFileName);
+
+ if (10 < $iMaxLength && $iMaxLength < \strlen($sClearedFileName) - \strlen($sExt))
+ {
+ $sClearedFileName = \substr($sClearedFileName, 0, $iMaxLength).(empty($sExt) ? '' : '.'.$sExt);
+ }
+
+ return \MailSo\Base\Utils::ClearFileName(\MailSo\Base\Utils::Utf8Clear($sClearedFileName));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoMessageUploadAttachments()
+ {
+ $oAccount = $this->initMailClientConnection();
+
+ $mResult = false;
+ $self = $this;
+
+ try
+ {
+ $aAttachments = $this->GetActionParam('Attachments', array());
+ if (\is_array($aAttachments) && 0 < \count($aAttachments))
+ {
+ $mResult = array();
+ foreach ($aAttachments as $sAttachment)
+ {
+ $aValues = \RainLoop\Utils::DecodeKeyValuesQ($sAttachment);
+ if (\is_array($aValues))
+ {
+ $sFolder = isset($aValues['Folder']) ? $aValues['Folder'] : '';
+ $iUid = (int) isset($aValues['Uid']) ? $aValues['Uid'] : 0;
+ $sMimeIndex = (string) isset($aValues['MimeIndex']) ? $aValues['MimeIndex'] : '';
+
+ $sTempName = \md5($sAttachment);
+ if (!$this->FilesProvider()->FileExists($oAccount, $sTempName))
+ {
+ $this->MailClient()->MessageMimeStream(
+ function($rResource, $sContentType, $sFileName, $sMimeIndex = '') use ($oAccount, &$mResult, $sTempName, $sAttachment, $self) {
+ if (is_resource($rResource))
+ {
+ $sContentType = (empty($sFileName)) ? 'text/plain' : \MailSo\Base\Utils::MimeContentType($sFileName);
+ $sFileName = $self->MainClearFileName($sFileName, $sContentType, $sMimeIndex);
+
+ if ($self->FilesProvider()->PutFile($oAccount, $sTempName, $rResource))
+ {
+ $mResult[$sTempName] = $sAttachment;
+ }
+ }
+ }, $sFolder, $iUid, true, $sMimeIndex);
+ }
+ else
+ {
+ $mResult[$sTempName] = $sAttachment;
+ }
+ }
+ }
+ }
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::MailServerError, $oException);
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $mResult);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoComposeUploadExternals()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ $mResult = false;
+ $aExternals = $this->GetActionParam('Externals', array());
+ if (\is_array($aExternals) && 0 < \count($aExternals))
+ {
+ $oHttp = \MailSo\Base\Http::SingletonInstance();
+
+ $mResult = array();
+ foreach ($aExternals as $sUrl)
+ {
+ $mResult[$sUrl] = '';
+
+ $sTempName = \md5($sUrl);
+
+ $iCode = 0;
+ $sContentType = '';
+
+ $rFile = $this->FilesProvider()->GetFile($oAccount, $sTempName, 'wb+');
+ if ($rFile && $oHttp->SaveUrlToFile($sUrl, $rFile, '', $sContentType, $iCode, $this->Logger(), 60,
+ $this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', '')))
+ {
+ $mResult[$sUrl] = $sTempName;
+ }
+
+ if (\is_resource($rFile))
+ {
+ @\fclose($rFile);
+ }
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $mResult);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoComposeUploadDrive()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ $mResult = false;
+
+ $sUrl = $this->GetActionParam('Url', '');
+ $sAccessToken = $this->GetActionParam('AccessToken', '');
+ $sGoogleApiKey = (string) $this->Config()->Get('social', 'google_api_key', '');
+
+ if (0 < \strlen($sUrl) && 0 < \strlen($sAccessToken) && 0 < \strlen($sGoogleApiKey))
+ {
+ $oHttp = \MailSo\Base\Http::SingletonInstance();
+
+ $mResult[$sUrl] = false;
+
+ $sTempName = \md5($sUrl);
+
+ $iCode = 0;
+ $sContentType = '';
+
+ $rFile = $this->FilesProvider()->GetFile($oAccount, $sTempName, 'wb+');
+ if ($rFile && $oHttp->SaveUrlToFile($sUrl.'&key='.$sGoogleApiKey, $rFile, '', $sContentType, $iCode, $this->Logger(), 60,
+ $this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', ''),
+ array('Authorization: Bearer '.$sAccessToken)))
+ {
+ $mResult[$sUrl] = array($sTempName, 0);
+ }
+
+ if (\is_resource($rFile))
+ {
+ @\fclose($rFile);
+ }
+
+ if (isset($mResult[$sUrl][1]))
+ {
+ $mResult[$sUrl][1] = $rFile = $this->FilesProvider()->FileSize($oAccount, $sTempName);
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $mResult);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoSocialUsers()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ $oSettings = $this->SettingsProvider()->Load($oAccount);
+
+ $aData = array(
+ 'Google' => '',
+ 'Facebook' => '',
+ 'Twitter' => ''
+ );
+
+ if ($oSettings)
+ {
+ $aData['Google'] = $oSettings->GetConf('GoogleSocialName', '');
+ $aData['Facebook'] = $oSettings->GetConf('FacebookSocialName', '');
+ $aData['Twitter'] = $oSettings->GetConf('TwitterSocialName', '');
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $aData);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoSocialGoogleDisconnect()
+ {
+ $oAccount = $this->getAccountFromToken();
+ return $this->DefaultResponse(__FUNCTION__, $this->Social()->GoogleDisconnect($oAccount));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoSocialTwitterDisconnect()
+ {
+ $oAccount = $this->getAccountFromToken();
+ return $this->DefaultResponse(__FUNCTION__, $this->Social()->TwitterDisconnect($oAccount));
+ }
+
+ /**
+ * @return array
+ */
+ public function DoSocialFacebookDisconnect()
+ {
+ $oAccount = $this->getAccountFromToken();
+ return $this->DefaultResponse(__FUNCTION__, $this->Social()->FacebookDisconnect($oAccount));
+ }
+
+ /**
+ * @param int $iError
+ * @param int $iClientError
+ *
+ * @return string
+ */
+ private function getUploadErrorMessageByCode($iError, &$iClientError)
+ {
+ $sError = '';
+ $iClientError = UploadClientError::NORMAL;
+ switch($iError)
+ {
+ case UPLOAD_ERR_OK:
+ break;
+ case UPLOAD_ERR_INI_SIZE:
+ case UPLOAD_ERR_FORM_SIZE:
+ case UploadError::CONFIG_SIZE:
+ case UploadError::EMPTY_FILES_DATA:
+ $sError = 'File is too big';
+ $iClientError = UploadClientError::FILE_IS_TOO_BIG;
+ break;
+ case UPLOAD_ERR_PARTIAL:
+ $sError = 'File partially uploaded';
+ $iClientError = UploadClientError::FILE_PARTIALLY_UPLOADED;
+ break;
+ case UPLOAD_ERR_NO_FILE:
+ $sError = 'No file uploaded';
+ $iClientError = UploadClientError::FILE_NO_UPLOADED;
+ break;
+ case UPLOAD_ERR_NO_TMP_DIR:
+ case UPLOAD_ERR_CANT_WRITE:
+ case UPLOAD_ERR_EXTENSION:
+ $sError = 'Missing temp folder';
+ $iClientError = UploadClientError::MISSING_TEMP_FOLDER;
+ break;
+ case UploadError::ON_SAVING:
+ $sError = 'Error on saving file';
+ $iClientError = UploadClientError::FILE_ON_SAVING_ERROR;
+ break;
+ case UploadError::FILE_TYPE:
+ $sError = 'Invalid file type';
+ $iClientError = UploadClientError::FILE_TYPE;
+ break;
+ case UploadError::UNKNOWN:
+ default:
+ $sError = 'Unknown error';
+ $iClientError = UploadClientError::UNKNOWN;
+ break;
+ }
+
+ return $sError;
+ }
+
+ /**
+ * @return array
+ */
+ public function Upload()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ $aResponse = array();
+
+ $aFile = $this->GetActionParam('File', null);
+ $iError = $this->GetActionParam('Error', \RainLoop\Enumerations\UploadError::UNKNOWN);
+
+ if ($oAccount && UPLOAD_ERR_OK === $iError && \is_array($aFile))
+ {
+ $sSavedName = 'upload-post-'.\md5($aFile['name'].$aFile['tmp_name']);
+ if (!$this->FilesProvider()->MoveUploadedFile($oAccount, $sSavedName, $aFile['tmp_name']))
+ {
+ $iError = \RainLoop\Enumerations\UploadError::ON_SAVING;
+ }
+ else
+ {
+ $sUploadName = $aFile['name'];
+ $iSize = $aFile['size'];
+ $sMimeType = $aFile['type'];
+
+ $aResponse['Attachment'] = array(
+ 'Name' => $sUploadName,
+ 'TempName' => $sSavedName,
+ 'MimeType' => $sMimeType,
+ 'Size' => (int) $iSize
+ );
+ }
+ }
+
+ if (UPLOAD_ERR_OK !== $iError)
+ {
+ $iClientError = \RainLoop\Enumerations\UploadClientError::NORMAL;
+ $sError = $this->getUploadErrorMessageByCode($iError, $iClientError);
+
+ if (!empty($sError))
+ {
+ $aResponse['ErrorCode'] = $iClientError;
+ $aResponse['Error'] = $sError;
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $aResponse);
+ }
+
+ /**
+ * @return array
+ */
+ public function DoClearUserBackground()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::USER_BACKGROUND, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $oSettings = $this->SettingsProvider()->Load($oAccount);
+ if ($oAccount && $oSettings)
+ {
+ $this->StorageProvider()->Clear($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'background'
+ );
+
+ $oSettings->SetConf('UserBackgroundName', '');
+ $oSettings->SetConf('UserBackgroundHash', '');
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $oAccount && $oSettings ?
+ $this->SettingsProvider()->Save($oAccount, $oSettings) : false);
+ }
+
+ /**
+ * @return array
+ */
+ public function UploadBackground()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ if (!$this->GetCapa(false, false, \RainLoop\Enumerations\Capa::USER_BACKGROUND, $oAccount))
+ {
+ return $this->FalseResponse(__FUNCTION__);
+ }
+
+ $sName = '';
+ $sHash = '';
+
+ $aFile = $this->GetActionParam('File', null);
+ $iError = $this->GetActionParam('Error', \RainLoop\Enumerations\UploadError::UNKNOWN);
+
+ if ($oAccount && UPLOAD_ERR_OK === $iError && \is_array($aFile))
+ {
+ $sMimeType = \strtolower(\MailSo\Base\Utils::MimeContentType($aFile['name']));
+ if (\in_array($sMimeType, array('image/png', 'image/jpg', 'image/jpeg')))
+ {
+ $sSavedName = 'upload-post-'.\md5($aFile['name'].$aFile['tmp_name']);
+ if (!$this->FilesProvider()->MoveUploadedFile($oAccount, $sSavedName, $aFile['tmp_name']))
+ {
+ $iError = \RainLoop\Enumerations\UploadError::ON_SAVING;
+ }
+ else
+ {
+ $rData = $this->FilesProvider()->GetFile($oAccount, $sSavedName);
+ if (@\is_resource($rData))
+ {
+ $sData = @\stream_get_contents($rData);
+ if (!empty($sData) && 0 < \strlen($sData))
+ {
+ $sName = $aFile['name'];
+ if (empty($sName))
+ {
+ $sName = '_';
+ }
+
+ if ($this->StorageProvider()->Put($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'background',
+ \json_encode(array(
+ 'Name' => $aFile['name'],
+ 'ContentType' => $sMimeType,
+ 'Raw' => \base64_encode($sData)
+ ))
+ ))
+ {
+ $oSettings = $this->SettingsProvider()->Load($oAccount);
+ if ($oSettings)
+ {
+ $sHash = \MailSo\Base\Utils::Md5Rand($sName.APP_VERSION.APP_SALT);
+
+ $oSettings->SetConf('UserBackgroundName', $sName);
+ $oSettings->SetConf('UserBackgroundHash', $sHash);
+ $this->SettingsProvider()->Save($oAccount, $oSettings);
+ }
+ }
+ }
+
+ unset($sData);
+ }
+
+ if (@\is_resource($rData))
+ {
+ @\fclose($rData);
+ }
+
+ unset($rData);
+ }
+
+ $this->FilesProvider()->Clear($oAccount, $sSavedName);
+ }
+ else
+ {
+ $iError = \RainLoop\Enumerations\UploadError::FILE_TYPE;
+ }
+ }
+
+ if (UPLOAD_ERR_OK !== $iError)
+ {
+ $iClientError = \RainLoop\Enumerations\UploadClientError::NORMAL;
+ $sError = $this->getUploadErrorMessageByCode($iError, $iClientError);
+
+ if (!empty($sError))
+ {
+ return $this->FalseResponse(__FUNCTION__, $iClientError, $sError);
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, !empty($sName) && !empty($sHash) ? array(
+ 'Name' => $sName,
+ 'Hash' => $sHash
+ ) : false);
+ }
+
+ /**
+ * @return array
+ */
+ public function UploadContacts()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ $mResponse = false;
+
+ $aFile = $this->GetActionParam('File', null);
+ $iError = $this->GetActionParam('Error', \RainLoop\Enumerations\UploadError::UNKNOWN);
+
+ if ($oAccount && UPLOAD_ERR_OK === $iError && \is_array($aFile))
+ {
+ $sSavedName = 'upload-post-'.\md5($aFile['name'].$aFile['tmp_name']);
+ if (!$this->FilesProvider()->MoveUploadedFile($oAccount, $sSavedName, $aFile['tmp_name']))
+ {
+ $iError = \RainLoop\Enumerations\UploadError::ON_SAVING;
+ }
+ else
+ {
+ @\ini_set('auto_detect_line_endings', true);
+ $mData = $this->FilesProvider()->GetFile($oAccount, $sSavedName);
+ if ($mData)
+ {
+ $sFileStart = @\fread($mData, 20);
+ \rewind($mData);
+
+ if (false !== $sFileStart)
+ {
+ $sFileStart = \trim($sFileStart);
+ if (false !== \strpos($sFileStart, 'BEGIN:VCARD'))
+ {
+ $mResponse = $this->importContactsFromVcfFile($oAccount, $mData);
+ }
+ else if (false !== \strpos($sFileStart, ',') || false !== \strpos($sFileStart, ';'))
+ {
+ $mResponse = $this->importContactsFromCsvFile($oAccount, $mData, $sFileStart);
+ }
+ }
+ }
+
+ if (\is_resource($mData))
+ {
+ @\fclose($mData);
+ }
+
+ unset($mData);
+ $this->FilesProvider()->Clear($oAccount, $sSavedName);
+
+ @\ini_set('auto_detect_line_endings', false);
+ }
+ }
+
+ if (UPLOAD_ERR_OK !== $iError)
+ {
+ $iClientError = \RainLoop\Enumerations\UploadClientError::NORMAL;
+ $sError = $this->getUploadErrorMessageByCode($iError, $iClientError);
+
+ if (!empty($sError))
+ {
+ return $this->FalseResponse(__FUNCTION__, $iClientError, $sError);
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, $mResponse);
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ * @param resource $rFile
+ * @param string $sFileStart
+ *
+ * @return int
+ */
+ private function importContactsFromCsvFile($oAccount, $rFile, $sFileStart)
+ {
+ $iCount = 0;
+ $aHeaders = null;
+ $aData = array();
+
+ if ($oAccount && \is_resource($rFile))
+ {
+ $oAddressBookProvider = $this->AddressBookProvider($oAccount);
+ if ($oAddressBookProvider && $oAddressBookProvider->IsActive())
+ {
+ $sDelimiter = ((int) \strpos($sFileStart, ',') > (int) \strpos($sFileStart, ';')) ? ',' : ';';
+
+ @\setlocale(LC_CTYPE, 'en_US.UTF-8');
+ while (false !== ($mRow = \fgetcsv($rFile, 5000, $sDelimiter, '"')))
+ {
+ if (null === $aHeaders)
+ {
+ if (3 >= \count($mRow))
+ {
+ return 0;
+ }
+
+ $aHeaders = $mRow;
+
+ foreach ($aHeaders as $iIndex => $sHeaderValue)
+ {
+ $aHeaders[$iIndex] = \MailSo\Base\Utils::Utf8Clear($sHeaderValue);
+ }
+ }
+ else
+ {
+ $aNewItem = array();
+ foreach ($aHeaders as $iIndex => $sHeaderValue)
+ {
+ $aNewItem[$sHeaderValue] = isset($mRow[$iIndex]) ? $mRow[$iIndex] : '';
+ }
+
+ $aData[] = $aNewItem;
+ }
+ }
+
+ if (\is_array($aData) && 0 < \count($aData))
+ {
+ $this->Logger()->Write('Import contacts from csv');
+ $iCount = $oAddressBookProvider->ImportCsvArray($oAccount->ParentEmailHelper(), $aData);
+ }
+ }
+ }
+
+ return $iCount;
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ * @param resource $rFile
+ *
+ * @return int
+ */
+ private function importContactsFromVcfFile($oAccount, $rFile)
+ {
+ $iCount = 0;
+ if ($oAccount && \is_resource($rFile))
+ {
+ $oAddressBookProvider = $this->AddressBookProvider($oAccount);
+ if ($oAddressBookProvider && $oAddressBookProvider->IsActive())
+ {
+ $sFile = \stream_get_contents($rFile);
+ if (\is_resource($rFile))
+ {
+ \fclose($rFile);
+ }
+
+ if (is_string($sFile) && 5 < \strlen($sFile))
+ {
+ $this->Logger()->Write('Import contacts from vcf');
+ $iCount = $oAddressBookProvider->ImportVcfFile($oAccount->ParentEmailHelper(), $sFile);
+ }
+ }
+ }
+
+ return $iCount;
+ }
+
+ /**
+ * @return bool
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function RawViewAsPlain()
+ {
+ $this->initMailClientConnection();
+
+ $sRawKey = (string) $this->GetActionParam('RawKey', '');
+ $aValues = $this->getDecodedRawKeyValue($sRawKey);
+
+ $sFolder = isset($aValues['Folder']) ? $aValues['Folder'] : '';
+ $iUid = (int) (isset($aValues['Uid']) ? $aValues['Uid'] : 0);
+ $sMimeIndex = (string) (isset($aValues['MimeIndex']) ? $aValues['MimeIndex'] : '');
+
+ \header('Content-Type: text/plain', true);
+
+ return $this->MailClient()->MessageMimeStream(function ($rResource) {
+ if (\is_resource($rResource))
+ {
+ \MailSo\Base\Utils::FpassthruWithTimeLimitReset($rResource);
+ }
+ }, $sFolder, $iUid, true, $sMimeIndex);
+ }
+
+ /**
+ * @return string
+ */
+ public function RawFramedView()
+ {
+ $oAccount = $this->getAccountFromToken(false);
+ if ($oAccount)
+ {
+ $sRawKey = (string) $this->GetActionParam('RawKey', '');
+ $aParams = $this->GetActionParam('Params', null);
+ $this->Http()->ServerNoCache();
+
+ $aData = \RainLoop\Utils::DecodeKeyValuesQ($sRawKey);
+ if (isset($aParams[0], $aParams[1], $aParams[2]) &&
+ 'Raw' === $aParams[0] && 'FramedView' === $aParams[2] && isset($aData['Framed']) && $aData['Framed'] && $aData['FileName'])
+ {
+ if ($this->isFileHasFramedPreview($aData['FileName']))
+ {
+ $sNewSpecAuthToken = $this->GetShortLifeSpecAuthToken();
+ if (!empty($sNewSpecAuthToken))
+ {
+ $aParams[1] = '_'.$sNewSpecAuthToken;
+ $aParams[2] = 'View';
+
+ \array_shift($aParams);
+ $sLast = \array_pop($aParams);
+
+ $sUrl = $this->Http()->GetFullUrl().'?/Raw/&q[]=/'.\implode('/', $aParams).'/&q[]=/'.$sLast;
+ $sFullUrl = 'https://docs.google.com/viewer?embedded=true&url='.\urlencode($sUrl);
+
+ @\header('Content-Type: text/html; charset=utf-8');
+ echo ''.
+ ''.
+ ''.
+ '';
+ }
+ }
+ }
+ }
+
+
+ return true;
+
+ }
+
+ /**
+ * @return bool
+ *
+ * @throws \MailSo\Base\Exceptions\Exception
+ */
+ public function Append()
+ {
+ $oAccount = $this->initMailClientConnection();
+
+ $sFolderFullNameRaw = $this->GetActionParam('Folder', '');
+
+ $_FILES = isset($_FILES) ? $_FILES : null;
+ if ($oAccount instanceof \RainLoop\Model\Account &&
+ $this->Config()->Get('labs', 'allow_message_append', false) &&
+ isset($_FILES, $_FILES['AppendFile'], $_FILES['AppendFile']['name'],
+ $_FILES['AppendFile']['tmp_name'], $_FILES['AppendFile']['size']))
+ {
+ if (is_string($_FILES['AppendFile']['tmp_name']) && 0 < strlen($_FILES['AppendFile']['tmp_name']))
+ {
+ if (\UPLOAD_ERR_OK === (int) $_FILES['AppendFile']['error'] && !empty($sFolderFullNameRaw))
+ {
+ $sSavedName = 'append-post-'.md5($sFolderFullNameRaw.$_FILES['AppendFile']['name'].$_FILES['AppendFile']['tmp_name']);
+
+ if ($this->FilesProvider()->MoveUploadedFile($oAccount,
+ $sSavedName, $_FILES['AppendFile']['tmp_name']))
+ {
+ $iMessageStreamSize = $this->FilesProvider()->FileSize($oAccount, $sSavedName);
+ $rMessageStream = $this->FilesProvider()->GetFile($oAccount, $sSavedName);
+
+ $this->MailClient()->MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderFullNameRaw);
+
+ $this->FilesProvider()->Clear($oAccount, $sSavedName);
+ }
+ }
+ }
+ }
+
+ return $this->DefaultResponse(__FUNCTION__, true);
+ }
+
+ /**
+ * @param bool $bAdmin
+ * @param bool $bMobile = false
+ * @param \RainLoop\Model\Account $oAccount = null
+ *
+ * @return array
+ */
+ public function Capa($bAdmin, $bMobile = false, $oAccount = null)
+ {
+ $oConfig = $this->Config();
+
+ $aResult = array();
+
+ if ($oConfig->Get('capa', 'folders', true))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::FOLDERS;
+
+ if ($oConfig->Get('capa', 'messagelist_actions', true))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::MESSAGELIST_ACTIONS;
+
+ if ($oConfig->Get('capa', 'dangerous_actions', true))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::DANGEROUS_ACTIONS;
+ }
+ }
+ }
+
+ if ($oConfig->Get('capa', 'reload', true))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::RELOAD;
+ }
+
+ if ($oConfig->Get('capa', 'quota', true))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::QUOTA;
+ }
+
+ if ($oConfig->Get('capa', 'settings', true))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::SETTINGS;
+
+ if ($oConfig->Get('webmail', 'allow_additional_accounts', false))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS;
+ }
+
+ if ($oConfig->Get('webmail', 'allow_additional_identities', false))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::IDENTITIES;
+ }
+
+ if ($oConfig->Get('capa', 'x-templates', true) && !$bMobile)
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::TEMPLATES;
+ }
+
+ if ($oConfig->Get('webmail', 'allow_themes', false) && !$bMobile)
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::THEMES;
+ }
+
+ if ($oConfig->Get('webmail', 'allow_user_background', false) && !$bMobile)
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::USER_BACKGROUND;
+ }
+
+ if ($oConfig->Get('security', 'openpgp', false) && !$bMobile)
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::OPEN_PGP;
+ }
+
+ if ($oConfig->Get('capa', 'filters', false))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::FILTERS;
+ if ($bAdmin || ($oAccount && $oAccount->Domain()->UseSieve()))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::SIEVE;
+ }
+ }
+ }
+
+ if ($oConfig->Get('security', 'allow_two_factor_auth', false) &&
+ ($bAdmin || ($oAccount && !$oAccount->IsAdditionalAccount())))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::TWO_FACTOR;
+
+ if ($oConfig->Get('security', 'force_two_factor_auth', false) &&
+ ($bAdmin || ($oAccount && !$oAccount->IsAdditionalAccount())))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::TWO_FACTOR_FORCE;
+ }
+ }
+
+ if ($oConfig->Get('capa', 'help', true) && !$bMobile)
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::HELP;
+ }
+
+ if ($oConfig->Get('capa', 'attachments_actions', false))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::ATTACHMENTS_ACTIONS;
+ }
+
+ if ($oConfig->Get('capa', 'message_actions', true))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::MESSAGE_ACTIONS;
+ }
+
+ if ($oConfig->Get('capa', 'composer', true))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::COMPOSER;
+
+ if ($oConfig->Get('capa', 'contacts', true))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::CONTACTS;
+ }
+ }
+
+ if ($oConfig->Get('capa', 'search', true))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::SEARCH;
+
+ if ($oConfig->Get('capa', 'search_adv', true) && !$bMobile)
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::SEARCH_ADV;
+ }
+ }
+
+ if ($oConfig->Get('labs', 'allow_gravatar', false))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::GRAVATAR;
+ }
+
+ if ($oConfig->Get('interface', 'show_attachment_thumbnail', true))
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::ATTACHMENT_THUMBNAILS;
+ }
+
+ if ($oConfig->Get('labs', 'allow_prefetch', false) && !$bMobile)
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::PREFETCH;
+ }
+
+ if (!\RainLoop\Utils::IsOwnCloud())
+ {
+ $aResult[] = \RainLoop\Enumerations\Capa::AUTOLOGOUT;
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param bool $bAdmin
+ * @param bool $bMobile
+ * @param string $sName
+ * @param \RainLoop\Model\Account $oAccount = null
+ *
+ * @return bool
+ */
+ public function GetCapa($bAdmin, $bMobile, $sName, $oAccount = null)
+ {
+ return \in_array($sName, $this->Capa($bAdmin, $bMobile, $oAccount));
+ }
+
+ /**
+ * @param string $sKey
+ * @param bool $bForce = false
+ *
+ * @return bool
+ */
+ public function cacheByKey($sKey, $bForce = false)
+ {
+ $bResult = false;
+ if (!empty($sKey) && ($bForce || $this->Config()->Get('cache', 'enable', true) && $this->Config()->Get('cache', 'http', true)))
+ {
+ $this->oHttp->ServerUseCache(
+ \md5('Etag:'.\md5($sKey.\md5($this->Config()->Get('cache', 'index', '')))),
+ 1382478804, 2002478804);
+
+ $bResult = true;
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @param string $sKey
+ * @param bool $bForce = false
+ *
+ * @return void
+ */
+ public function verifyCacheByKey($sKey, $bForce = false)
+ {
+ if (!empty($sKey) && ($bForce || $this->Config()->Get('cache', 'enable', true) && $this->Config()->Get('cache', 'http', true)))
+ {
+ $sIfModifiedSince = $this->Http()->GetHeader('If-Modified-Since', '');
+ $sIfNoneMatch = $this->Http()->GetHeader('If-None-Match', '');
+
+ if (!empty($sIfModifiedSince) || !empty($sIfNoneMatch))
+ {
+ $this->Http()->StatusHeader(304);
+ $this->cacheByKey($sKey);
+ exit();
+ }
+ }
+ }
+
+ /**
+ * @param \RainLoop\Model\Account $oAccount
+ * @param string $sHash
+ *
+ * @return array
+ */
+ private function getMimeFileByHash($oAccount, $sHash)
+ {
+ $aValues = $this->getDecodedRawKeyValue($sHash);
+
+ $sFolder = isset($aValues['Folder']) ? $aValues['Folder'] : '';
+ $iUid = (int) isset($aValues['Uid']) ? $aValues['Uid'] : 0;
+ $sMimeIndex = (string) isset($aValues['MimeIndex']) ? $aValues['MimeIndex'] : '';
+
+ $sContentTypeIn = (string) isset($aValues['MimeType']) ? $aValues['MimeType'] : '';
+ $sFileNameIn = (string) isset($aValues['FileName']) ? $aValues['FileName'] : '';
+
+ $oFileProvider = $this->FilesProvider();
+
+ $sResultHash = '';
+
+ $mResult = $this->MailClient()->MessageMimeStream(function($rResource, $sContentType, $sFileName, $sMimeIndex = '')
+ use ($oAccount, $oFileProvider, $sFileNameIn, $sContentTypeIn, &$sResultHash) {
+
+ unset($sContentType, $sFileName, $sMimeIndex);
+
+ if ($oAccount && \is_resource($rResource))
+ {
+ $sHash = \MailSo\Base\Utils::Md5Rand($sFileNameIn.'~'.$sContentTypeIn);
+ $rTempResource = $oFileProvider->GetFile($oAccount, $sHash, 'wb+');
+
+ if (@\is_resource($rTempResource))
+ {
+ if (false !== \MailSo\Base\Utils::MultipleStreamWriter($rResource, array($rTempResource)))
+ {
+ $sResultHash = $sHash;
+ }
+
+ @\fclose($rTempResource);
+ }
+ }
+
+ }, $sFolder, $iUid, true, $sMimeIndex);
+
+ $aValues['FileHash'] = '';
+ if ($mResult)
+ {
+ $aValues['FileHash'] = $sResultHash;
+ }
+
+ return $aValues;
+ }
+
+ /**
+ * @param \Imagine\Image\AbstractImage $oImage
+ * @param int $iOrientation
+ */
+ private function rotateImageByOrientation(&$oImage, $iOrientation)
+ {
+ if (0 < $iOrientation)
+ {
+ switch ($iOrientation)
+ {
+ default:
+ case 1:
+ break;
+
+ case 2: // horizontal flip
+ $oImage->flipHorizontally();
+ break;
+
+ case 3: // 180 rotate left
+ $oImage->rotate(180);
+ break;
+
+ case 4: // vertical flip
+ $oImage->flipVertically();
+ break;
+
+ case 5: // vertical flip + 90 rotate right
+ $oImage->flipVertically();
+ $oImage->rotate(-90);
+ break;
+
+ case 6: // 90 rotate right
+ $oImage->rotate(-90);
+ break;
+
+ case 7: // horizontal flip + 90 rotate right
+ $oImage->flipHorizontally();
+ $oImage->rotate(-90);
+ break;
+
+ case 8: // 90 rotate left
+ $oImage->rotate(90);
+ break;
+ }
+ }
+ }
+
+ /**
+ * @param \Imagine\Image\AbstractImage $oImage
+ */
+ private function correctImageOrientation($oImage, $bDetectImageOrientation = true, $iThumbnailBoxSize = null)
+ {
+ $iOrientation = 1;
+ if ($bDetectImageOrientation && \MailSo\Base\Utils::FunctionExistsAndEnabled('exif_read_data') &&
+ \MailSo\Base\Utils::FunctionExistsAndEnabled('gd_info'))
+ {
+ $oMetadata = $oImage->metadata(new \Imagine\Image\Metadata\ExifMetadataReader());
+ $iOrientation = isset($oMetadata['ifd0.Orientation']) &&
+ is_numeric($oMetadata['ifd0.Orientation']) ? (int) $oMetadata['ifd0.Orientation'] : 1;
+ }
+
+ if ($iThumbnailBoxSize && 0 < $iThumbnailBoxSize)
+ {
+ $oImage = $oImage->thumbnail(
+ new \Imagine\Image\Box($iThumbnailBoxSize, $iThumbnailBoxSize),
+ \Imagine\Image\ImageInterface::THUMBNAIL_OUTBOUND);
+
+ $this->rotateImageByOrientation($oImage, $iOrientation);
+ }
+ else
+ {
+ $this->rotateImageByOrientation($oImage, $iOrientation);
+ }
+
+ return $oImage;
+ }
+
+ /**
+ * @param bool $bDownload
+ * @param bool $bThumbnail = false
+ *
+ * @return bool
+ */
+ private function rawSmart($bDownload, $bThumbnail = false)
+ {
+ $sRawKey = (string) $this->GetActionParam('RawKey', '');
+ $aValues = $this->getDecodedRawKeyValue($sRawKey);
+
+ $sRange = $this->Http()->GetHeader('Range');
+
+ $aMatch = array();
+ $sRangeStart = $sRangeEnd = '';
+ $bIsRangeRequest = false;
+
+ if (!empty($sRange) && 'bytes=0-' !== \strtolower($sRange) && \preg_match('/^bytes=([0-9]+)-([0-9]*)/i', \trim($sRange), $aMatch))
+ {
+ $sRangeStart = $aMatch[1];
+ $sRangeEnd = $aMatch[2];
+
+ $bIsRangeRequest = true;
+ }
+
+ $sFolder = isset($aValues['Folder']) ? $aValues['Folder'] : '';
+ $iUid = isset($aValues['Uid']) ? (int) $aValues['Uid'] : 0;
+ $sMimeIndex = isset($aValues['MimeIndex']) ? (string) $aValues['MimeIndex'] : '';
+
+ $sContentTypeIn = isset($aValues['MimeType']) ? (string) $aValues['MimeType'] : '';
+ $sFileNameIn = isset($aValues['FileName']) ? (string) $aValues['FileName'] : '';
+ $sFileHashIn = isset($aValues['FileHash']) ? (string) $aValues['FileHash'] : '';
+
+ $bDetectImageOrientation = !!$this->Config()->Get('labs', 'detect_image_exif_orientation', true);
+
+ if (!empty($sFileHashIn))
+ {
+ $this->verifyCacheByKey($sRawKey);
+
+ $oAccount = $this->getAccountFromToken();
+
+ $sContentTypeOut = empty($sContentTypeIn) ?
+ \MailSo\Base\Utils::MimeContentType($sFileNameIn) : $sContentTypeIn;
+
+ $sFileNameOut = $this->MainClearFileName($sFileNameIn, $sContentTypeIn, $sMimeIndex);
+
+ $rResource = $this->FilesProvider()->GetFile($oAccount, $sFileHashIn);
+ if (\is_resource($rResource))
+ {
+ $sFileNameOut = \MailSo\Base\Utils::ConvertEncoding(
+ $sFileNameOut, \MailSo\Base\Enumerations\Charset::UTF_8,
+ \MailSo\Base\Enumerations\Charset::CP858);
+
+ \header('Content-Type: '.$sContentTypeOut);
+ \header('Content-Disposition: attachment; '.
+ \trim(\MailSo\Base\Utils::EncodeHeaderUtf8AttributeValue('filename', $sFileNameOut)), true);
+
+ \header('Accept-Ranges: none', true);
+ \header('Content-Transfer-Encoding: binary');
+
+ \MailSo\Base\Utils::FpassthruWithTimeLimitReset($rResource);
+ return true;
+ }
+
+ return false;
+ }
+ else
+ {
+ if (!empty($sFolder) && 0 < $iUid)
+ {
+ $this->verifyCacheByKey($sRawKey);
+ }
+ }
+
+ $oAccount = $this->initMailClientConnection();
+
+ $self = $this;
+ return $this->MailClient()->MessageMimeStream(
+ function($rResource, $sContentType, $sFileName, $sMimeIndex = '') use (
+ $self, $oAccount, $sRawKey, $sContentTypeIn, $sFileNameIn, $bDownload, $bThumbnail, $bDetectImageOrientation,
+ $bIsRangeRequest, $sRangeStart, $sRangeEnd
+ ) {
+ if ($oAccount && \is_resource($rResource))
+ {
+ \MailSo\Base\Utils::ResetTimeLimit();
+
+ $sContentTypeOut = $sContentTypeIn;
+ if (empty($sContentTypeOut))
+ {
+ $sContentTypeOut = $sContentType;
+ if (empty($sContentTypeOut))
+ {
+ $sContentTypeOut = (empty($sFileName)) ? 'text/plain' : \MailSo\Base\Utils::MimeContentType($sFileName);
+ }
+ }
+
+ $sFileNameOut = $sFileNameIn;
+ if (empty($sFileNameOut))
+ {
+ $sFileNameOut = $sFileName;
+ }
+
+ $sFileNameOut = $self->MainClearFileName($sFileNameOut, $sContentTypeOut, $sMimeIndex);
+
+ $self->cacheByKey($sRawKey);
+
+ $sLoadedData = null;
+ $bDetectImageOrientation = false;
+
+ if (!$bDownload)
+ {
+ if ($bThumbnail)
+ {
+ try
+ {
+ $oImagine = new \Imagine\Gd\Imagine();
+
+ $oImage = $oImagine->load(\stream_get_contents($rResource));
+
+ $oImage = $self->correctImageOrientation($oImage, $bDetectImageOrientation, 60);
+
+ \header('Content-Disposition: inline; '.
+ \trim(\MailSo\Base\Utils::EncodeHeaderUtf8AttributeValue('filename', $sFileNameOut.'_thumb60x60.png')), true);
+
+ $oImage->show('png');
+ }
+ catch (\Exception $oException)
+ {
+ $self->Logger()->WriteExceptionShort($oException);
+ }
+ }
+ else if ($bDetectImageOrientation &&
+ \in_array($sContentTypeOut, array('image/png', 'image/jpeg', 'image/jpg')) &&
+ \MailSo\Base\Utils::FunctionExistsAndEnabled('gd_info'))
+ {
+ try
+ {
+ $oImagine = new \Imagine\Gd\Imagine();
+
+ $sLoadedData = \stream_get_contents($rResource);
+
+ $oImage = $oImagine->load($sLoadedData);
+
+ $oImage = $self->correctImageOrientation($oImage, $bDetectImageOrientation);
+
+ \header('Content-Disposition: inline; '.
+ \trim(\MailSo\Base\Utils::EncodeHeaderUtf8AttributeValue('filename', $sFileNameOut)), true);
+
+ $oImage->show($sContentTypeOut === 'image/png' ? 'png' : 'jpg');
+ }
+ catch (\Exception $oException)
+ {
+ $self->Logger()->WriteExceptionShort($oException);
+ }
+ }
+ else
+ {
+ $sLoadedData = \stream_get_contents($rResource);
+ }
+ }
+
+ if ($bDownload || $sLoadedData)
+ {
+ \header('Content-Type: '.$sContentTypeOut);
+ \header('Content-Disposition: '.($bDownload ? 'attachment' : 'inline').'; '.
+ \trim(\MailSo\Base\Utils::EncodeHeaderUtf8AttributeValue('filename', $sFileNameOut)), true);
+
+ \header('Accept-Ranges: bytes');
+ \header('Content-Transfer-Encoding: binary');
+
+ if ($bIsRangeRequest && !$sLoadedData)
+ {
+ $sLoadedData = \stream_get_contents($rResource);
+ }
+
+ \MailSo\Base\Utils::ResetTimeLimit();
+
+ if ($sLoadedData)
+ {
+ if ($bIsRangeRequest && (0 < \strlen($sRangeStart) || 0 < \strlen($sRangeEnd)))
+ {
+ $iFullContentLength = \strlen($sLoadedData);
+
+ $self->Http()->StatusHeader(206);
+
+ $iRangeStart = (int) $sRangeStart;
+ $iRangeEnd = (int) $sRangeEnd;
+
+ if ('' === $sRangeEnd)
+ {
+ $sLoadedData = 0 < $iRangeStart ? \substr($sLoadedData, $iRangeStart) : $sLoadedData;
+ }
+ else
+ {
+ if ($iRangeStart < $iRangeEnd)
+ {
+ $sLoadedData = \substr($sLoadedData, $iRangeStart, $iRangeEnd - $iRangeStart);
+ }
+ else
+ {
+ $sLoadedData = 0 < $iRangeStart ? \substr($sLoadedData, $iRangeStart) : $sLoadedData;
+ }
+ }
+
+ $iContentLength = \strlen($sLoadedData);
+
+ if (0 < $iContentLength)
+ {
+ \header('Content-Length: '.$iContentLength, true);
+ \header('Content-Range: bytes '.$sRangeStart.'-'.(0 < $iRangeEnd ? $iRangeEnd : $iFullContentLength - 1).'/'.$iFullContentLength);
+ }
+
+ echo $sLoadedData;
+ }
+ else
+ {
+ echo $sLoadedData;
+ }
+
+ unset($sLoadedData);
+ }
+ else
+ {
+ \MailSo\Base\Utils::FpassthruWithTimeLimitReset($rResource);
+ }
+ }
+ }
+ }, $sFolder, $iUid, true, $sMimeIndex);
+ }
+
+ /**
+ * @return bool
+ */
+ public function RawDownload()
+ {
+ return $this->rawSmart(true);
+ }
+
+ /**
+ * @return bool
+ */
+ public function RawView()
+ {
+ return $this->rawSmart(false);
+ }
+
+ /**
+ * @return bool
+ */
+ public function RawViewThumbnail()
+ {
+ return $this->rawSmart(false, true);
+ }
+
+ /**
+ * @return bool
+ */
+ public function RawUserBackground()
+ {
+ $sRawKey = (string) $this->GetActionParam('RawKey', '');
+ $this->verifyCacheByKey($sRawKey);
+
+ $oAccount = $this->getAccountFromToken();
+
+ $sData = $this->StorageProvider()->Get($oAccount,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
+ 'background'
+ );
+
+ if (!empty($sData))
+ {
+ $aData = \json_decode($sData, true);
+ unset($sData);
+
+ if (!empty($aData['ContentType']) && !empty($aData['Raw']) &&
+ \in_array($aData['ContentType'], array('image/png', 'image/jpg', 'image/jpeg')))
+ {
+ $this->cacheByKey($sRawKey);
+
+ @\header('Content-Type: '.$aData['ContentType']);
+ echo \base64_decode($aData['Raw']);
+ unset($aData);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @return bool
+ */
+ public function RawPublic()
+ {
+ $sRawKey = (string) $this->GetActionParam('RawKey', '');
+ $this->verifyCacheByKey($sRawKey);
+
+ $sHash = $sRawKey;
+ $sData = '';
+
+ if (!empty($sHash))
+ {
+ $sData = $this->StorageProvider()->Get(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ \RainLoop\KeyPathHelper::PublicFile($sHash)
+ );
+ }
+
+ $aMatch = array();
+ if (!empty($sData) && 0 === \strpos($sData, 'data:') &&
+ \preg_match('/^data:([^:]+):/', $sData, $aMatch) && !empty($aMatch[1]))
+ {
+ $sContentType = \trim($aMatch[1]);
+ if (\in_array($sContentType, array('image/png', 'image/jpg', 'image/jpeg')))
+ {
+ $this->cacheByKey($sRawKey);
+
+ @\header('Content-Type: '.$sContentType);
+ echo \preg_replace('/^data:[^:]+:/', '', $sData);
+ unset($sData);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $sFileName
+ *
+ * @return bool
+ */
+ public function isFileHasFramedPreview($sFileName)
+ {
+ $sExt = \MailSo\Base\Utils::GetFileExtension($sFileName);
+ return \in_array($sExt, array('doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'));
+ }
+
+ /**
+ * @param string $sFileName
+ *
+ * @return bool
+ */
+ public function isFileHasThumbnail($sFileName)
+ {
+ static $aCache = array();
+
+ $sExt = \MailSo\Base\Utils::GetFileExtension($sFileName);
+ if (isset($aCache[$sExt]))
+ {
+ return $aCache[$sExt];
+ }
+
+ $bResult = \function_exists('gd_info');
+ if ($bResult)
+ {
+ $bResult = false;
+ switch ($sExt)
+ {
+ case 'png':
+ $bResult = \function_exists('imagecreatefrompng');
+ break;
+ case 'gif':
+ $bResult = \function_exists('imagecreatefromgif');
+ break;
+ case 'jpg':
+ case 'jpeg':
+ $bResult = \function_exists('imagecreatefromjpeg');
+ break;
+ }
+ }
+
+ $aCache[$sExt] = $bResult;
+
+ return $bResult;
+ }
+
+ /**
+ * @return bool
+ */
+ public function RawAvatar()
+ {
+ $sData = '';
+
+ $sRawKey = (string) $this->GetActionParam('RawKey', '');
+ $sRawKey = \urldecode($sRawKey);
+
+ $this->verifyCacheByKey($sRawKey);
+
+ if (0 < \strlen($sRawKey) && \preg_match('/^[^@]+@([^@]+)$/', $sRawKey))
+ {
+ $sEmail = \MailSo\Base\Utils::IdnToAscii($sRawKey, true);
+
+ $iCode = 0;
+ $sContentType = '';
+
+ $sGravatarUrl = 'http://gravatar.com/avatar/'.\md5($sEmail).'.jpg?s=80&d=404';
+
+ $this->Logger()->Write('gravatar: '.$sGravatarUrl);
+
+ $sData = $this->Http()->GetUrlAsString($sGravatarUrl, null, $sContentType, $iCode, null, 5,
+ $this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', ''));
+
+ $sContentType = \strtolower(\trim($sContentType));
+ if (200 !== $iCode || empty($sData) || !\in_array($sContentType, array('image/jpeg', 'image/jpg', 'image/png')))
+ {
+ $this->Logger()->Write('gravatar: code: '.$iCode.', content-type: '.$sContentType);
+
+ $sData = '';
+
+ $aMatch = array();
+ if (\preg_match('/^[^@]+@([a-z0-9\-\.]+)$/', $sEmail, $aMatch) && !empty($aMatch[1]))
+ {
+ $sDomain = $aMatch[1];
+ if (\file_exists(APP_VERSION_ROOT_PATH.'app/resources/images/services/'.$sDomain.'.png'))
+ {
+ $sContentType = 'image/png';
+ $sData = \file_get_contents(APP_VERSION_ROOT_PATH.'app/resources/images/services/'.$sDomain.'.png');
+ }
+ }
+ }
+ }
+
+ if (empty($sData) || empty($sContentType))
+ {
+ $sContentType = 'image/png';
+ $sData = \file_get_contents(APP_VERSION_ROOT_PATH.'app/resources/images/empty-contact.png');
+ }
+
+ $this->cacheByKey($sRawKey);
+ \header('Content-Type: '.$sContentType);
+ echo $sData;
+ return true;
+ }
+
+ /**
+ * @return bool
+ */
+ public function RawContactsVcf()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ \header('Content-Type: text/x-vcard; charset=UTF-8');
+ \header('Content-Disposition: attachment; filename="contacts.vcf"', true);
+ \header('Accept-Ranges: none', true);
+ \header('Content-Transfer-Encoding: binary');
+
+ $this->oHttp->ServerNoCache();
+
+ return $this->AddressBookProvider($oAccount)->IsActive() ?
+ $this->AddressBookProvider($oAccount)->Export($oAccount->ParentEmailHelper(), 'vcf') : false;
+ }
+
+ /**
+ * @return bool
+ */
+ public function RawContactsCsv()
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ \header('Content-Type: text/csv; charset=UTF-8');
+ \header('Content-Disposition: attachment; filename="contacts.csv"', true);
+ \header('Accept-Ranges: none', true);
+ \header('Content-Transfer-Encoding: binary');
+
+ $this->oHttp->ServerNoCache();
+
+ return $this->AddressBookProvider($oAccount)->IsActive() ?
+ $this->AddressBookProvider($oAccount)->Export($oAccount->ParentEmailHelper(), 'csv') : false;
+ }
+
+ /**
+ * @return \RainLoop\Model\Account|bool
+ */
+ private function initMailClientConnection()
+ {
+ $oAccount = null;
+
+ if (!$this->MailClient()->IsLoggined())
+ {
+ $oAccount = $this->getAccountFromToken();
+
+ try
+ {
+ $oAccount->IncConnectAndLoginHelper($this->Plugins(), $this->MailClient(), $this->Config());
+ }
+ catch (\MailSo\Net\Exceptions\ConnectionException $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ConnectionError, $oException);
+ }
+ catch (\Exception $oException)
+ {
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError, $oException);
+ }
+
+ $this->MailClient()->ImapClient()->__FORCE_SELECT_ON_EXAMINE__ = !!$this->Config()->Get('labs', 'use_imap_force_selection');
+ }
+
+ return $oAccount;
+ }
+
+ /**
+ * @param string $sRawKey
+ *
+ * @return array | false
+ */
+ private function getDecodedRawKeyValue($sRawKey)
+ {
+ $bResult = false;
+ if (!empty($sRawKey))
+ {
+ $aValues = \RainLoop\Utils::DecodeKeyValuesQ($sRawKey);
+ if (is_array($aValues))
+ {
+ $bResult = $aValues;
+ }
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @param string $sRawKey
+ * @param int | null $iLenCache
+ * @return array | bool
+ */
+ private function getDecodedClientRawKeyValue($sRawKey, $iLenCache = null)
+ {
+ $mResult = false;
+ if (!empty($sRawKey))
+ {
+ $sRawKey = \MailSo\Base\Utils::UrlSafeBase64Decode($sRawKey);
+ $aValues = explode("\x0", $sRawKey);
+
+ if (is_array($aValues) && (null === $iLenCache || $iLenCache === count($aValues)))
+ {
+ $mResult = $aValues;
+ }
+ }
+
+ return $mResult;
+ }
+
+ /**
+ * @param string $sTheme
+ *
+ * @return string
+ */
+ public function ValidateTheme($sTheme, $bMobile = false)
+ {
+ if ($bMobile)
+ {
+ return 'Mobile';
+ }
+
+ return \in_array($sTheme, $this->GetThemes($bMobile)) ?
+ $sTheme : $this->Config()->Get('themes', 'default', $bMobile ? 'Mobile' : 'Default');
+ }
+
+ /**
+ * @param string $sLanguage
+ * @param string $sDefault = ''
+ * @param bool $bAdmin = false
+ * @param bool $bAllowEmptyResult = false
+ *
+ * @return string
+ */
+ public function ValidateLanguage($sLanguage, $sDefault = '', $bAdmin = false, $bAllowEmptyResult = false)
+ {
+ $sResult = '';
+ $aLang = $this->GetLanguages($bAdmin);
+
+ if (\is_array($aLang))
+ {
+ $aHelper = array('en' => 'en_us', 'ar' => 'ar_sa', 'cs' => 'cs_cz', 'no' => 'nb_no', 'ua' => 'uk_ua',
+ 'cn' => 'zh_cn', 'zh' => 'zh_cn', 'tw' => 'zh_tw');
+
+ $sLanguage = isset($aHelper[$sLanguage]) ? $aHelper[$sLanguage] : $sLanguage;
+ $sDefault = isset($aHelper[$sDefault]) ? $aHelper[$sDefault] : $sDefault;
+
+ $sLanguage = \strtolower(\str_replace('-', '_', $sLanguage));
+ if (2 === strlen($sLanguage))
+ {
+ $sLanguage = $sLanguage.'_'.$sLanguage;
+ }
+
+ $sDefault = \strtolower(\str_replace('-', '_', $sDefault));
+ if (2 === strlen($sDefault))
+ {
+ $sDefault = $sDefault.'_'.$sDefault;
+ }
+
+ $sLanguage = \preg_replace_callback('/_([a-zA-Z0-9]{2})$/', function ($aData) {
+ return \strtoupper($aData[0]);
+ }, $sLanguage);
+
+ $sDefault = \preg_replace_callback('/_([a-zA-Z0-9]{2})$/', function ($aData) {
+ return \strtoupper($aData[0]);
+ }, $sDefault);
+
+ if (\in_array($sLanguage, $aLang))
+ {
+ $sResult = $sLanguage;
+ }
+
+ if (empty($sResult) && !empty($sDefault) && \in_array($sDefault, $aLang))
+ {
+ $sResult = $sDefault;
+ }
+
+ if (empty($sResult) && !$bAllowEmptyResult)
+ {
+ $sResult = $this->Config()->Get('webmail', $bAdmin ? 'language_admin' : 'language', 'en_US');
+ $sResult = \in_array($sResult, $aLang) ? $sResult : 'en_US';
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sType
+ *
+ * @return string
+ */
+ public function ValidateContactPdoType($sType)
+ {
+ return \in_array($sType, array('mysql', 'pgsql', 'sqlite')) ? $sType : 'sqlite';
+ }
+
+ /**
+ * @staticvar array $aCache
+ *
+ * @return array
+ */
+ public function GetThemes($bMobile = false, $bIncludeMobile = true)
+ {
+ if ($bMobile)
+ {
+ return array('Mobile');
+ }
+
+ static $aCache = array('full' => null, 'mobile' => null);
+ if ($bIncludeMobile && \is_array($aCache['full']))
+ {
+ return $aCache['full'];
+ }
+ else if ($bIncludeMobile && \is_array($aCache['mobile']))
+ {
+ return $aCache['mobile'];
+ }
+
+ $bClear = false;
+ $bDefault = false;
+ $sList = array();
+ $sDir = APP_VERSION_ROOT_PATH.'themes';
+ if (@\is_dir($sDir))
+ {
+ $rDirH = \opendir($sDir);
+ if ($rDirH)
+ {
+ while (($sFile = \readdir($rDirH)) !== false)
+ {
+ if ('.' !== $sFile{0} && \is_dir($sDir.'/'.$sFile) && \file_exists($sDir.'/'.$sFile.'/styles.less'))
+ {
+ if ('Default' === $sFile)
+ {
+ $bDefault = true;
+ }
+ else if ('Clear' === $sFile)
+ {
+ $bClear = true;
+ }
+ else if ($bIncludeMobile || 'Mobile' !== $sFile)
+ {
+ $sList[] = $sFile;
+ }
+ }
+ }
+ @closedir($rDirH);
+ }
+ }
+
+ $sDir = APP_INDEX_ROOT_PATH.'themes'; // custom user themes
+ if (@\is_dir($sDir))
+ {
+ $rDirH = \opendir($sDir);
+ if ($rDirH)
+ {
+ while (($sFile = \readdir($rDirH)) !== false)
+ {
+ if ('.' !== $sFile{0} && \is_dir($sDir.'/'.$sFile) && \file_exists($sDir.'/'.$sFile.'/styles.less'))
+ {
+ $sList[] = $sFile.'@custom';
+ }
+ }
+
+ @\closedir($rDirH);
+ }
+ }
+
+ $sList = \array_unique($sList);
+ \sort($sList);
+
+ if ($bDefault)
+ {
+ \array_unshift($sList, 'Default');
+ }
+
+ if ($bClear)
+ {
+ \array_push($sList, 'Clear');
+ }
+
+ $aCache[$bIncludeMobile ? 'full' : 'mobile'] = $sList;
+ return $sList;
+ }
+
+ /**
+ * @staticvar array $aCache
+ * @param bool $bAdmin = false
+ *
+ * @return array
+ */
+ public function GetLanguages($bAdmin = false)
+ {
+ static $aCache = array();
+ $sDir = APP_VERSION_ROOT_PATH.'app/localization/'.($bAdmin ? 'admin' : 'webmail').'/';
+
+ if (isset($aCache[$sDir]))
+ {
+ return $aCache[$sDir];
+ }
+
+ $aTop = array();
+ $aList = array();
+
+ if (@\is_dir($sDir))
+ {
+ $rDirH = \opendir($sDir);
+ if ($rDirH)
+ {
+ while (($sFile = \readdir($rDirH)) !== false)
+ {
+ if ('.' !== $sFile{0} && \is_file($sDir.'/'.$sFile) && '.yml' === \substr($sFile, -4))
+ {
+ $sLang = \substr($sFile, 0, -4);
+ if (0 < \strlen($sLang) && 'always' !== $sLang && '_source.en' !== $sLang)
+ {
+ \array_push($aList, $sLang);
+ }
+ }
+ }
+
+ @\closedir($rDirH);
+ }
+ }
+
+ \sort($aTop);
+ \sort($aList);
+
+ $aCache[$sDir] = \array_merge($aTop, $aList);
+ return $aCache[$sDir];
+ }
+
+ /**
+ * @param string $sName
+ * @param string $sHtml
+ *
+ * @return string
+ */
+ public function ProcessTemplate($sName, $sHtml)
+ {
+ $sHtml = $this->Plugins()->ProcessTemplate($sName, $sHtml);
+ $sHtml = \preg_replace('/\{\{INCLUDE\/([a-zA-Z]+)\/PLACE\}\}/', '', $sHtml);
+
+ $sHtml = \preg_replace('/';
+ }
+
+ unset($aTemplates);
+
+ return $bJsOutput ? 'window.rainloopTEMPLATES='.\MailSo\Base\Utils::Php2js(array($sHtml), $this->Logger()).';' : $sHtml;
+ }
+
+ /**
+ * @param string $sLanguage
+ *
+ * @return string
+ */
+ private function convertLanguageNameToMomentLanguageName($sLanguage)
+ {
+ $aHelper = array('en_gb' => 'en-gb', 'fr_ca' => 'fr-ca', 'pt_br' => 'pt-br',
+ 'uk_ua' => 'ua', 'zh_cn' => 'zh-cn', 'zh_tw' => 'zh-tw');
+
+ return isset($aHelper[$sLanguage]) ? $aHelper[$sLanguage] : \substr($sLanguage, 0, 2);
+ }
+
+ /**
+ * @param string $sLanguage
+ * @param bool $bAdmin = false
+ * @param bool $bWrapByScriptTag = true
+ *
+ * @return string
+ */
+ private function compileLanguage($sLanguage, $bAdmin = false, $bWrapByScriptTag = true)
+ {
+ $aResultLang = array();
+
+ $sMoment = 'window.moment && window.moment.lang && window.moment.lang(\'en\');';
+ $sMomentFileName = APP_VERSION_ROOT_PATH.'app/localization/moment/'.
+ $this->convertLanguageNameToMomentLanguageName($sLanguage).'.js';
+
+ if (\file_exists($sMomentFileName))
+ {
+ $sMoment = \file_get_contents($sMomentFileName);
+ $sMoment = \preg_replace('/\/\/[^\n]+\n/', '', $sMoment);
+ }
+
+ \RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/localization/langs.yml', $aResultLang);
+ \RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/localization/'.
+ ($bAdmin ? 'admin' : 'webmail').'/_source.en.yml', $aResultLang);
+ \RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/localization/'.
+ ($bAdmin ? 'admin' : 'webmail').'/'.$sLanguage.'.yml', $aResultLang);
+
+ $this->Plugins()->ReadLang($sLanguage, $aResultLang);
+
+ $sLangJs = '';
+ $aLangKeys = \array_keys($aResultLang);
+ foreach ($aLangKeys as $sKey)
+ {
+ $sString = isset($aResultLang[$sKey]) ? $aResultLang[$sKey] : $sKey;
+
+ $sLangJs .= '"'.\str_replace('"', '\\"', \str_replace('\\', '\\\\', $sKey)).'":'
+ .'"'.\str_replace(array("\r", "\n", "\t"), array('\r', '\n', '\t'),
+ \str_replace('"', '\\"', \str_replace('\\', '\\\\', $sString))).'",';
+ }
+
+ $sResult = empty($sLangJs) ? 'null' : '{'.\substr($sLangJs, 0, -1).'}';
+
+ return
+ ($bWrapByScriptTag ? '' : '')
+ ;
+ }
+
+ /**
+ * @param array $aAppData
+ * @param bool $bWrapByScriptTag = true
+ *
+ * @return string
+ */
+ private function compileAppData($aAppData, $bWrapByScriptTag = true)
+ {
+ return
+ ($bWrapByScriptTag ? '' : '')
+ ;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/RainLoop/Settings.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/RainLoop/Settings.php
new file mode 100644
index 0000000..d234f08
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/RainLoop/Settings.php
@@ -0,0 +1,78 @@
+aData = array();
+ $this->bLocal = !!$bLocal;
+ }
+
+ /**
+ * @param array $aData
+ *
+ * @return \RainLoop\Settings
+ */
+ public function InitData($aData)
+ {
+ if (\is_array($aData))
+ {
+ $this->aData = $aData;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function DataAsArray()
+ {
+ return $this->aData;
+ }
+
+ /**
+ * @return bool
+ */
+ public function IsLocal()
+ {
+ return $this->bLocal;
+ }
+
+ /**
+ * @param string $sName
+ * @param mixed $mDefValue = null
+ *
+ * @return mixed
+ */
+ public function GetConf($sName, $mDefValue = null)
+ {
+ return isset($this->aData[$sName]) ? $this->aData[$sName] : $mDefValue;
+ }
+
+ /**
+ * @param string $sName
+ * @param mixed $mValue
+ *
+ * @return void
+ */
+ public function SetConf($sName, $mValue)
+ {
+ $this->aData[$sName] = $mValue;
+ }
+}
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/RainLoop/Social.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/RainLoop/Social.php
new file mode 100644
index 0000000..0183b84
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/RainLoop/Social.php
@@ -0,0 +1,788 @@
+oHttp = $oHttp;
+ $this->oActions = $oActions;
+ }
+
+ /**
+ * @return bool
+ */
+ public function GoogleDisconnect($oAccount)
+ {
+ $oGoogle = $this->GoogleConnector();
+ if ($oAccount && $oGoogle)
+ {
+ $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
+ $sEncodedeData = $oSettings->GetConf('GoogleAccessToken', '');
+
+ if (!empty($sEncodedeData))
+ {
+ $aData = \RainLoop\Utils::DecodeKeyValues($sEncodedeData);
+ if (\is_array($aData) && !empty($aData['id']))
+ {
+ $this->oActions->StorageProvider()->Clear(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->GoogleUserLoginStorageKey($oGoogle, $aData['id'])
+ );
+ }
+ }
+
+ $oSettings->SetConf('GoogleAccessToken', '');
+ $oSettings->SetConf('GoogleSocialName', '');
+
+ return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
+ }
+
+ return false;
+ }
+
+ /**
+ * @return bool
+ */
+ public function FacebookDisconnect($oAccount)
+ {
+ $oFacebook = $this->FacebookConnector($oAccount ? $oAccount : null);
+ if ($oAccount && $oFacebook)
+ {
+ $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
+
+ $sEncodedeData = $oSettings->GetConf('FacebookAccessToken', '');
+
+ if (!empty($sEncodedeData))
+ {
+ $aData = \RainLoop\Utils::DecodeKeyValues($sEncodedeData);
+ if (is_array($aData) && isset($aData['id']))
+ {
+ $this->oActions->StorageProvider()->Clear(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->FacebookUserLoginStorageKey($oFacebook, $aData['id'])
+ );
+ }
+ }
+
+ $oSettings->SetConf('FacebookAccessToken', '');
+ $oSettings->SetConf('FacebookSocialName', '');
+
+ return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
+ }
+
+ return false;
+ }
+
+ /**
+ * @return bool
+ */
+ public function TwitterDisconnect($oAccount)
+ {
+ $oTwitter = $this->TwitterConnector();
+ if ($oAccount && $oTwitter)
+ {
+ $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
+ $sEncodedeData = $oSettings->GetConf('TwitterAccessToken', '');
+
+ if (!empty($sEncodedeData))
+ {
+ $aData = \RainLoop\Utils::DecodeKeyValues($sEncodedeData);
+ if (is_array($aData) && isset($aData['user_id']))
+ {
+ $this->oActions->StorageProvider()->Clear(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->TwitterUserLoginStorageKey($oTwitter, $aData['user_id'])
+ );
+ }
+ }
+
+ $oSettings->SetConf('TwitterAccessToken', '');
+ $oSettings->SetConf('TwitterSocialName', '');
+
+ return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
+ }
+
+ return false;
+ }
+
+ /**
+ * @return string
+ */
+ public function GooglePopupService($bGmail = false)
+ {
+ $sResult = '';
+ $sLoginUrl = '';
+ $oAccount = null;
+
+ $bLogin = false;
+ $iErrorCode = \RainLoop\Notifications::UnknownError;
+
+ try
+ {
+ $oGoogle = $this->GoogleConnector();
+ if ($this->oHttp->HasQuery('error'))
+ {
+ $iErrorCode = ('access_denied' === $this->oHttp->GetQuery('error')) ?
+ \RainLoop\Notifications::SocialGoogleLoginAccessDisable : \RainLoop\Notifications::UnknownError;
+ }
+ else if ($oGoogle)
+ {
+ $oAccount = $this->oActions->GetAccount();
+ $bLogin = !$oAccount;
+
+ $sCheckToken = '';
+ $sCheckAuth = '';
+ $sState = $this->oHttp->GetQuery('state');
+ if (!empty($sState))
+ {
+ $aParts = explode('|', $sState, 3);
+
+ if (!$bGmail)
+ {
+ $bGmail = !empty($aParts[0]) ? '1' === (string) $aParts[0] : false;
+ }
+
+ $sCheckToken = !empty($aParts[1]) ? $aParts[1] : '';
+ $sCheckAuth = !empty($aParts[2]) ? $aParts[2] : '';
+ }
+
+ $sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialGoogle';
+ if (!$this->oHttp->HasQuery('code'))
+ {
+ $aParams = array(
+ 'scope' => \trim(\implode(' ', array(
+ 'https://www.googleapis.com/auth/userinfo.email',
+ 'https://www.googleapis.com/auth/userinfo.profile',
+ $bGmail ? 'https://mail.google.com/' : ''
+ ))),
+ 'state' => ($bGmail ? '1' : '0').'|'.\RainLoop\Utils::GetConnectionToken().'|'.$this->oActions->GetSpecAuthToken(),
+ 'response_type' => 'code'
+ );
+
+// if ($bGmail)
+// {
+// $aParams['access_type'] = 'offline';
+// $aParams['approval_prompt'] = 'force';
+// }
+
+ $sLoginUrl = $oGoogle->getAuthenticationUrl('https://accounts.google.com/o/oauth2/auth', $sRedirectUrl, $aParams);
+ }
+ else if (!empty($sState) && $sCheckToken === \RainLoop\Utils::GetConnectionToken())
+ {
+ if (!empty($sCheckAuth))
+ {
+ $this->oActions->SetSpecAuthToken($sCheckAuth);
+ $oAccount = $this->oActions->GetAccount();
+ $bLogin = !$oAccount;
+ }
+
+ $aParams = array('code' => $this->oHttp->GetQuery('code'), 'redirect_uri' => $sRedirectUrl);
+ $aAuthorizationResponse = $oGoogle->getAccessToken('https://accounts.google.com/o/oauth2/token', 'authorization_code', $aParams);
+
+ if (!empty($aAuthorizationResponse['result']['access_token']))
+ {
+ $oGoogle->setAccessToken($aAuthorizationResponse['result']['access_token']);
+ $aUserInfoResponse = $oGoogle->fetch('https://www.googleapis.com/oauth2/v2/userinfo');
+
+ if (!empty($aUserInfoResponse['result']['id']))
+ {
+ if ($bLogin)
+ {
+ $aUserData = null;
+ if ($bGmail)
+ {
+ if (!empty($aUserInfoResponse['result']['email']))
+ {
+ $aUserData = array(
+ 'Email' => $aUserInfoResponse['result']['email'],
+ 'Password' => APP_GOOGLE_ACCESS_TOKEN_PREFIX.$aAuthorizationResponse['result']['access_token']
+ );
+ }
+ }
+ else
+ {
+ $sUserData = $this->oActions->StorageProvider()->Get(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->GoogleUserLoginStorageKey($oGoogle, $aUserInfoResponse['result']['id'])
+ );
+
+ $aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData);
+ }
+
+ if ($aUserData && \is_array($aUserData) &&
+ !empty($aUserData['Email']) && isset($aUserData['Password']))
+ {
+ $iErrorCode = $this->loginProcess($oAccount, $aUserData['Email'], $aUserData['Password']);
+ }
+ else
+ {
+ $iErrorCode = \RainLoop\Notifications::SocialGoogleLoginAccessDisable;
+ }
+ }
+
+ if ($oAccount && !$bGmail)
+ {
+ $aUserData = array(
+ 'ID' => $aUserInfoResponse['result']['id'],
+ 'Email' => $oAccount->Email(),
+ 'Password' => $oAccount->Password()
+ );
+
+ $sSocialName = !empty($aUserInfoResponse['result']['name']) ? $aUserInfoResponse['result']['name'] : '';
+ $sSocialName .= !empty($aUserInfoResponse['result']['email']) ? ' ('.$aUserInfoResponse['result']['email'].')' : '';
+ $sSocialName = \trim($sSocialName);
+
+ $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
+
+ $oSettings->SetConf('GoogleAccessToken', \RainLoop\Utils::EncodeKeyValues(array(
+ 'id' => $aUserInfoResponse['result']['id']
+ )));
+
+ $oSettings->SetConf('GoogleSocialName', $sSocialName);
+
+ $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
+
+ $this->oActions->StorageProvider()->Put(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->GoogleUserLoginStorageKey($oGoogle, $aUserInfoResponse['result']['id']),
+ \RainLoop\Utils::EncodeKeyValues($aUserData));
+
+ $iErrorCode = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+
+ if ($sLoginUrl)
+ {
+ $this->oActions->Location($sLoginUrl);
+ }
+ else
+ {
+ @\header('Content-Type: text/html; charset=utf-8');
+ $sCallBackType = $bLogin ? '_login' : '';
+ $sConnectionFunc = 'rl_'.\md5(\RainLoop\Utils::GetConnectionToken()).'_google'.$sCallBackType.'_service';
+ $sResult = '';
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function FacebookPopupService()
+ {
+ $sResult = '';
+ $sLoginUrl = '';
+ $sSocialName = '';
+
+ $mData = false;
+ $sUserData = '';
+ $aUserData = false;
+ $oAccount = null;
+
+ $bLogin = false;
+ $iErrorCode = \RainLoop\Notifications::UnknownError;
+
+ if (0 === \strlen($this->oActions->GetSpecAuthToken()) && $this->oHttp->HasQuery('rlah'))
+ {
+ $this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', ''));
+ }
+
+ $oAccount = $this->oActions->GetAccount();
+
+ $oFacebook = $this->FacebookConnector($oAccount);
+ if ($oFacebook)
+ {
+ try
+ {
+ $oSession = $oFacebook->getSessionFromRedirect();
+ if (!$oSession && !$this->oHttp->HasQuery('state'))
+ {
+ $sLoginUrl = $oFacebook->getLoginUrl().'&display=popup';
+ }
+ else if ($oSession)
+ {
+ $oRequest = new \Facebook\FacebookRequest($oSession, 'GET', '/me');
+ $oResponse = $oRequest->execute();
+ $oGraphObject = $oResponse->getGraphObject();
+
+ $mData = $oGraphObject->getProperty('id');
+ $sSocialName = $oGraphObject->getProperty('name');
+
+ if ($oAccount)
+ {
+ if ($mData && 0 < \strlen($mData))
+ {
+ $aUserData = array(
+ 'Email' => $oAccount->Email(),
+ 'Password' => $oAccount->Password()
+ );
+
+ $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
+ $oSettings->SetConf('FacebookSocialName', $sSocialName);
+ $oSettings->SetConf('FacebookAccessToken', \RainLoop\Utils::EncodeKeyValues(array('id' => $mData)));
+
+
+ $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
+
+ $this->oActions->StorageProvider()->Put(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->FacebookUserLoginStorageKey($oFacebook, $mData),
+ \RainLoop\Utils::EncodeKeyValues($aUserData));
+
+ $iErrorCode = 0;
+ }
+ }
+ else
+ {
+ $bLogin = true;
+
+ if ($mData && 0 < \strlen($mData))
+ {
+ $sUserData = $this->oActions->StorageProvider()->Get(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->FacebookUserLoginStorageKey($oFacebook, $mData));
+
+ if ($sUserData)
+ {
+ $aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData);
+ }
+ }
+
+ if ($aUserData && \is_array($aUserData) &&
+ !empty($aUserData['Email']) && isset($aUserData['Password']))
+ {
+ $iErrorCode = $this->loginProcess($oAccount, $aUserData['Email'], $aUserData['Password']);
+ }
+ else
+ {
+ $iErrorCode = \RainLoop\Notifications::SocialFacebookLoginAccessDisable;
+ }
+ }
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+ }
+
+ if ($sLoginUrl)
+ {
+ $this->oActions->Location($sLoginUrl);
+ }
+ else
+ {
+ $this->oHttp->ServerNoCache();
+
+ @\header('Content-Type: text/html; charset=utf-8');
+
+ $sCallBackType = $bLogin ? '_login' : '';
+ $sConnectionFunc = 'rl_'.\md5(\RainLoop\Utils::GetConnectionToken()).'_facebook'.$sCallBackType.'_service';
+ $sResult = '';
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @return string
+ */
+ public function TwitterPopupService()
+ {
+ $sResult = '';
+ $sLoginUrl = '';
+
+ $sSocialName = '';
+ $oAccount = null;
+
+ $bLogin = false;
+ $iErrorCode = \RainLoop\Notifications::UnknownError;
+
+ $sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialTwitter';
+ if (0 < strlen($this->oActions->GetSpecAuthToken()))
+ {
+ $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
+ }
+ else if ($this->oHttp->HasQuery('rlah'))
+ {
+ $this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', ''));
+ $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
+ }
+
+ try
+ {
+ $oTwitter = $this->TwitterConnector();
+ if ($oTwitter)
+ {
+ $sSessionKey = \implode('_', array('twitter',
+ \md5($oTwitter->config['consumer_secret']), \md5(\RainLoop\Utils::GetConnectionToken()), 'AuthSessionData'));
+
+ $oAccount = $this->oActions->GetAccount();
+ if ($oAccount)
+ {
+ if (isset($_REQUEST['oauth_verifier']))
+ {
+ $sAuth = $this->oActions->Cacher()->Get($sSessionKey);
+ $oAuth = $sAuth ? \json_decode($sAuth, true) : null;
+
+ if ($oAuth && !empty($oAuth['oauth_token']) && !empty($oAuth['oauth_token_secret']))
+ {
+ $oTwitter->config['user_token'] = $oAuth['oauth_token'];
+ $oTwitter->config['user_secret'] = $oAuth['oauth_token_secret'];
+
+ $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/access_token', ''), array(
+ 'oauth_callback' => $sRedirectUrl,
+ 'oauth_verifier' => $_REQUEST['oauth_verifier']
+ ));
+
+ if (200 === $iCode && isset($oTwitter->response['response']))
+ {
+ $aAccessToken = $oTwitter->extract_params($oTwitter->response['response']);
+ if ($aAccessToken && isset($aAccessToken['oauth_token']) && !empty($aAccessToken['user_id']))
+ {
+ $oTwitter->config['user_token'] = $aAccessToken['oauth_token'];
+ $oTwitter->config['user_secret'] = $aAccessToken['oauth_token_secret'];
+
+ $sSocialName = !empty($aAccessToken['screen_name']) ? '@'.$aAccessToken['screen_name'] : $aAccessToken['user_id'];
+ $sSocialName = \trim($sSocialName);
+
+ $aUserData = array(
+ 'Email' => $oAccount->Email(),
+ 'Password' => $oAccount->Password()
+ );
+
+ $oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
+ $oSettings->SetConf('TwitterAccessToken', \RainLoop\Utils::EncodeKeyValues($aAccessToken));
+ $oSettings->SetConf('TwitterSocialName', $sSocialName);
+ $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
+
+ $this->oActions->StorageProvider()->Put(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->TwitterUserLoginStorageKey($oTwitter, $aAccessToken['user_id']),
+ \RainLoop\Utils::EncodeKeyValues($aUserData));
+
+ $iErrorCode = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ $aParams = array(
+ 'oauth_callback' => $sRedirectUrl,
+ 'x_auth_access_type' => 'read'
+ );
+
+ $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/request_token', ''), $aParams);
+ if (200 === $iCode && isset($oTwitter->response['response']))
+ {
+ $oAuth = $oTwitter->extract_params($oTwitter->response['response']);
+ if (!empty($oAuth['oauth_token']))
+ {
+ $this->oActions->Cacher()->Set($sSessionKey, \json_encode($oAuth));
+ $sLoginUrl = $oTwitter->url('oauth/authenticate', '').'?oauth_token='.$oAuth['oauth_token'];
+ }
+ }
+ }
+ }
+ else
+ {
+ $bLogin = true;
+
+ if (isset($_REQUEST['oauth_verifier']))
+ {
+ $sAuth = $this->oActions->Cacher()->Get($sSessionKey);
+ $oAuth = $sAuth ? \json_decode($sAuth, true) : null;
+ if ($oAuth && !empty($oAuth['oauth_token']) && !empty($oAuth['oauth_token_secret']))
+ {
+ $oTwitter->config['user_token'] = $oAuth['oauth_token'];
+ $oTwitter->config['user_secret'] = $oAuth['oauth_token_secret'];
+
+ $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/access_token', ''), array(
+ 'oauth_callback' => $sRedirectUrl,
+ 'oauth_verifier' => $_REQUEST['oauth_verifier']
+ ));
+
+ if (200 === $iCode && isset($oTwitter->response['response']))
+ {
+ $aAccessToken = $oTwitter->extract_params($oTwitter->response['response']);
+ if ($aAccessToken && isset($aAccessToken['oauth_token']) && !empty($aAccessToken['user_id']))
+ {
+ $sUserData = $this->oActions->StorageProvider()->Get(null,
+ \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
+ $this->TwitterUserLoginStorageKey($oTwitter, $aAccessToken['user_id'])
+ );
+
+ $aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData);
+
+ if ($aUserData && \is_array($aUserData) &&
+ !empty($aUserData['Email']) &&
+ isset($aUserData['Password']))
+ {
+ $iErrorCode = $this->loginProcess($oAccount, $aUserData['Email'], $aUserData['Password']);
+ }
+ else
+ {
+ $iErrorCode = \RainLoop\Notifications::SocialTwitterLoginAccessDisable;
+ }
+
+ $this->oActions->Cacher()->Delete($sSessionKey);
+ }
+ }
+ }
+ }
+ else
+ {
+ $aParams = array(
+ 'oauth_callback' => $sRedirectUrl,
+ 'x_auth_access_type' => 'read'
+ );
+
+ $iCode = $oTwitter->request('POST', $oTwitter->url('oauth/request_token', ''), $aParams);
+ if (200 === $iCode && isset($oTwitter->response['response']))
+ {
+ $oAuth = $oTwitter->extract_params($oTwitter->response['response']);
+ if (!empty($oAuth['oauth_token']))
+ {
+ $this->oActions->Cacher()->Set($sSessionKey, \json_encode($oAuth));
+ $sLoginUrl = $oTwitter->url('oauth/authenticate', '').'?oauth_token='.$oAuth['oauth_token'];
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+
+ if ($sLoginUrl)
+ {
+ $this->oActions->Location($sLoginUrl);
+ }
+ else
+ {
+ @\header('Content-Type: text/html; charset=utf-8');
+ $sCallBackType = $bLogin ? '_login' : '';
+ $sConnectionFunc = 'rl_'.\md5(\RainLoop\Utils::GetConnectionToken()).'_twitter'.$sCallBackType.'_service';
+ $sResult = '';
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @return \OAuth2\Client|null
+ */
+ public function GoogleConnector()
+ {
+ $oGoogle = false;
+ $oConfig = $this->oActions->Config();
+ if ($oConfig->Get('social', 'google_enable', false) &&
+ '' !== \trim($oConfig->Get('social', 'google_client_id', '')) &&
+ '' !== \trim($oConfig->Get('social', 'google_client_secret', '')))
+ {
+ include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/Client.php';
+ include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/IGrantType.php';
+ include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php';
+ include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/RefreshToken.php';
+
+ try
+ {
+ $oGoogle = new \OAuth2\Client(
+ \trim($oConfig->Get('social', 'google_client_id', '')),
+ \trim($oConfig->Get('social', 'google_client_secret', '')));
+
+ $sProxy = $this->oActions->Config()->Get('labs', 'curl_proxy', '');
+ if (0 < \strlen($sProxy))
+ {
+ $oGoogle->setCurlOption(CURLOPT_PROXY, $sProxy);
+
+ $sProxyAuth = $this->oActions->Config()->Get('labs', 'curl_proxy_auth', '');
+ if (0 < \strlen($sProxyAuth))
+ {
+ $oGoogle->setCurlOption(CURLOPT_PROXYUSERPWD, $sProxyAuth);
+ }
+ }
+ }
+ catch (\Exception $oException)
+ {
+ $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+ }
+
+ return false === $oGoogle ? null : $oGoogle;
+ }
+
+ /**
+ * @return \tmhOAuth|null
+ */
+ public function TwitterConnector()
+ {
+ $oTwitter = false;
+ $oConfig = $this->oActions->Config();
+ if ($oConfig->Get('social', 'twitter_enable', false) &&
+ '' !== \trim($oConfig->Get('social', 'twitter_consumer_key', '')) &&
+ '' !== \trim($oConfig->Get('social', 'twitter_consumer_secret', '')))
+ {
+ include_once APP_VERSION_ROOT_PATH.'app/libraries/tmhOAuth/tmhOAuth.php';
+ include_once APP_VERSION_ROOT_PATH.'app/libraries/tmhOAuth/tmhUtilities.php';
+
+ $sProxy = $this->oActions->Config()->Get('labs', 'curl_proxy', '');
+ $sProxyAuth = $this->oActions->Config()->Get('labs', 'curl_proxy_auth', '');
+
+ $oTwitter = new \tmhOAuth(array(
+ 'consumer_key' => \trim($oConfig->Get('social', 'twitter_consumer_key', '')),
+ 'consumer_secret' => \trim($oConfig->Get('social', 'twitter_consumer_secret', '')),
+ 'curl_proxy' => 0 < \strlen($sProxy) ? $sProxy : false,
+ 'curl_proxyuserpwd' => 0 < \strlen($sProxyAuth) ? $sProxyAuth : false
+ ));
+ }
+
+ return false === $oTwitter ? null : $oTwitter;
+ }
+
+ /**
+ * @param \RainLoop\Model\Account|null $oAccount = null
+ *
+ * @return \RainLoop\Common\RainLoopFacebookRedirectLoginHelper|null
+ */
+ public function FacebookConnector($oAccount = null)
+ {
+ $oFacebook = false;
+ $oConfig = $this->oActions->Config();
+ $sAppID = \trim($oConfig->Get('social', 'fb_app_id', ''));
+
+ if (\version_compare(PHP_VERSION, '5.4.0', '>=') &&
+ $oConfig->Get('social', 'fb_enable', false) && '' !== $sAppID &&
+ '' !== \trim($oConfig->Get('social', 'fb_app_secret', '')) &&
+ \class_exists('Facebook\FacebookSession')
+ )
+ {
+ \Facebook\FacebookSession::setDefaultApplication($sAppID,
+ \trim($oConfig->Get('social', 'fb_app_secret', '')));
+
+ $sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialFacebook';
+ if (0 < \strlen($this->oActions->GetSpecAuthToken()))
+ {
+ $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
+ }
+ else if ($this->oHttp->HasQuery('rlah'))
+ {
+ $this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', ''));
+ $sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
+ }
+
+ try
+ {
+ $oAccount = $this->oActions->GetAccount();
+
+ $oFacebook = new \RainLoop\Common\RainLoopFacebookRedirectLoginHelper($sRedirectUrl);
+ $oFacebook->initRainLoopData(array(
+ 'rlAppId' => $sAppID,
+ 'rlAccount' => $oAccount,
+ 'rlUserHash' => \RainLoop\Utils::GetConnectionToken(),
+ 'rlStorageProvaider' => $this->oActions->StorageProvider()
+ ));
+ }
+ catch (\Exception $oException)
+ {
+ $this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
+ }
+ }
+
+ return false === $oFacebook ? null : $oFacebook;
+ }
+
+ /**
+ * @return string
+ */
+ public function GoogleUserLoginStorageKey($oGoogle, $sGoogleUserId)
+ {
+ return \implode('_', array('google', \md5($oGoogle->getClientId()), $sGoogleUserId, APP_SALT));
+ }
+
+ /**
+ * @return string
+ */
+ public function FacebookUserLoginStorageKey($oFacebook, $sFacebookUserId)
+ {
+ return \implode('_', array('facebookNew', \md5($oFacebook->GetRLAppId()), $sFacebookUserId, APP_SALT));
+ }
+
+ /**
+ * @return string
+ */
+ public function TwitterUserLoginStorageKey($oTwitter, $sTwitterUserId)
+ {
+ return \implode('_', array('twitter', \md5($oTwitter->config['consumer_secret']), $sTwitterUserId, APP_SALT));
+ }
+
+ /**
+ * @param \RainLoop\Model\Account|null $oAccount
+ * @param string $sEmail
+ * @param string $sPassword
+ *
+ * @return int
+ */
+ private function loginProcess(&$oAccount, $sEmail, $sPassword)
+ {
+ $iErrorCode = \RainLoop\Notifications::UnknownError;
+
+ try
+ {
+ $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword);
+ if ($oAccount instanceof \RainLoop\Model\Account)
+ {
+ $this->oActions->AuthToken($oAccount);
+ $iErrorCode = 0;
+ }
+ else
+ {
+ $oAccount = null;
+ $iErrorCode = \RainLoop\Notifications::AuthError;
+ }
+ }
+ catch (\RainLoop\Exceptions\ClientException $oException)
+ {
+ $iErrorCode = $oException->getCode();
+ }
+ catch (\Exception $oException)
+ {
+ unset($oException);
+ $iErrorCode = \RainLoop\Notifications::UnknownError;
+ }
+
+ return $iErrorCode;
+ }
+}
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/RainLoop/Utils.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/RainLoop/Utils.php
new file mode 100644
index 0000000..ebe79da
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/RainLoop/Utils.php
@@ -0,0 +1,734 @@
+setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
+ $oRsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
+ $oRsa->setPrivateKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
+
+ $sPrivateKey = \file_exists(APP_PRIVATE_DATA.'rsa/private') ?
+ \file_get_contents(APP_PRIVATE_DATA.'rsa/private') : '';
+
+ if (!empty($sPrivateKey))
+ {
+ $oRsa->loadKey($sPrivateKey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
+ $oRsa->loadKey($oRsa->getPublicKey(), CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
+
+ \RainLoop\Utils::$RSA = $oRsa;
+ }
+ }
+ }
+
+ return \RainLoop\Utils::$RSA;
+ }
+
+ /**
+ * @return string
+ */
+ static public function RsaPrivateKey()
+ {
+ if (!empty(\RainLoop\Utils::$RsaKey))
+ {
+ return \RainLoop\Utils::$RsaKey;
+ }
+
+ \RainLoop\Utils::$RsaKey = \file_exists(APP_PRIVATE_DATA.'rsa/private') ?
+ \file_get_contents(APP_PRIVATE_DATA.'rsa/private') : '';
+
+ \RainLoop\Utils::$RsaKey = \is_string(\RainLoop\Utils::$RsaKey) ? \RainLoop\Utils::$RsaKey : '';
+ }
+
+ /**
+ * @param string $sString
+ * @param string $sKey = ''
+ *
+ * @return string|false
+ */
+ static public function EncryptStringRSA($sString, $sKey = '')
+ {
+ $sResult = '';
+ $sKey = \md5($sKey);
+
+ $sPrivateKey = \RainLoop\Utils::RsaPrivateKey();
+ if (!empty($sPrivateKey))
+ {
+ $oPrivKey = \openssl_pkey_get_private($sPrivateKey);
+ $oKeyDetails = \openssl_pkey_get_details($oPrivKey);
+
+ if (!empty($oKeyDetails['key']) && !empty($oKeyDetails['bits']))
+ {
+ $oPubKey = \openssl_pkey_get_public($oKeyDetails['key']);
+
+ $iC = (($oKeyDetails['bits'] / 8) - 15);
+ $aString = \str_split($sString, $iC);
+
+ foreach ($aString as $iIndex => $sLine)
+ {
+ $sEncrypted = '';
+ \openssl_public_encrypt($sLine, $sEncrypted, $oPubKey);
+ $aString[$iIndex] = $sEncrypted;
+ }
+
+ $aString[] = $sKey;
+ $sResult = @\serialize($aString);
+
+ \openssl_free_key($oPubKey);
+ }
+
+ \openssl_free_key($oPrivKey);
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sString
+ * @param string $sKey = ''
+ *
+ * @return string|false
+ */
+ static public function DecryptStringRSA($sString, $sKey = '')
+ {
+ $sResult = '';
+ $sKey = \md5($sKey);
+
+ $sPrivateKey = \RainLoop\Utils::RsaPrivateKey();
+ if (!empty($sPrivateKey) && !empty($sString))
+ {
+ $oPrivKey = \openssl_pkey_get_private($sPrivateKey);
+
+ $aString = @\unserialize($sString);
+ if (\is_array($aString))
+ {
+ if ($sKey === \array_pop($aString))
+ {
+ foreach ($aString as $iIndex => $sLine)
+ {
+ $sDecrypted = '';
+ \openssl_private_decrypt($sLine, $sDecrypted, $oPrivKey);
+ $aString[$iIndex] = $sDecrypted;
+ }
+
+ $sResult = \implode('', $aString);
+ }
+ }
+
+ \openssl_free_key($oPrivKey);
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sString
+ * @param string $sKey
+ *
+ * @return string
+ */
+ static public function EncryptString($sString, $sKey)
+ {
+ return \MailSo\Base\Crypt::XxteaEncrypt($sString, $sKey);
+ }
+
+ /**
+ * @param string $sEncriptedString
+ * @param string $sKey
+ *
+ * @return string
+ */
+ static public function DecryptString($sEncriptedString, $sKey)
+ {
+ return \MailSo\Base\Crypt::XxteaDecrypt($sEncriptedString, $sKey);
+ }
+
+ /**
+ * @param string $sString
+ * @param string $sKey
+ *
+ * @return string
+ */
+ static public function EncryptStringQ($sString, $sKey)
+ {
+// if (\MailSo\Base\Utils::FunctionExistsAndEnabled('openssl_pkey_get_private'))
+// {
+// return \RainLoop\Utils::EncryptStringRSA($sString,
+// $sKey.'Q'.\RainLoop\Utils::GetShortToken());
+// }
+
+ return \MailSo\Base\Crypt::XxteaEncrypt($sString,
+ $sKey.'Q'.\RainLoop\Utils::GetShortToken());
+ }
+
+ /**
+ * @param string $sEncriptedString
+ * @param string $sKey
+ *
+ * @return string
+ */
+ static public function DecryptStringQ($sEncriptedString, $sKey)
+ {
+// if (\MailSo\Base\Utils::FunctionExistsAndEnabled('openssl_pkey_get_private'))
+// {
+// return \RainLoop\Utils::DecryptStringRSA($sEncriptedString,
+// $sKey.'Q'.\RainLoop\Utils::GetShortToken());
+// }
+
+ return \MailSo\Base\Crypt::XxteaDecrypt($sEncriptedString,
+ $sKey.'Q'.\RainLoop\Utils::GetShortToken());
+ }
+
+ /**
+ * @param array $aValues
+ * @param string $sCustomKey = ''
+ *
+ * @return string
+ */
+ static public function EncodeKeyValues(array $aValues, $sCustomKey = '')
+ {
+ return \MailSo\Base\Utils::UrlSafeBase64Encode(
+ \RainLoop\Utils::EncryptString(@\serialize($aValues), \md5(APP_SALT.$sCustomKey)));
+ }
+
+ /**
+ * @param string $sEncodedValues
+ * @param string $sCustomKey = ''
+ *
+ * @return array
+ */
+ static public function DecodeKeyValues($sEncodedValues, $sCustomKey = '')
+ {
+ $aResult = @\unserialize(
+ \RainLoop\Utils::DecryptString(
+ \MailSo\Base\Utils::UrlSafeBase64Decode($sEncodedValues), \md5(APP_SALT.$sCustomKey)));
+
+ return \is_array($aResult) ? $aResult : array();
+ }
+
+ /**
+ * @param array $aValues
+ * @param string $sCustomKey = ''
+ *
+ * @return string
+ */
+ static public function EncodeKeyValuesQ(array $aValues, $sCustomKey = '')
+ {
+ return \MailSo\Base\Utils::UrlSafeBase64Encode(
+ \RainLoop\Utils::EncryptStringQ(
+ @\serialize($aValues), \md5(APP_SALT.$sCustomKey)));
+ }
+
+ /**
+ * @param string $sEncodedValues
+ * @param string $sCustomKey = ''
+ *
+ * @return array
+ */
+ static public function DecodeKeyValuesQ($sEncodedValues, $sCustomKey = '')
+ {
+ $aResult = @\unserialize(
+ \RainLoop\Utils::DecryptStringQ(
+ \MailSo\Base\Utils::UrlSafeBase64Decode($sEncodedValues), \md5(APP_SALT.$sCustomKey)));
+
+ return \is_array($aResult) ? $aResult : array();
+ }
+
+ /**
+ * @return string
+ */
+ static public function GetConnectionToken()
+ {
+ $sKey = 'rltoken';
+
+ $sToken = \RainLoop\Utils::GetCookie($sKey, null);
+ if (null === $sToken)
+ {
+ $sToken = \MailSo\Base\Utils::Md5Rand(APP_SALT);
+ \RainLoop\Utils::SetCookie($sKey, $sToken, \time() + 60 * 60 * 24 * 30);
+ }
+
+ return \md5('Connection'.APP_SALT.$sToken.'Token'.APP_SALT);
+ }
+
+ /**
+ * @return string
+ */
+ static public function Fingerprint()
+ {
+ return \md5(empty($_SERVER['HTTP_USER_AGENT']) ? 'RainLoopFingerprint' : $_SERVER['HTTP_USER_AGENT']);
+ }
+
+ /**
+ * @return string
+ */
+ static public function GetShortToken()
+ {
+ $sKey = 'rlsession';
+
+ $sToken = \RainLoop\Utils::GetCookie($sKey, null);
+ if (null === $sToken)
+ {
+ $sToken = \MailSo\Base\Utils::Md5Rand(APP_SALT);
+ \RainLoop\Utils::SetCookie($sKey, $sToken, 0);
+ }
+
+ return \md5('Session'.APP_SALT.$sToken.'Token'.APP_SALT);
+ }
+
+ /**
+ * @return void
+ */
+ static public function UpdateConnectionToken()
+ {
+ $sKey = 'rltoken';
+
+ $sToken = \RainLoop\Utils::GetCookie($sKey, '');
+ if (!empty($sToken))
+ {
+ \RainLoop\Utils::SetCookie($sKey, $sToken, \time() + 60 * 60 * 24 * 30);
+ }
+ }
+
+ /**
+ * @return string
+ */
+ static public function GetCsrfToken()
+ {
+ return \md5('Csrf'.APP_SALT.self::GetConnectionToken().'Token'.APP_SALT);
+ }
+
+ /**
+ * @param string $sPath
+ *
+ * @return string
+ */
+ public static function PathMD5($sPath)
+ {
+ $sResult = '';
+ if (@\is_dir($sPath))
+ {
+ $oDirIterator = new \RecursiveDirectoryIterator($sPath);
+ $oIterator = new \RecursiveIteratorIterator($oDirIterator, \RecursiveIteratorIterator::SELF_FIRST);
+
+ foreach ($oIterator as $oFile)
+ {
+ $sResult = \md5($sResult.($oFile->isFile() ? \md5_file($oFile) : $oFile));
+ }
+ }
+
+ return $sResult;
+ }
+
+ /**
+ * @param string $sFileName
+ * @param array $aResultLang
+ *
+ * @return void
+ */
+ public static function ReadAndAddLang($sFileName, &$aResultLang)
+ {
+ if (\file_exists($sFileName))
+ {
+ $isYml = '.yml' === substr($sFileName, -4);
+ if ($isYml)
+ {
+ $aLang = \spyc_load(\str_replace(array(': >-', ': |-'), array(': >', ': |'), \file_get_contents($sFileName)));
+ if (\is_array($aLang))
+ {
+ \reset($aLang);
+ $sLangKey = key($aLang);
+ if (isset($aLang[$sLangKey]) && is_array($aLang[$sLangKey]))
+ {
+ $aLang = $aLang[$sLangKey];
+ }
+ else
+ {
+ $aLang = null;
+ }
+ }
+ }
+ else
+ {
+ $aLang = \RainLoop\Utils::CustomParseIniFile($sFileName, true);
+ }
+
+ if (\is_array($aLang))
+ {
+ foreach ($aLang as $sKey => $mValue)
+ {
+ if (\is_array($mValue))
+ {
+ foreach ($mValue as $sSecKey => $mSecValue)
+ {
+ $aResultLang[$sKey.'/'.$sSecKey] = $mSecValue;
+ }
+ }
+ else
+ {
+ $aResultLang[$sKey] = $mValue;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @param string $sDir
+ * @param string $sType = ''
+ * @return array
+ */
+ public static function FolderFiles($sDir, $sType = '')
+ {
+ $aResult = array();
+ if (@\is_dir($sDir))
+ {
+ if (false !== ($rDirHandle = @\opendir($sDir)))
+ {
+ while (false !== ($sFile = @\readdir($rDirHandle)))
+ {
+ if (empty($sType) || $sType === \substr($sFile, -\strlen($sType)))
+ {
+ if (\is_file($sDir.'/'.$sFile))
+ {
+ $aResult[] = $sFile;
+ }
+ }
+ }
+
+ @\closedir($rDirHandle);
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sHtml
+ *
+ * @return string
+ */
+ public static function ClearHtmlOutput($sHtml)
+ {
+// return $sHtml;
+ return \str_replace('> <', '><',
+ \preg_replace('/[\s]+ /i', ' ',
+ \preg_replace('/ [\s]+/i', ' ',
+ \preg_replace('/[\r\n\t]+/', ' ',
+ $sHtml
+ ))));
+ }
+
+ /**
+ * @param string $sKey
+ * @return bool
+ */
+ public static function FastCheck($sKey)
+ {
+ $bResult = false;
+
+ $aMatches = array();
+ if (!empty($sKey) && 0 < \strlen($sKey) && \preg_match('/^(RL[\d]+)\-(.+)\-([^\-]+)$/', $sKey, $aMatches) && 3 === \count($aMatches))
+ {
+ $bResult = $aMatches[3] === \strtoupper(\base_convert(\crc32(\md5(
+ $aMatches[1].'-'.$aMatches[2].'-')), 10, 32));
+ }
+
+ return $bResult;
+ }
+
+ /**
+ * @param array $aList
+ * @param string $sDirName
+ * @param string $sNameSuffix = ''
+ */
+ public static function CompileTemplates(&$aList, $sDirName, $sNameSuffix = '')
+ {
+ if (\file_exists($sDirName))
+ {
+ $aFileList = \RainLoop\Utils::FolderFiles($sDirName, '.html');
+
+ foreach ($aFileList as $sName)
+ {
+ $sTemplateName = \substr($sName, 0, -5).$sNameSuffix;
+ $aList[$sTemplateName] = $sDirName.'/'.$sName;
+ }
+ }
+ }
+
+ /**
+ * @param string $sName
+ * @param mixed $mDefault = null
+ * @return mixed
+ */
+ public static function GetCookie($sName, $mDefault = null)
+ {
+ if (null === \RainLoop\Utils::$Cookies)
+ {
+ \RainLoop\Utils::$Cookies = is_array($_COOKIE) ? $_COOKIE : array();
+ }
+
+ return isset(\RainLoop\Utils::$Cookies[$sName]) ? \RainLoop\Utils::$Cookies[$sName] : $mDefault;
+ }
+
+ public static function SetCookie($sName, $sValue = '', $iExpire = 0, $sPath = null, $sDomain = null, $bSecure = null, $bHttpOnly = true)
+ {
+ if (null === \RainLoop\Utils::$Cookies)
+ {
+ \RainLoop\Utils::$Cookies = is_array($_COOKIE) ? $_COOKIE : array();
+ }
+
+ if (null === $sPath)
+ {
+ $sPath = \RainLoop\Utils::$CookieDefaultPath;
+ $sPath = $sPath && 0 < \strlen($sPath) ? $sPath : null;
+ }
+
+ if (null === $bSecure)
+ {
+ $bSecure = \RainLoop\Utils::$CookieDefaultSecure;
+ }
+
+ \RainLoop\Utils::$Cookies[$sName] = $sValue;
+ @\setcookie($sName, $sValue, $iExpire, $sPath, $sDomain, $bSecure, $bHttpOnly);
+ }
+
+ public static function ClearCookie($sName)
+ {
+ if (null === \RainLoop\Utils::$Cookies)
+ {
+ \RainLoop\Utils::$Cookies = is_array($_COOKIE) ? $_COOKIE : array();
+ }
+
+ $sPath = \RainLoop\Utils::$CookieDefaultPath;
+ $sPath = $sPath && 0 < \strlen($sPath) ? $sPath : null;
+
+ unset(\RainLoop\Utils::$Cookies[$sName]);
+ @\setcookie($sName, '', \time() - 3600 * 24 * 30, $sPath);
+ }
+
+ /**
+ * @return bool
+ */
+ public static function IsOwnCloud()
+ {
+ return isset($_ENV['RAINLOOP_OWNCLOUD']) && $_ENV['RAINLOOP_OWNCLOUD'] &&
+ \class_exists('OC');
+ }
+ /**
+ * @return bool
+ */
+ public static function IsOwnCloudLoggedIn()
+ {
+ return self::IsOwnCloud() && \class_exists('OCP\User') && \OCP\User::isLoggedIn();
+ }
+
+ /**
+ * @param string $sV
+ * @param bool $bEncode = false
+ *
+ * @return string
+ */
+ public static function UrlEncode($sV, $bEncode = false)
+ {
+ return $bEncode ? \urlencode($sV) : $sV;
+ }
+
+ /**
+ * @return string
+ */
+ public static function WebPath()
+ {
+ $sAppPath = '';
+ if (\RainLoop\Utils::IsOwnCloud())
+ {
+ if (\class_exists('OC_App'))
+ {
+ $sAppPath = \rtrim(\trim(\OC_App::getAppWebPath('rainloop')), '\\/').'/app/';
+ }
+
+ if (empty($sAppPath))
+ {
+ $sUrl = \MailSo\Base\Http::SingletonInstance()->GetUrl();
+ if ($sUrl && \preg_match('/\/index\.php\/apps\/rainloop/', $sUrl))
+ {
+ $sAppPath = \preg_replace('/\/index\.php\/apps\/rainloop.+$/',
+ '/apps/rainloop/app/', $sUrl);
+ }
+ }
+ }
+
+ return $sAppPath;
+ }
+ /**
+ * @return string
+ */
+ public static function WebVersionPath()
+ {
+ return self::WebPath().'rainloop/v/'.APP_VERSION.'/';
+ }
+
+ /**
+ * @return string
+ */
+ public static function WebStaticPath()
+ {
+ return self::WebVersionPath().'static/';
+ }
+
+ /**
+ * @param array $aSuggestions
+ *
+ * @return array
+ */
+ public static function RemoveSuggestionDuplicates($aSuggestions)
+ {
+ $aResult = array();
+
+ if (is_array($aSuggestions))
+ {
+ $aCache = array();
+ foreach ($aSuggestions as $aItem)
+ {
+ $sLine = \implode('~~', $aItem);
+ if (!isset($aCache[$sLine]))
+ {
+ $aCache[$sLine] = true;
+ $aResult[] = $aItem;
+ }
+ }
+ }
+
+ return $aResult;
+ }
+
+ /**
+ * @param string $sFileName
+ * @param bool $bProcessSections = false
+ *
+ * @return array
+ */
+ public static function CustomParseIniFile($sFileName, $bProcessSections = false)
+ {
+// if (\MailSo\Base\Utils::FunctionExistsAndEnabled('parse_ini_file'))
+// {
+// return @\parse_ini_file($sFileName, !!$bProcessSections);
+// }
+
+ $sData = @\file_get_contents($sFileName);
+ return \is_string($sData) ? @\parse_ini_string($sData, !!$bProcessSections) : null;
+ }
+
+ public static function CustomBaseConvert($sNumberInput, $sFromBaseInput = '0123456789', $sToBaseInput = '0123456789')
+ {
+ if ($sFromBaseInput === $sToBaseInput)
+ {
+ return $sNumberInput;
+ }
+
+ $mFromBase = \str_split($sFromBaseInput, 1);
+ $mToBase = \str_split($sToBaseInput, 1);
+ $aNumber = \str_split($sNumberInput, 1);
+ $iFromLen = \strlen($sFromBaseInput);
+ $iToLen = \strlen($sToBaseInput);
+ $numberLen = \strlen($sNumberInput);
+ $mRetVal = '';
+
+ if ($sToBaseInput === '0123456789')
+ {
+ $mRetVal = 0;
+ for ($iIndex = 1; $iIndex <= $numberLen; $iIndex++)
+ {
+ $mRetVal = \bcadd($mRetVal, \bcmul(\array_search($aNumber[$iIndex - 1], $mFromBase), \bcpow($iFromLen, $numberLen - $iIndex)));
+ }
+
+ return $mRetVal;
+ }
+
+ if ($sFromBaseInput != '0123456789')
+ {
+ $sBase10 = \RainLoop\Utils::CustomBaseConvert($sNumberInput, $sFromBaseInput, '0123456789');
+ }
+ else
+ {
+ $sBase10 = $sNumberInput;
+ }
+
+ if ($sBase10 < \strlen($sToBaseInput))
+ {
+ return $mToBase[$sBase10];
+ }
+
+ while ($sBase10 !== '0')
+ {
+ $mRetVal = $mToBase[\bcmod($sBase10, $iToLen)].$mRetVal;
+ $sBase10 = \bcdiv($sBase10, $iToLen, 0);
+ }
+
+ return $mRetVal;
+ }
+}
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Backend/AbstractBackend.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Backend/AbstractBackend.php
new file mode 100644
index 0000000..eab6440
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Backend/AbstractBackend.php
@@ -0,0 +1,155 @@
+ array(
+ * '{DAV:}displayname' => null,
+ * ),
+ * 424 => array(
+ * '{DAV:}owner' => null,
+ * )
+ * )
+ *
+ * In this example it was forbidden to update {DAV:}displayname.
+ * (403 Forbidden), which in turn also caused {DAV:}owner to fail
+ * (424 Failed Dependency) because the request needs to be atomic.
+ *
+ * @param mixed $calendarId
+ * @param array $mutations
+ * @return bool|array
+ */
+ public function updateCalendar($calendarId, array $mutations) {
+
+ return false;
+
+ }
+
+ /**
+ * Performs a calendar-query on the contents of this calendar.
+ *
+ * The calendar-query is defined in RFC4791 : CalDAV. Using the
+ * calendar-query it is possible for a client to request a specific set of
+ * object, based on contents of iCalendar properties, date-ranges and
+ * iCalendar component types (VTODO, VEVENT).
+ *
+ * This method should just return a list of (relative) urls that match this
+ * query.
+ *
+ * The list of filters are specified as an array. The exact array is
+ * documented by \SabreForRainLoop\CalDAV\CalendarQueryParser.
+ *
+ * Note that it is extremely likely that getCalendarObject for every path
+ * returned from this method will be called almost immediately after. You
+ * may want to anticipate this to speed up these requests.
+ *
+ * This method provides a default implementation, which parses *all* the
+ * iCalendar objects in the specified calendar.
+ *
+ * This default may well be good enough for personal use, and calendars
+ * that aren't very large. But if you anticipate high usage, big calendars
+ * or high loads, you are strongly adviced to optimize certain paths.
+ *
+ * The best way to do so is override this method and to optimize
+ * specifically for 'common filters'.
+ *
+ * Requests that are extremely common are:
+ * * requests for just VEVENTS
+ * * requests for just VTODO
+ * * requests with a time-range-filter on either VEVENT or VTODO.
+ *
+ * ..and combinations of these requests. It may not be worth it to try to
+ * handle every possible situation and just rely on the (relatively
+ * easy to use) CalendarQueryValidator to handle the rest.
+ *
+ * Note that especially time-range-filters may be difficult to parse. A
+ * time-range filter specified on a VEVENT must for instance also handle
+ * recurrence rules correctly.
+ * A good example of how to interprete all these filters can also simply
+ * be found in \SabreForRainLoop\CalDAV\CalendarQueryFilter. This class is as correct
+ * as possible, so it gives you a good idea on what type of stuff you need
+ * to think of.
+ *
+ * @param mixed $calendarId
+ * @param array $filters
+ * @return array
+ */
+ public function calendarQuery($calendarId, array $filters) {
+
+ $result = array();
+ $objects = $this->getCalendarObjects($calendarId);
+
+ $validator = new \SabreForRainLoop\CalDAV\CalendarQueryValidator();
+
+ foreach($objects as $object) {
+
+ if ($this->validateFilterForObject($object, $filters)) {
+ $result[] = $object['uri'];
+ }
+
+ }
+
+ return $result;
+
+ }
+
+ /**
+ * This method validates if a filters (as passed to calendarQuery) matches
+ * the given object.
+ *
+ * @param array $object
+ * @param array $filters
+ * @return bool
+ */
+ protected function validateFilterForObject(array $object, array $filters) {
+
+ // Unfortunately, setting the 'calendardata' here is optional. If
+ // it was excluded, we actually need another call to get this as
+ // well.
+ if (!isset($object['calendardata'])) {
+ $object = $this->getCalendarObject($object['calendarid'], $object['uri']);
+ }
+
+ $data = is_resource($object['calendardata'])?stream_get_contents($object['calendardata']):$object['calendardata'];
+ $vObject = VObject\Reader::read($data);
+
+ $validator = new CalDAV\CalendarQueryValidator();
+ return $validator->validate($vObject, $filters);
+
+ }
+
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Backend/BackendInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Backend/BackendInterface.php
new file mode 100644
index 0000000..ddfe5d8
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Backend/BackendInterface.php
@@ -0,0 +1,233 @@
+ array(
+ * '{DAV:}displayname' => null,
+ * ),
+ * 424 => array(
+ * '{DAV:}owner' => null,
+ * )
+ * )
+ *
+ * In this example it was forbidden to update {DAV:}displayname.
+ * (403 Forbidden), which in turn also caused {DAV:}owner to fail
+ * (424 Failed Dependency) because the request needs to be atomic.
+ *
+ * @param mixed $calendarId
+ * @param array $mutations
+ * @return bool|array
+ */
+ public function updateCalendar($calendarId, array $mutations);
+
+ /**
+ * Delete a calendar and all it's objects
+ *
+ * @param mixed $calendarId
+ * @return void
+ */
+ public function deleteCalendar($calendarId);
+
+ /**
+ * Returns all calendar objects within a calendar.
+ *
+ * Every item contains an array with the following keys:
+ * * id - unique identifier which will be used for subsequent updates
+ * * calendardata - The iCalendar-compatible calendar data
+ * * uri - a unique key which will be used to construct the uri. This can be any arbitrary string.
+ * * lastmodified - a timestamp of the last modification time
+ * * etag - An arbitrary string, surrounded by double-quotes. (e.g.:
+ * ' "abcdef"')
+ * * calendarid - The calendarid as it was passed to this function.
+ * * size - The size of the calendar objects, in bytes.
+ *
+ * Note that the etag is optional, but it's highly encouraged to return for
+ * speed reasons.
+ *
+ * The calendardata is also optional. If it's not returned
+ * 'getCalendarObject' will be called later, which *is* expected to return
+ * calendardata.
+ *
+ * If neither etag or size are specified, the calendardata will be
+ * used/fetched to determine these numbers. If both are specified the
+ * amount of times this is needed is reduced by a great degree.
+ *
+ * @param mixed $calendarId
+ * @return array
+ */
+ public function getCalendarObjects($calendarId);
+
+ /**
+ * Returns information from a single calendar object, based on it's object
+ * uri.
+ *
+ * The returned array must have the same keys as getCalendarObjects. The
+ * 'calendardata' object is required here though, while it's not required
+ * for getCalendarObjects.
+ *
+ * This method must return null if the object did not exist.
+ *
+ * @param mixed $calendarId
+ * @param string $objectUri
+ * @return array|null
+ */
+ public function getCalendarObject($calendarId,$objectUri);
+
+ /**
+ * Creates a new calendar object.
+ *
+ * It is possible return an etag from this function, which will be used in
+ * the response to this PUT request. Note that the ETag must be surrounded
+ * by double-quotes.
+ *
+ * However, you should only really return this ETag if you don't mangle the
+ * calendar-data. If the result of a subsequent GET to this object is not
+ * the exact same as this request body, you should omit the ETag.
+ *
+ * @param mixed $calendarId
+ * @param string $objectUri
+ * @param string $calendarData
+ * @return string|null
+ */
+ public function createCalendarObject($calendarId,$objectUri,$calendarData);
+
+ /**
+ * Updates an existing calendarobject, based on it's uri.
+ *
+ * It is possible return an etag from this function, which will be used in
+ * the response to this PUT request. Note that the ETag must be surrounded
+ * by double-quotes.
+ *
+ * However, you should only really return this ETag if you don't mangle the
+ * calendar-data. If the result of a subsequent GET to this object is not
+ * the exact same as this request body, you should omit the ETag.
+ *
+ * @param mixed $calendarId
+ * @param string $objectUri
+ * @param string $calendarData
+ * @return string|null
+ */
+ public function updateCalendarObject($calendarId,$objectUri,$calendarData);
+
+ /**
+ * Deletes an existing calendar object.
+ *
+ * @param mixed $calendarId
+ * @param string $objectUri
+ * @return void
+ */
+ public function deleteCalendarObject($calendarId,$objectUri);
+
+ /**
+ * Performs a calendar-query on the contents of this calendar.
+ *
+ * The calendar-query is defined in RFC4791 : CalDAV. Using the
+ * calendar-query it is possible for a client to request a specific set of
+ * object, based on contents of iCalendar properties, date-ranges and
+ * iCalendar component types (VTODO, VEVENT).
+ *
+ * This method should just return a list of (relative) urls that match this
+ * query.
+ *
+ * The list of filters are specified as an array. The exact array is
+ * documented by SabreForRainLoop\CalDAV\CalendarQueryParser.
+ *
+ * Note that it is extremely likely that getCalendarObject for every path
+ * returned from this method will be called almost immediately after. You
+ * may want to anticipate this to speed up these requests.
+ *
+ * This method provides a default implementation, which parses *all* the
+ * iCalendar objects in the specified calendar.
+ *
+ * This default may well be good enough for personal use, and calendars
+ * that aren't very large. But if you anticipate high usage, big calendars
+ * or high loads, you are strongly adviced to optimize certain paths.
+ *
+ * The best way to do so is override this method and to optimize
+ * specifically for 'common filters'.
+ *
+ * Requests that are extremely common are:
+ * * requests for just VEVENTS
+ * * requests for just VTODO
+ * * requests with a time-range-filter on either VEVENT or VTODO.
+ *
+ * ..and combinations of these requests. It may not be worth it to try to
+ * handle every possible situation and just rely on the (relatively
+ * easy to use) CalendarQueryValidator to handle the rest.
+ *
+ * Note that especially time-range-filters may be difficult to parse. A
+ * time-range filter specified on a VEVENT must for instance also handle
+ * recurrence rules correctly.
+ * A good example of how to interprete all these filters can also simply
+ * be found in SabreForRainLoop\CalDAV\CalendarQueryFilter. This class is as correct
+ * as possible, so it gives you a good idea on what type of stuff you need
+ * to think of.
+ *
+ * @param mixed $calendarId
+ * @param array $filters
+ * @return array
+ */
+ public function calendarQuery($calendarId, array $filters);
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Backend/NotificationSupport.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Backend/NotificationSupport.php
new file mode 100644
index 0000000..9ae43c8
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Backend/NotificationSupport.php
@@ -0,0 +1,47 @@
+ 'displayname',
+ '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'description',
+ '{urn:ietf:params:xml:ns:caldav}calendar-timezone' => 'timezone',
+ '{http://apple.com/ns/ical/}calendar-order' => 'calendarorder',
+ '{http://apple.com/ns/ical/}calendar-color' => 'calendarcolor',
+ );
+
+ /**
+ * Creates the backend
+ *
+ * @param \PDO $pdo
+ * @param string $calendarTableName
+ * @param string $calendarObjectTableName
+ */
+ public function __construct(\PDO $pdo, $calendarTableName = 'calendars', $calendarObjectTableName = 'calendarobjects') {
+
+ $this->pdo = $pdo;
+ $this->calendarTableName = $calendarTableName;
+ $this->calendarObjectTableName = $calendarObjectTableName;
+
+ }
+
+ /**
+ * Returns a list of calendars for a principal.
+ *
+ * Every project is an array with the following keys:
+ * * id, a unique id that will be used by other functions to modify the
+ * calendar. This can be the same as the uri or a database key.
+ * * uri, which the basename of the uri with which the calendar is
+ * accessed.
+ * * principaluri. The owner of the calendar. Almost always the same as
+ * principalUri passed to this method.
+ *
+ * Furthermore it can contain webdav properties in clark notation. A very
+ * common one is '{DAV:}displayname'.
+ *
+ * @param string $principalUri
+ * @return array
+ */
+ public function getCalendarsForUser($principalUri) {
+
+ $fields = array_values($this->propertyMap);
+ $fields[] = 'id';
+ $fields[] = 'uri';
+ $fields[] = 'ctag';
+ $fields[] = 'components';
+ $fields[] = 'principaluri';
+ $fields[] = 'transparent';
+
+ // Making fields a comma-delimited list
+ $fields = implode(', ', $fields);
+ $stmt = $this->pdo->prepare("SELECT " . $fields . " FROM ".$this->calendarTableName." WHERE principaluri = ? ORDER BY calendarorder ASC");
+ $stmt->execute(array($principalUri));
+
+ $calendars = array();
+ while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+
+ $components = array();
+ if ($row['components']) {
+ $components = explode(',',$row['components']);
+ }
+
+ $calendar = array(
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'principaluri' => $row['principaluri'],
+ '{' . CalDAV\Plugin::NS_CALENDARSERVER . '}getctag' => $row['ctag']?$row['ctag']:'0',
+ '{' . CalDAV\Plugin::NS_CALDAV . '}supported-calendar-component-set' => new CalDAV\Property\SupportedCalendarComponentSet($components),
+ '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp' => new CalDAV\Property\ScheduleCalendarTransp($row['transparent']?'transparent':'opaque'),
+ );
+
+
+ foreach($this->propertyMap as $xmlName=>$dbName) {
+ $calendar[$xmlName] = $row[$dbName];
+ }
+
+ $calendars[] = $calendar;
+
+ }
+
+ return $calendars;
+
+ }
+
+ /**
+ * Creates a new calendar for a principal.
+ *
+ * If the creation was a success, an id must be returned that can be used to reference
+ * this calendar in other methods, such as updateCalendar
+ *
+ * @param string $principalUri
+ * @param string $calendarUri
+ * @param array $properties
+ * @return string
+ */
+ public function createCalendar($principalUri, $calendarUri, array $properties) {
+
+ $fieldNames = array(
+ 'principaluri',
+ 'uri',
+ 'ctag',
+ 'transparent',
+ );
+ $values = array(
+ ':principaluri' => $principalUri,
+ ':uri' => $calendarUri,
+ ':ctag' => 1,
+ ':transparent' => 0,
+ );
+
+ // Default value
+ $sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';
+ $fieldNames[] = 'components';
+ if (!isset($properties[$sccs])) {
+ $values[':components'] = 'VEVENT,VTODO';
+ } else {
+ if (!($properties[$sccs] instanceof CalDAV\Property\SupportedCalendarComponentSet)) {
+ throw new DAV\Exception('The ' . $sccs . ' property must be of type: \SabreForRainLoop\CalDAV\Property\SupportedCalendarComponentSet');
+ }
+ $values[':components'] = implode(',',$properties[$sccs]->getValue());
+ }
+ $transp = '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp';
+ if (isset($properties[$transp])) {
+ $values[':transparent'] = $properties[$transp]->getValue()==='transparent';
+ }
+
+ foreach($this->propertyMap as $xmlName=>$dbName) {
+ if (isset($properties[$xmlName])) {
+
+ $values[':' . $dbName] = $properties[$xmlName];
+ $fieldNames[] = $dbName;
+ }
+ }
+
+ $stmt = $this->pdo->prepare("INSERT INTO ".$this->calendarTableName." (".implode(', ', $fieldNames).") VALUES (".implode(', ',array_keys($values)).")");
+ $stmt->execute($values);
+
+ return $this->pdo->lastInsertId();
+
+ }
+
+ /**
+ * Updates properties for a calendar.
+ *
+ * The mutations array uses the propertyName in clark-notation as key,
+ * and the array value for the property value. In the case a property
+ * should be deleted, the property value will be null.
+ *
+ * This method must be atomic. If one property cannot be changed, the
+ * entire operation must fail.
+ *
+ * If the operation was successful, true can be returned.
+ * If the operation failed, false can be returned.
+ *
+ * Deletion of a non-existent property is always successful.
+ *
+ * Lastly, it is optional to return detailed information about any
+ * failures. In this case an array should be returned with the following
+ * structure:
+ *
+ * array(
+ * 403 => array(
+ * '{DAV:}displayname' => null,
+ * ),
+ * 424 => array(
+ * '{DAV:}owner' => null,
+ * )
+ * )
+ *
+ * In this example it was forbidden to update {DAV:}displayname.
+ * (403 Forbidden), which in turn also caused {DAV:}owner to fail
+ * (424 Failed Dependency) because the request needs to be atomic.
+ *
+ * @param string $calendarId
+ * @param array $mutations
+ * @return bool|array
+ */
+ public function updateCalendar($calendarId, array $mutations) {
+
+ $newValues = array();
+ $result = array(
+ 200 => array(), // Ok
+ 403 => array(), // Forbidden
+ 424 => array(), // Failed Dependency
+ );
+
+ $hasError = false;
+
+ foreach($mutations as $propertyName=>$propertyValue) {
+
+ switch($propertyName) {
+ case '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp' :
+ $fieldName = 'transparent';
+ $newValues[$fieldName] = $propertyValue->getValue()==='transparent';
+ break;
+ default :
+ // Checking the property map
+ if (!isset($this->propertyMap[$propertyName])) {
+ // We don't know about this property.
+ $hasError = true;
+ $result[403][$propertyName] = null;
+ unset($mutations[$propertyName]);
+ continue;
+ }
+
+ $fieldName = $this->propertyMap[$propertyName];
+ $newValues[$fieldName] = $propertyValue;
+ }
+
+ }
+
+ // If there were any errors we need to fail the request
+ if ($hasError) {
+ // Properties has the remaining properties
+ foreach($mutations as $propertyName=>$propertyValue) {
+ $result[424][$propertyName] = null;
+ }
+
+ // Removing unused statuscodes for cleanliness
+ foreach($result as $status=>$properties) {
+ if (is_array($properties) && count($properties)===0) unset($result[$status]);
+ }
+
+ return $result;
+
+ }
+
+ // Success
+
+ // Now we're generating the sql query.
+ $valuesSql = array();
+ foreach($newValues as $fieldName=>$value) {
+ $valuesSql[] = $fieldName . ' = ?';
+ }
+ $valuesSql[] = 'ctag = ctag + 1';
+
+ $stmt = $this->pdo->prepare("UPDATE " . $this->calendarTableName . " SET " . implode(', ',$valuesSql) . " WHERE id = ?");
+ $newValues['id'] = $calendarId;
+ $stmt->execute(array_values($newValues));
+
+ return true;
+
+ }
+
+ /**
+ * Delete a calendar and all it's objects
+ *
+ * @param string $calendarId
+ * @return void
+ */
+ public function deleteCalendar($calendarId) {
+
+ $stmt = $this->pdo->prepare('DELETE FROM '.$this->calendarObjectTableName.' WHERE calendarid = ?');
+ $stmt->execute(array($calendarId));
+
+ $stmt = $this->pdo->prepare('DELETE FROM '.$this->calendarTableName.' WHERE id = ?');
+ $stmt->execute(array($calendarId));
+
+ }
+
+ /**
+ * Returns all calendar objects within a calendar.
+ *
+ * Every item contains an array with the following keys:
+ * * id - unique identifier which will be used for subsequent updates
+ * * calendardata - The iCalendar-compatible calendar data
+ * * uri - a unique key which will be used to construct the uri. This can be any arbitrary string.
+ * * lastmodified - a timestamp of the last modification time
+ * * etag - An arbitrary string, surrounded by double-quotes. (e.g.:
+ * ' "abcdef"')
+ * * calendarid - The calendarid as it was passed to this function.
+ * * size - The size of the calendar objects, in bytes.
+ *
+ * Note that the etag is optional, but it's highly encouraged to return for
+ * speed reasons.
+ *
+ * The calendardata is also optional. If it's not returned
+ * 'getCalendarObject' will be called later, which *is* expected to return
+ * calendardata.
+ *
+ * If neither etag or size are specified, the calendardata will be
+ * used/fetched to determine these numbers. If both are specified the
+ * amount of times this is needed is reduced by a great degree.
+ *
+ * @param string $calendarId
+ * @return array
+ */
+ public function getCalendarObjects($calendarId) {
+
+ $stmt = $this->pdo->prepare('SELECT id, uri, lastmodified, etag, calendarid, size FROM '.$this->calendarObjectTableName.' WHERE calendarid = ?');
+ $stmt->execute(array($calendarId));
+
+ $result = array();
+ foreach($stmt->fetchAll(\PDO::FETCH_ASSOC) as $row) {
+ $result[] = array(
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'lastmodified' => $row['lastmodified'],
+ 'etag' => '"' . $row['etag'] . '"',
+ 'calendarid' => $row['calendarid'],
+ 'size' => (int)$row['size'],
+ );
+ }
+
+ return $result;
+
+ }
+
+ /**
+ * Returns information from a single calendar object, based on it's object
+ * uri.
+ *
+ * The returned array must have the same keys as getCalendarObjects. The
+ * 'calendardata' object is required here though, while it's not required
+ * for getCalendarObjects.
+ *
+ * This method must return null if the object did not exist.
+ *
+ * @param string $calendarId
+ * @param string $objectUri
+ * @return array|null
+ */
+ public function getCalendarObject($calendarId,$objectUri) {
+
+ $stmt = $this->pdo->prepare('SELECT id, uri, lastmodified, etag, calendarid, size, calendardata FROM '.$this->calendarObjectTableName.' WHERE calendarid = ? AND uri = ?');
+ $stmt->execute(array($calendarId, $objectUri));
+ $row = $stmt->fetch(\PDO::FETCH_ASSOC);
+
+ if(!$row) return null;
+
+ return array(
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'lastmodified' => $row['lastmodified'],
+ 'etag' => '"' . $row['etag'] . '"',
+ 'calendarid' => $row['calendarid'],
+ 'size' => (int)$row['size'],
+ 'calendardata' => $row['calendardata'],
+ );
+
+ }
+
+
+ /**
+ * Creates a new calendar object.
+ *
+ * It is possible return an etag from this function, which will be used in
+ * the response to this PUT request. Note that the ETag must be surrounded
+ * by double-quotes.
+ *
+ * However, you should only really return this ETag if you don't mangle the
+ * calendar-data. If the result of a subsequent GET to this object is not
+ * the exact same as this request body, you should omit the ETag.
+ *
+ * @param mixed $calendarId
+ * @param string $objectUri
+ * @param string $calendarData
+ * @return string|null
+ */
+ public function createCalendarObject($calendarId,$objectUri,$calendarData) {
+
+ $extraData = $this->getDenormalizedData($calendarData);
+
+ $stmt = $this->pdo->prepare('INSERT INTO '.$this->calendarObjectTableName.' (calendarid, uri, calendardata, lastmodified, etag, size, componenttype, firstoccurence, lastoccurence) VALUES (?,?,?,?,?,?,?,?,?)');
+ $stmt->execute(array(
+ $calendarId,
+ $objectUri,
+ $calendarData,
+ time(),
+ $extraData['etag'],
+ $extraData['size'],
+ $extraData['componentType'],
+ $extraData['firstOccurence'],
+ $extraData['lastOccurence'],
+ ));
+ $stmt = $this->pdo->prepare('UPDATE '.$this->calendarTableName.' SET ctag = ctag + 1 WHERE id = ?');
+ $stmt->execute(array($calendarId));
+
+ return '"' . $extraData['etag'] . '"';
+
+ }
+
+ /**
+ * Updates an existing calendarobject, based on it's uri.
+ *
+ * It is possible return an etag from this function, which will be used in
+ * the response to this PUT request. Note that the ETag must be surrounded
+ * by double-quotes.
+ *
+ * However, you should only really return this ETag if you don't mangle the
+ * calendar-data. If the result of a subsequent GET to this object is not
+ * the exact same as this request body, you should omit the ETag.
+ *
+ * @param mixed $calendarId
+ * @param string $objectUri
+ * @param string $calendarData
+ * @return string|null
+ */
+ public function updateCalendarObject($calendarId,$objectUri,$calendarData) {
+
+ $extraData = $this->getDenormalizedData($calendarData);
+
+ $stmt = $this->pdo->prepare('UPDATE '.$this->calendarObjectTableName.' SET calendardata = ?, lastmodified = ?, etag = ?, size = ?, componenttype = ?, firstoccurence = ?, lastoccurence = ? WHERE calendarid = ? AND uri = ?');
+ $stmt->execute(array($calendarData,time(), $extraData['etag'], $extraData['size'], $extraData['componentType'], $extraData['firstOccurence'], $extraData['lastOccurence'] ,$calendarId,$objectUri));
+ $stmt = $this->pdo->prepare('UPDATE '.$this->calendarTableName.' SET ctag = ctag + 1 WHERE id = ?');
+ $stmt->execute(array($calendarId));
+
+ return '"' . $extraData['etag'] . '"';
+
+ }
+
+ /**
+ * Parses some information from calendar objects, used for optimized
+ * calendar-queries.
+ *
+ * Returns an array with the following keys:
+ * * etag
+ * * size
+ * * componentType
+ * * firstOccurence
+ * * lastOccurence
+ *
+ * @param string $calendarData
+ * @return array
+ */
+ protected function getDenormalizedData($calendarData) {
+
+ $vObject = VObject\Reader::read($calendarData);
+ $componentType = null;
+ $component = null;
+ $firstOccurence = null;
+ $lastOccurence = null;
+ foreach($vObject->getComponents() as $component) {
+ if ($component->name!=='VTIMEZONE') {
+ $componentType = $component->name;
+ break;
+ }
+ }
+ if (!$componentType) {
+ throw new \SabreForRainLoop\DAV\Exception\BadRequest('Calendar objects must have a VJOURNAL, VEVENT or VTODO component');
+ }
+ if ($componentType === 'VEVENT') {
+ $firstOccurence = $component->DTSTART->getDateTime()->getTimeStamp();
+ // Finding the last occurence is a bit harder
+ if (!isset($component->RRULE)) {
+ if (isset($component->DTEND)) {
+ $lastOccurence = $component->DTEND->getDateTime()->getTimeStamp();
+ } elseif (isset($component->DURATION)) {
+ $endDate = clone $component->DTSTART->getDateTime();
+ $endDate->add(VObject\DateTimeParser::parse($component->DURATION->getValue()));
+ $lastOccurence = $endDate->getTimeStamp();
+ } elseif (!$component->DTSTART->hasTime()) {
+ $endDate = clone $component->DTSTART->getDateTime();
+ $endDate->modify('+1 day');
+ $lastOccurence = $endDate->getTimeStamp();
+ } else {
+ $lastOccurence = $firstOccurence;
+ }
+ } else {
+ $it = new VObject\RecurrenceIterator($vObject, (string)$component->UID);
+ $maxDate = new \DateTime(self::MAX_DATE);
+ if ($it->isInfinite()) {
+ $lastOccurence = $maxDate->getTimeStamp();
+ } else {
+ $end = $it->getDtEnd();
+ while($it->valid() && $end < $maxDate) {
+ $end = $it->getDtEnd();
+ $it->next();
+
+ }
+ $lastOccurence = $end->getTimeStamp();
+ }
+
+ }
+ }
+
+ return array(
+ 'etag' => md5($calendarData),
+ 'size' => strlen($calendarData),
+ 'componentType' => $componentType,
+ 'firstOccurence' => $firstOccurence,
+ 'lastOccurence' => $lastOccurence,
+ );
+
+ }
+
+ /**
+ * Deletes an existing calendar object.
+ *
+ * @param string $calendarId
+ * @param string $objectUri
+ * @return void
+ */
+ public function deleteCalendarObject($calendarId,$objectUri) {
+
+ $stmt = $this->pdo->prepare('DELETE FROM '.$this->calendarObjectTableName.' WHERE calendarid = ? AND uri = ?');
+ $stmt->execute(array($calendarId,$objectUri));
+ $stmt = $this->pdo->prepare('UPDATE '. $this->calendarTableName .' SET ctag = ctag + 1 WHERE id = ?');
+ $stmt->execute(array($calendarId));
+
+ }
+
+ /**
+ * Performs a calendar-query on the contents of this calendar.
+ *
+ * The calendar-query is defined in RFC4791 : CalDAV. Using the
+ * calendar-query it is possible for a client to request a specific set of
+ * object, based on contents of iCalendar properties, date-ranges and
+ * iCalendar component types (VTODO, VEVENT).
+ *
+ * This method should just return a list of (relative) urls that match this
+ * query.
+ *
+ * The list of filters are specified as an array. The exact array is
+ * documented by \SabreForRainLoop\CalDAV\CalendarQueryParser.
+ *
+ * Note that it is extremely likely that getCalendarObject for every path
+ * returned from this method will be called almost immediately after. You
+ * may want to anticipate this to speed up these requests.
+ *
+ * This method provides a default implementation, which parses *all* the
+ * iCalendar objects in the specified calendar.
+ *
+ * This default may well be good enough for personal use, and calendars
+ * that aren't very large. But if you anticipate high usage, big calendars
+ * or high loads, you are strongly adviced to optimize certain paths.
+ *
+ * The best way to do so is override this method and to optimize
+ * specifically for 'common filters'.
+ *
+ * Requests that are extremely common are:
+ * * requests for just VEVENTS
+ * * requests for just VTODO
+ * * requests with a time-range-filter on a VEVENT.
+ *
+ * ..and combinations of these requests. It may not be worth it to try to
+ * handle every possible situation and just rely on the (relatively
+ * easy to use) CalendarQueryValidator to handle the rest.
+ *
+ * Note that especially time-range-filters may be difficult to parse. A
+ * time-range filter specified on a VEVENT must for instance also handle
+ * recurrence rules correctly.
+ * A good example of how to interprete all these filters can also simply
+ * be found in \SabreForRainLoop\CalDAV\CalendarQueryFilter. This class is as correct
+ * as possible, so it gives you a good idea on what type of stuff you need
+ * to think of.
+ *
+ * This specific implementation (for the PDO) backend optimizes filters on
+ * specific components, and VEVENT time-ranges.
+ *
+ * @param string $calendarId
+ * @param array $filters
+ * @return array
+ */
+ public function calendarQuery($calendarId, array $filters) {
+
+ $result = array();
+ $validator = new \SabreForRainLoop\CalDAV\CalendarQueryValidator();
+
+ $componentType = null;
+ $requirePostFilter = true;
+ $timeRange = null;
+
+ // if no filters were specified, we don't need to filter after a query
+ if (!$filters['prop-filters'] && !$filters['comp-filters']) {
+ $requirePostFilter = false;
+ }
+
+ // Figuring out if there's a component filter
+ if (count($filters['comp-filters']) > 0 && !$filters['comp-filters'][0]['is-not-defined']) {
+ $componentType = $filters['comp-filters'][0]['name'];
+
+ // Checking if we need post-filters
+ if (!$filters['prop-filters'] && !$filters['comp-filters'][0]['comp-filters'] && !$filters['comp-filters'][0]['time-range'] && !$filters['comp-filters'][0]['prop-filters']) {
+ $requirePostFilter = false;
+ }
+ // There was a time-range filter
+ if ($componentType == 'VEVENT' && isset($filters['comp-filters'][0]['time-range'])) {
+ $timeRange = $filters['comp-filters'][0]['time-range'];
+
+ // If start time OR the end time is not specified, we can do a
+ // 100% accurate mysql query.
+ if (!$filters['prop-filters'] && !$filters['comp-filters'][0]['comp-filters'] && !$filters['comp-filters'][0]['prop-filters'] && (!$timeRange['start'] || !$timeRange['end'])) {
+ $requirePostFilter = false;
+ }
+ }
+
+ }
+
+ if ($requirePostFilter) {
+ $query = "SELECT uri, calendardata FROM ".$this->calendarObjectTableName." WHERE calendarid = :calendarid";
+ } else {
+ $query = "SELECT uri FROM ".$this->calendarObjectTableName." WHERE calendarid = :calendarid";
+ }
+
+ $values = array(
+ 'calendarid' => $calendarId,
+ );
+
+ if ($componentType) {
+ $query.=" AND componenttype = :componenttype";
+ $values['componenttype'] = $componentType;
+ }
+
+ if ($timeRange && $timeRange['start']) {
+ $query.=" AND lastoccurence > :startdate";
+ $values['startdate'] = $timeRange['start']->getTimeStamp();
+ }
+ if ($timeRange && $timeRange['end']) {
+ $query.=" AND firstoccurence < :enddate";
+ $values['enddate'] = $timeRange['end']->getTimeStamp();
+ }
+
+ $stmt = $this->pdo->prepare($query);
+ $stmt->execute($values);
+
+ $result = array();
+ while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+ if ($requirePostFilter) {
+ if (!$this->validateFilterForObject($row, $filters)) {
+ continue;
+ }
+ }
+ $result[] = $row['uri'];
+
+ }
+
+ return $result;
+
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Backend/SharingSupport.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Backend/SharingSupport.php
new file mode 100644
index 0000000..3bfcc14
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Backend/SharingSupport.php
@@ -0,0 +1,243 @@
+caldavBackend = $caldavBackend;
+ $this->calendarInfo = $calendarInfo;
+
+ }
+
+ /**
+ * Returns the name of the calendar
+ *
+ * @return string
+ */
+ public function getName() {
+
+ return $this->calendarInfo['uri'];
+
+ }
+
+ /**
+ * Updates properties such as the display name and description
+ *
+ * @param array $mutations
+ * @return array
+ */
+ public function updateProperties($mutations) {
+
+ return $this->caldavBackend->updateCalendar($this->calendarInfo['id'],$mutations);
+
+ }
+
+ /**
+ * Returns the list of properties
+ *
+ * @param array $requestedProperties
+ * @return array
+ */
+ public function getProperties($requestedProperties) {
+
+ $response = array();
+
+ foreach($requestedProperties as $prop) switch($prop) {
+
+ case '{urn:ietf:params:xml:ns:caldav}supported-calendar-data' :
+ $response[$prop] = new Property\SupportedCalendarData();
+ break;
+ case '{urn:ietf:params:xml:ns:caldav}supported-collation-set' :
+ $response[$prop] = new Property\SupportedCollationSet();
+ break;
+ case '{DAV:}owner' :
+ $response[$prop] = new DAVACL\Property\Principal(DAVACL\Property\Principal::HREF,$this->calendarInfo['principaluri']);
+ break;
+ default :
+ if (isset($this->calendarInfo[$prop])) $response[$prop] = $this->calendarInfo[$prop];
+ break;
+
+ }
+ return $response;
+
+ }
+
+ /**
+ * Returns a calendar object
+ *
+ * The contained calendar objects are for example Events or Todo's.
+ *
+ * @param string $name
+ * @return \SabreForRainLoop\CalDAV\ICalendarObject
+ */
+ public function getChild($name) {
+
+ $obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'],$name);
+
+ if (!$obj) throw new DAV\Exception\NotFound('Calendar object not found');
+
+ $obj['acl'] = $this->getACL();
+ // Removing the irrelivant
+ foreach($obj['acl'] as $key=>$acl) {
+ if ($acl['privilege'] === '{' . Plugin::NS_CALDAV . '}read-free-busy') {
+ unset($obj['acl'][$key]);
+ }
+ }
+
+ return new CalendarObject($this->caldavBackend,$this->calendarInfo,$obj);
+
+ }
+
+ /**
+ * Returns the full list of calendar objects
+ *
+ * @return array
+ */
+ public function getChildren() {
+
+ $objs = $this->caldavBackend->getCalendarObjects($this->calendarInfo['id']);
+ $children = array();
+ foreach($objs as $obj) {
+ $obj['acl'] = $this->getACL();
+ // Removing the irrelivant
+ foreach($obj['acl'] as $key=>$acl) {
+ if ($acl['privilege'] === '{' . Plugin::NS_CALDAV . '}read-free-busy') {
+ unset($obj['acl'][$key]);
+ }
+ }
+ $children[] = new CalendarObject($this->caldavBackend,$this->calendarInfo,$obj);
+ }
+ return $children;
+
+ }
+
+ /**
+ * Checks if a child-node exists.
+ *
+ * @param string $name
+ * @return bool
+ */
+ public function childExists($name) {
+
+ $obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'],$name);
+ if (!$obj)
+ return false;
+ else
+ return true;
+
+ }
+
+ /**
+ * Creates a new directory
+ *
+ * We actually block this, as subdirectories are not allowed in calendars.
+ *
+ * @param string $name
+ * @return void
+ */
+ public function createDirectory($name) {
+
+ throw new DAV\Exception\MethodNotAllowed('Creating collections in calendar objects is not allowed');
+
+ }
+
+ /**
+ * Creates a new file
+ *
+ * The contents of the new file must be a valid ICalendar string.
+ *
+ * @param string $name
+ * @param resource $calendarData
+ * @return string|null
+ */
+ public function createFile($name,$calendarData = null) {
+
+ if (is_resource($calendarData)) {
+ $calendarData = stream_get_contents($calendarData);
+ }
+ return $this->caldavBackend->createCalendarObject($this->calendarInfo['id'],$name,$calendarData);
+
+ }
+
+ /**
+ * Deletes the calendar.
+ *
+ * @return void
+ */
+ public function delete() {
+
+ $this->caldavBackend->deleteCalendar($this->calendarInfo['id']);
+
+ }
+
+ /**
+ * Renames the calendar. Note that most calendars use the
+ * {DAV:}displayname to display a name to display a name.
+ *
+ * @param string $newName
+ * @return void
+ */
+ public function setName($newName) {
+
+ throw new DAV\Exception\MethodNotAllowed('Renaming calendars is not yet supported');
+
+ }
+
+ /**
+ * Returns the last modification date as a unix timestamp.
+ *
+ * @return void
+ */
+ public function getLastModified() {
+
+ return null;
+
+ }
+
+ /**
+ * Returns the owner principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getOwner() {
+
+ return $this->calendarInfo['principaluri'];
+
+ }
+
+ /**
+ * Returns a group principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getGroup() {
+
+ return null;
+
+ }
+
+ /**
+ * Returns a list of ACE's for this node.
+ *
+ * Each ACE has the following properties:
+ * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
+ * currently the only supported privileges
+ * * 'principal', a url to the principal who owns the node
+ * * 'protected' (optional), indicating that this ACE is not allowed to
+ * be updated.
+ *
+ * @return array
+ */
+ public function getACL() {
+
+ return array(
+ array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->getOwner(),
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}write',
+ 'principal' => $this->getOwner(),
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->getOwner() . '/calendar-proxy-write',
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}write',
+ 'principal' => $this->getOwner() . '/calendar-proxy-write',
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->getOwner() . '/calendar-proxy-read',
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{' . Plugin::NS_CALDAV . '}read-free-busy',
+ 'principal' => '{DAV:}authenticated',
+ 'protected' => true,
+ ),
+
+ );
+
+ }
+
+ /**
+ * Updates the ACL
+ *
+ * This method will receive a list of new ACE's.
+ *
+ * @param array $acl
+ * @return void
+ */
+ public function setACL(array $acl) {
+
+ throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported');
+
+ }
+
+ /**
+ * Returns the list of supported privileges for this node.
+ *
+ * The returned data structure is a list of nested privileges.
+ * See \SabreForRainLoop\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
+ * standard structure.
+ *
+ * If null is returned from this method, the default privilege set is used,
+ * which is fine for most common usecases.
+ *
+ * @return array|null
+ */
+ public function getSupportedPrivilegeSet() {
+
+ $default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet();
+
+ // We need to inject 'read-free-busy' in the tree, aggregated under
+ // {DAV:}read.
+ foreach($default['aggregates'] as &$agg) {
+
+ if ($agg['privilege'] !== '{DAV:}read') continue;
+
+ $agg['aggregates'][] = array(
+ 'privilege' => '{' . Plugin::NS_CALDAV . '}read-free-busy',
+ );
+
+ }
+ return $default;
+
+ }
+
+ /**
+ * Performs a calendar-query on the contents of this calendar.
+ *
+ * The calendar-query is defined in RFC4791 : CalDAV. Using the
+ * calendar-query it is possible for a client to request a specific set of
+ * object, based on contents of iCalendar properties, date-ranges and
+ * iCalendar component types (VTODO, VEVENT).
+ *
+ * This method should just return a list of (relative) urls that match this
+ * query.
+ *
+ * The list of filters are specified as an array. The exact array is
+ * documented by SabreForRainLoop\CalDAV\CalendarQueryParser.
+ *
+ * @param array $filters
+ * @return array
+ */
+ public function calendarQuery(array $filters) {
+
+ return $this->caldavBackend->calendarQuery($this->calendarInfo['id'], $filters);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/CalendarObject.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/CalendarObject.php
new file mode 100644
index 0000000..9f6b498
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/CalendarObject.php
@@ -0,0 +1,279 @@
+caldavBackend = $caldavBackend;
+
+ if (!isset($objectData['calendarid'])) {
+ throw new \InvalidArgumentException('The objectData argument must contain a \'calendarid\' property');
+ }
+ if (!isset($objectData['uri'])) {
+ throw new \InvalidArgumentException('The objectData argument must contain an \'uri\' property');
+ }
+
+ $this->calendarInfo = $calendarInfo;
+ $this->objectData = $objectData;
+
+ }
+
+ /**
+ * Returns the uri for this object
+ *
+ * @return string
+ */
+ public function getName() {
+
+ return $this->objectData['uri'];
+
+ }
+
+ /**
+ * Returns the ICalendar-formatted object
+ *
+ * @return string
+ */
+ public function get() {
+
+ // Pre-populating the 'calendardata' is optional, if we don't have it
+ // already we fetch it from the backend.
+ if (!isset($this->objectData['calendardata'])) {
+ $this->objectData = $this->caldavBackend->getCalendarObject($this->objectData['calendarid'], $this->objectData['uri']);
+ }
+ return $this->objectData['calendardata'];
+
+ }
+
+ /**
+ * Updates the ICalendar-formatted object
+ *
+ * @param string|resource $calendarData
+ * @return string
+ */
+ public function put($calendarData) {
+
+ if (is_resource($calendarData)) {
+ $calendarData = stream_get_contents($calendarData);
+ }
+ $etag = $this->caldavBackend->updateCalendarObject($this->calendarInfo['id'],$this->objectData['uri'],$calendarData);
+ $this->objectData['calendardata'] = $calendarData;
+ $this->objectData['etag'] = $etag;
+
+ return $etag;
+
+ }
+
+ /**
+ * Deletes the calendar object
+ *
+ * @return void
+ */
+ public function delete() {
+
+ $this->caldavBackend->deleteCalendarObject($this->calendarInfo['id'],$this->objectData['uri']);
+
+ }
+
+ /**
+ * Returns the mime content-type
+ *
+ * @return string
+ */
+ public function getContentType() {
+
+ return 'text/calendar; charset=utf-8';
+
+ }
+
+ /**
+ * Returns an ETag for this object.
+ *
+ * The ETag is an arbitrary string, but MUST be surrounded by double-quotes.
+ *
+ * @return string
+ */
+ public function getETag() {
+
+ if (isset($this->objectData['etag'])) {
+ return $this->objectData['etag'];
+ } else {
+ return '"' . md5($this->get()). '"';
+ }
+
+ }
+
+ /**
+ * Returns the last modification date as a unix timestamp
+ *
+ * @return int
+ */
+ public function getLastModified() {
+
+ return $this->objectData['lastmodified'];
+
+ }
+
+ /**
+ * Returns the size of this object in bytes
+ *
+ * @return int
+ */
+ public function getSize() {
+
+ if (array_key_exists('size',$this->objectData)) {
+ return $this->objectData['size'];
+ } else {
+ return strlen($this->get());
+ }
+
+ }
+
+ /**
+ * Returns the owner principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getOwner() {
+
+ return $this->calendarInfo['principaluri'];
+
+ }
+
+ /**
+ * Returns a group principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getGroup() {
+
+ return null;
+
+ }
+
+ /**
+ * Returns a list of ACE's for this node.
+ *
+ * Each ACE has the following properties:
+ * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
+ * currently the only supported privileges
+ * * 'principal', a url to the principal who owns the node
+ * * 'protected' (optional), indicating that this ACE is not allowed to
+ * be updated.
+ *
+ * @return array
+ */
+ public function getACL() {
+
+ // An alternative acl may be specified in the object data.
+ if (isset($this->objectData['acl'])) {
+ return $this->objectData['acl'];
+ }
+
+ // The default ACL
+ return array(
+ array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->calendarInfo['principaluri'],
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}write',
+ 'principal' => $this->calendarInfo['principaluri'],
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}write',
+ 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-read',
+ 'protected' => true,
+ ),
+
+ );
+
+ }
+
+ /**
+ * Updates the ACL
+ *
+ * This method will receive a list of new ACE's.
+ *
+ * @param array $acl
+ * @return void
+ */
+ public function setACL(array $acl) {
+
+ throw new \SabreForRainLoop\DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported');
+
+ }
+
+ /**
+ * Returns the list of supported privileges for this node.
+ *
+ * The returned data structure is a list of nested privileges.
+ * See \SabreForRainLoop\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
+ * standard structure.
+ *
+ * If null is returned from this method, the default privilege set is used,
+ * which is fine for most common usecases.
+ *
+ * @return array|null
+ */
+ public function getSupportedPrivilegeSet() {
+
+ return null;
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryParser.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryParser.php
new file mode 100644
index 0000000..8a3aec7
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryParser.php
@@ -0,0 +1,298 @@
+dom = $dom;
+ $this->xpath = new \DOMXPath($dom);
+ $this->xpath->registerNameSpace('cal',Plugin::NS_CALDAV);
+ $this->xpath->registerNameSpace('dav','urn:DAV');
+
+ }
+
+ /**
+ * Parses the request.
+ *
+ * @return void
+ */
+ public function parse() {
+
+ $filterNode = null;
+
+ $filter = $this->xpath->query('/cal:calendar-query/cal:filter');
+ if ($filter->length !== 1) {
+ throw new \SabreForRainLoop\DAV\Exception\BadRequest('Only one filter element is allowed');
+ }
+
+ $compFilters = $this->parseCompFilters($filter->item(0));
+ if (count($compFilters)!==1) {
+ throw new \SabreForRainLoop\DAV\Exception\BadRequest('There must be exactly 1 top-level comp-filter.');
+ }
+
+ $this->filters = $compFilters[0];
+ $this->requestedProperties = array_keys(\SabreForRainLoop\DAV\XMLUtil::parseProperties($this->dom->firstChild));
+
+ $expand = $this->xpath->query('/cal:calendar-query/dav:prop/cal:calendar-data/cal:expand');
+ if ($expand->length>0) {
+ $this->expand = $this->parseExpand($expand->item(0));
+ }
+
+
+ }
+
+ /**
+ * Parses all the 'comp-filter' elements from a node
+ *
+ * @param \DOMElement $parentNode
+ * @return array
+ */
+ protected function parseCompFilters(\DOMElement $parentNode) {
+
+ $compFilterNodes = $this->xpath->query('cal:comp-filter', $parentNode);
+ $result = array();
+
+ for($ii=0; $ii < $compFilterNodes->length; $ii++) {
+
+ $compFilterNode = $compFilterNodes->item($ii);
+
+ $compFilter = array();
+ $compFilter['name'] = $compFilterNode->getAttribute('name');
+ $compFilter['is-not-defined'] = $this->xpath->query('cal:is-not-defined', $compFilterNode)->length>0;
+ $compFilter['comp-filters'] = $this->parseCompFilters($compFilterNode);
+ $compFilter['prop-filters'] = $this->parsePropFilters($compFilterNode);
+ $compFilter['time-range'] = $this->parseTimeRange($compFilterNode);
+
+ if ($compFilter['time-range'] && !in_array($compFilter['name'],array(
+ 'VEVENT',
+ 'VTODO',
+ 'VJOURNAL',
+ 'VFREEBUSY',
+ 'VALARM',
+ ))) {
+ throw new \SabreForRainLoop\DAV\Exception\BadRequest('The time-range filter is not defined for the ' . $compFilter['name'] . ' component');
+ };
+
+ $result[] = $compFilter;
+
+ }
+
+ return $result;
+
+ }
+
+ /**
+ * Parses all the prop-filter elements from a node
+ *
+ * @param \DOMElement $parentNode
+ * @return array
+ */
+ protected function parsePropFilters(\DOMElement $parentNode) {
+
+ $propFilterNodes = $this->xpath->query('cal:prop-filter', $parentNode);
+ $result = array();
+
+ for ($ii=0; $ii < $propFilterNodes->length; $ii++) {
+
+ $propFilterNode = $propFilterNodes->item($ii);
+ $propFilter = array();
+ $propFilter['name'] = $propFilterNode->getAttribute('name');
+ $propFilter['is-not-defined'] = $this->xpath->query('cal:is-not-defined', $propFilterNode)->length>0;
+ $propFilter['param-filters'] = $this->parseParamFilters($propFilterNode);
+ $propFilter['text-match'] = $this->parseTextMatch($propFilterNode);
+ $propFilter['time-range'] = $this->parseTimeRange($propFilterNode);
+
+ $result[] = $propFilter;
+
+ }
+
+ return $result;
+
+ }
+
+ /**
+ * Parses the param-filter element
+ *
+ * @param \DOMElement $parentNode
+ * @return array
+ */
+ protected function parseParamFilters(\DOMElement $parentNode) {
+
+ $paramFilterNodes = $this->xpath->query('cal:param-filter', $parentNode);
+ $result = array();
+
+ for($ii=0;$ii<$paramFilterNodes->length;$ii++) {
+
+ $paramFilterNode = $paramFilterNodes->item($ii);
+ $paramFilter = array();
+ $paramFilter['name'] = $paramFilterNode->getAttribute('name');
+ $paramFilter['is-not-defined'] = $this->xpath->query('cal:is-not-defined', $paramFilterNode)->length>0;
+ $paramFilter['text-match'] = $this->parseTextMatch($paramFilterNode);
+
+ $result[] = $paramFilter;
+
+ }
+
+ return $result;
+
+ }
+
+ /**
+ * Parses the text-match element
+ *
+ * @param \DOMElement $parentNode
+ * @return array|null
+ */
+ protected function parseTextMatch(\DOMElement $parentNode) {
+
+ $textMatchNodes = $this->xpath->query('cal:text-match', $parentNode);
+
+ if ($textMatchNodes->length === 0)
+ return null;
+
+ $textMatchNode = $textMatchNodes->item(0);
+ $negateCondition = $textMatchNode->getAttribute('negate-condition');
+ $negateCondition = $negateCondition==='yes';
+ $collation = $textMatchNode->getAttribute('collation');
+ if (!$collation) $collation = 'i;ascii-casemap';
+
+ return array(
+ 'negate-condition' => $negateCondition,
+ 'collation' => $collation,
+ 'value' => $textMatchNode->nodeValue
+ );
+
+ }
+
+ /**
+ * Parses the time-range element
+ *
+ * @param \DOMElement $parentNode
+ * @return array|null
+ */
+ protected function parseTimeRange(\DOMElement $parentNode) {
+
+ $timeRangeNodes = $this->xpath->query('cal:time-range', $parentNode);
+ if ($timeRangeNodes->length === 0) {
+ return null;
+ }
+
+ $timeRangeNode = $timeRangeNodes->item(0);
+
+ if ($start = $timeRangeNode->getAttribute('start')) {
+ $start = VObject\DateTimeParser::parseDateTime($start);
+ } else {
+ $start = null;
+ }
+ if ($end = $timeRangeNode->getAttribute('end')) {
+ $end = VObject\DateTimeParser::parseDateTime($end);
+ } else {
+ $end = null;
+ }
+
+ if (!is_null($start) && !is_null($end) && $end <= $start) {
+ throw new \SabreForRainLoop\DAV\Exception\BadRequest('The end-date must be larger than the start-date in the time-range filter');
+ }
+
+ return array(
+ 'start' => $start,
+ 'end' => $end,
+ );
+
+ }
+
+ /**
+ * Parses the CALDAV:expand element
+ *
+ * @param \DOMElement $parentNode
+ * @return void
+ */
+ protected function parseExpand(\DOMElement $parentNode) {
+
+ $start = $parentNode->getAttribute('start');
+ if(!$start) {
+ throw new \SabreForRainLoop\DAV\Exception\BadRequest('The "start" attribute is required for the CALDAV:expand element');
+ }
+ $start = VObject\DateTimeParser::parseDateTime($start);
+
+ $end = $parentNode->getAttribute('end');
+ if(!$end) {
+ throw new \SabreForRainLoop\DAV\Exception\BadRequest('The "end" attribute is required for the CALDAV:expand element');
+ }
+
+ $end = VObject\DateTimeParser::parseDateTime($end);
+
+ if ($end <= $start) {
+ throw new \SabreForRainLoop\DAV\Exception\BadRequest('The end-date must be larger than the start-date in the expand element.');
+ }
+
+ return array(
+ 'start' => $start,
+ 'end' => $end,
+ );
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryValidator.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryValidator.php
new file mode 100644
index 0000000..4537d3b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/CalendarQueryValidator.php
@@ -0,0 +1,392 @@
+name !== $filters['name']) {
+ return false;
+ }
+
+ return
+ $this->validateCompFilters($vObject, $filters['comp-filters']) &&
+ $this->validatePropFilters($vObject, $filters['prop-filters']);
+
+
+ }
+
+ /**
+ * This method checks the validity of comp-filters.
+ *
+ * A list of comp-filters needs to be specified. Also the parent of the
+ * component we're checking should be specified, not the component to check
+ * itself.
+ *
+ * @param VObject\Component $parent
+ * @param array $filters
+ * @return bool
+ */
+ protected function validateCompFilters(VObject\Component $parent, array $filters) {
+
+ foreach($filters as $filter) {
+
+ $isDefined = isset($parent->$filter['name']);
+
+ if ($filter['is-not-defined']) {
+
+ if ($isDefined) {
+ return false;
+ } else {
+ continue;
+ }
+
+ }
+ if (!$isDefined) {
+ return false;
+ }
+
+ if ($filter['time-range']) {
+ foreach($parent->$filter['name'] as $subComponent) {
+ if ($this->validateTimeRange($subComponent, $filter['time-range']['start'], $filter['time-range']['end'])) {
+ continue 2;
+ }
+ }
+ return false;
+ }
+
+ if (!$filter['comp-filters'] && !$filter['prop-filters']) {
+ continue;
+ }
+
+ // If there are sub-filters, we need to find at least one component
+ // for which the subfilters hold true.
+ foreach($parent->$filter['name'] as $subComponent) {
+
+ if (
+ $this->validateCompFilters($subComponent, $filter['comp-filters']) &&
+ $this->validatePropFilters($subComponent, $filter['prop-filters'])) {
+ // We had a match, so this comp-filter succeeds
+ continue 2;
+ }
+
+ }
+
+ // If we got here it means there were sub-comp-filters or
+ // sub-prop-filters and there was no match. This means this filter
+ // needs to return false.
+ return false;
+
+ }
+
+ // If we got here it means we got through all comp-filters alive so the
+ // filters were all true.
+ return true;
+
+ }
+
+ /**
+ * This method checks the validity of prop-filters.
+ *
+ * A list of prop-filters needs to be specified. Also the parent of the
+ * property we're checking should be specified, not the property to check
+ * itself.
+ *
+ * @param VObject\Component $parent
+ * @param array $filters
+ * @return bool
+ */
+ protected function validatePropFilters(VObject\Component $parent, array $filters) {
+
+ foreach($filters as $filter) {
+
+ $isDefined = isset($parent->$filter['name']);
+
+ if ($filter['is-not-defined']) {
+
+ if ($isDefined) {
+ return false;
+ } else {
+ continue;
+ }
+
+ }
+ if (!$isDefined) {
+ return false;
+ }
+
+ if ($filter['time-range']) {
+ foreach($parent->$filter['name'] as $subComponent) {
+ if ($this->validateTimeRange($subComponent, $filter['time-range']['start'], $filter['time-range']['end'])) {
+ continue 2;
+ }
+ }
+ return false;
+ }
+
+ if (!$filter['param-filters'] && !$filter['text-match']) {
+ continue;
+ }
+
+ // If there are sub-filters, we need to find at least one property
+ // for which the subfilters hold true.
+ foreach($parent->$filter['name'] as $subComponent) {
+
+ if(
+ $this->validateParamFilters($subComponent, $filter['param-filters']) &&
+ (!$filter['text-match'] || $this->validateTextMatch($subComponent, $filter['text-match']))
+ ) {
+ // We had a match, so this prop-filter succeeds
+ continue 2;
+ }
+
+ }
+
+ // If we got here it means there were sub-param-filters or
+ // text-match filters and there was no match. This means the
+ // filter needs to return false.
+ return false;
+
+ }
+
+ // If we got here it means we got through all prop-filters alive so the
+ // filters were all true.
+ return true;
+
+ }
+
+ /**
+ * This method checks the validity of param-filters.
+ *
+ * A list of param-filters needs to be specified. Also the parent of the
+ * parameter we're checking should be specified, not the parameter to check
+ * itself.
+ *
+ * @param VObject\Property $parent
+ * @param array $filters
+ * @return bool
+ */
+ protected function validateParamFilters(VObject\Property $parent, array $filters) {
+
+ foreach($filters as $filter) {
+
+ $isDefined = isset($parent[$filter['name']]);
+
+ if ($filter['is-not-defined']) {
+
+ if ($isDefined) {
+ return false;
+ } else {
+ continue;
+ }
+
+ }
+ if (!$isDefined) {
+ return false;
+ }
+
+ if (!$filter['text-match']) {
+ continue;
+ }
+
+ if (version_compare(VObject\Version::VERSION, '3.0.0beta1', '>=')) {
+
+ // If there are sub-filters, we need to find at least one parameter
+ // for which the subfilters hold true.
+ foreach($parent[$filter['name']]->getParts() as $subParam) {
+
+ if($this->validateTextMatch($subParam,$filter['text-match'])) {
+ // We had a match, so this param-filter succeeds
+ continue 2;
+ }
+
+ }
+
+ } else {
+
+ // If there are sub-filters, we need to find at least one parameter
+ // for which the subfilters hold true.
+ foreach($parent[$filter['name']] as $subParam) {
+
+ if($this->validateTextMatch($subParam,$filter['text-match'])) {
+ // We had a match, so this param-filter succeeds
+ continue 2;
+ }
+
+ }
+
+ }
+
+ // If we got here it means there was a text-match filter and there
+ // were no matches. This means the filter needs to return false.
+ return false;
+
+ }
+
+ // If we got here it means we got through all param-filters alive so the
+ // filters were all true.
+ return true;
+
+ }
+
+ /**
+ * This method checks the validity of a text-match.
+ *
+ * A single text-match should be specified as well as the specific property
+ * or parameter we need to validate.
+ *
+ * @param VObject\Node|string $check Value to check against.
+ * @param array $textMatch
+ * @return bool
+ */
+ protected function validateTextMatch($check, array $textMatch) {
+
+ if ($check instanceof VObject\Node) {
+ $check = (string)$check;
+ }
+
+ $isMatching = \SabreForRainLoop\DAV\StringUtil::textMatch($check, $textMatch['value'], $textMatch['collation']);
+
+ return ($textMatch['negate-condition'] xor $isMatching);
+
+ }
+
+ /**
+ * Validates if a component matches the given time range.
+ *
+ * This is all based on the rules specified in rfc4791, which are quite
+ * complex.
+ *
+ * @param VObject\Node $component
+ * @param DateTime $start
+ * @param DateTime $end
+ * @return bool
+ */
+ protected function validateTimeRange(VObject\Node $component, $start, $end) {
+
+ if (is_null($start)) {
+ $start = new DateTime('1900-01-01');
+ }
+ if (is_null($end)) {
+ $end = new DateTime('3000-01-01');
+ }
+
+ switch($component->name) {
+
+ case 'VEVENT' :
+ case 'VTODO' :
+ case 'VJOURNAL' :
+
+ return $component->isInTimeRange($start, $end);
+
+ case 'VALARM' :
+
+ // If the valarm is wrapped in a recurring event, we need to
+ // expand the recursions, and validate each.
+ //
+ // Our datamodel doesn't easily allow us to do this straight
+ // in the VALARM component code, so this is a hack, and an
+ // expensive one too.
+ if ($component->parent->name === 'VEVENT' && $component->parent->RRULE) {
+
+ // Fire up the iterator!
+ $it = new VObject\RecurrenceIterator($component->parent->parent, (string)$component->parent->UID);
+ while($it->valid()) {
+ $expandedEvent = $it->getEventObject();
+
+ // We need to check from these expanded alarms, which
+ // one is the first to trigger. Based on this, we can
+ // determine if we can 'give up' expanding events.
+ $firstAlarm = null;
+ if ($expandedEvent->VALARM !== null) {
+ foreach($expandedEvent->VALARM as $expandedAlarm) {
+
+ $effectiveTrigger = $expandedAlarm->getEffectiveTriggerTime();
+ if ($expandedAlarm->isInTimeRange($start, $end)) {
+ return true;
+ }
+
+ if ((string)$expandedAlarm->TRIGGER['VALUE'] === 'DATE-TIME') {
+ // This is an alarm with a non-relative trigger
+ // time, likely created by a buggy client. The
+ // implication is that every alarm in this
+ // recurring event trigger at the exact same
+ // time. It doesn't make sense to traverse
+ // further.
+ } else {
+ // We store the first alarm as a means to
+ // figure out when we can stop traversing.
+ if (!$firstAlarm || $effectiveTrigger < $firstAlarm) {
+ $firstAlarm = $effectiveTrigger;
+ }
+ }
+ }
+ }
+ if (is_null($firstAlarm)) {
+ // No alarm was found.
+ //
+ // Or technically: No alarm that will change for
+ // every instance of the recurrence was found,
+ // which means we can assume there was no match.
+ return false;
+ }
+ if ($firstAlarm > $end) {
+ return false;
+ }
+ $it->next();
+ }
+ return false;
+ } else {
+ return $component->isInTimeRange($start, $end);
+ }
+
+ case 'VFREEBUSY' :
+ throw new \SabreForRainLoop\DAV\Exception\NotImplemented('time-range filters are currently not supported on ' . $component->name . ' components');
+
+ case 'COMPLETED' :
+ case 'CREATED' :
+ case 'DTEND' :
+ case 'DTSTAMP' :
+ case 'DTSTART' :
+ case 'DUE' :
+ case 'LAST-MODIFIED' :
+ return ($start <= $component->getDateTime() && $end >= $component->getDateTime());
+
+
+
+ default :
+ throw new \SabreForRainLoop\DAV\Exception\BadRequest('You cannot create a time-range filter on a ' . $component->name . ' component');
+
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/CalendarRootNode.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/CalendarRootNode.php
new file mode 100644
index 0000000..69e01b1
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/CalendarRootNode.php
@@ -0,0 +1,77 @@
+caldavBackend = $caldavBackend;
+
+ }
+
+ /**
+ * Returns the nodename
+ *
+ * We're overriding this, because the default will be the 'principalPrefix',
+ * and we want it to be SabreForRainLoop\CalDAV\Plugin::CALENDAR_ROOT
+ *
+ * @return string
+ */
+ public function getName() {
+
+ return Plugin::CALENDAR_ROOT;
+
+ }
+
+ /**
+ * This method returns a node for a principal.
+ *
+ * The passed array contains principal information, and is guaranteed to
+ * at least contain a uri item. Other properties may or may not be
+ * supplied by the authentication backend.
+ *
+ * @param array $principal
+ * @return \SabreForRainLoop\DAV\INode
+ */
+ public function getChildForPrincipal(array $principal) {
+
+ return new UserCalendars($this->caldavBackend, $principal);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Exception/InvalidComponentType.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Exception/InvalidComponentType.php
new file mode 100644
index 0000000..c7d0ea9
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Exception/InvalidComponentType.php
@@ -0,0 +1,35 @@
+ownerDocument;
+
+ $np = $doc->createElementNS(CalDAV\Plugin::NS_CALDAV,'cal:supported-calendar-component');
+ $errorNode->appendChild($np);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/ICSExportPlugin.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/ICSExportPlugin.php
new file mode 100644
index 0000000..6e36274
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/ICSExportPlugin.php
@@ -0,0 +1,142 @@
+server = $server;
+ $this->server->subscribeEvent('beforeMethod',array($this,'beforeMethod'), 90);
+
+ }
+
+ /**
+ * 'beforeMethod' event handles. This event handles intercepts GET requests ending
+ * with ?export
+ *
+ * @param string $method
+ * @param string $uri
+ * @return bool
+ */
+ public function beforeMethod($method, $uri) {
+
+ if ($method!='GET') return;
+ if ($this->server->httpRequest->getQueryString()!='export') return;
+
+ // splitting uri
+ list($uri) = explode('?',$uri,2);
+
+ $node = $this->server->tree->getNodeForPath($uri);
+
+ if (!($node instanceof Calendar)) return;
+
+ // Checking ACL, if available.
+ if ($aclPlugin = $this->server->getPlugin('acl')) {
+ $aclPlugin->checkPrivileges($uri, '{DAV:}read');
+ }
+
+ $this->server->httpResponse->setHeader('Content-Type','text/calendar');
+ $this->server->httpResponse->sendStatus(200);
+
+ $nodes = $this->server->getPropertiesForPath($uri, array(
+ '{' . Plugin::NS_CALDAV . '}calendar-data',
+ ),1);
+
+ $this->server->httpResponse->sendBody($this->generateICS($nodes));
+
+ // Returning false to break the event chain
+ return false;
+
+ }
+
+ /**
+ * Merges all calendar objects, and builds one big ics export
+ *
+ * @param array $nodes
+ * @return string
+ */
+ public function generateICS(array $nodes) {
+
+ $calendar = new VObject\Component\VCalendar();
+ $calendar->version = '2.0';
+ if (DAV\Server::$exposeVersion) {
+ $calendar->prodid = '-//SabreDAV//SabreDAV ' . DAV\Version::VERSION . '//EN';
+ } else {
+ $calendar->prodid = '-//SabreDAV//SabreDAV//EN';
+ }
+ $calendar->calscale = 'GREGORIAN';
+
+ $collectedTimezones = array();
+
+ $timezones = array();
+ $objects = array();
+
+ foreach($nodes as $node) {
+
+ if (!isset($node[200]['{' . Plugin::NS_CALDAV . '}calendar-data'])) {
+ continue;
+ }
+ $nodeData = $node[200]['{' . Plugin::NS_CALDAV . '}calendar-data'];
+
+ $nodeComp = VObject\Reader::read($nodeData);
+
+ foreach($nodeComp->children() as $child) {
+
+ switch($child->name) {
+ case 'VEVENT' :
+ case 'VTODO' :
+ case 'VJOURNAL' :
+ $objects[] = $child;
+ break;
+
+ // VTIMEZONE is special, because we need to filter out the duplicates
+ case 'VTIMEZONE' :
+ // Naively just checking tzid.
+ if (in_array((string)$child->TZID, $collectedTimezones)) continue;
+
+ $timezones[] = $child;
+ $collectedTimezones[] = $child->TZID;
+ break;
+
+ }
+
+ }
+
+ }
+
+ foreach($timezones as $tz) $calendar->add($tz);
+ foreach($objects as $obj) $calendar->add($obj);
+
+ return $calendar->serialize();
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/ICalendar.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/ICalendar.php
new file mode 100644
index 0000000..e6de95b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/ICalendar.php
@@ -0,0 +1,36 @@
+caldavBackend = $caldavBackend;
+ $this->principalUri = $principalUri;
+
+ }
+
+ /**
+ * Returns all notifications for a principal
+ *
+ * @return array
+ */
+ public function getChildren() {
+
+ $children = array();
+ $notifications = $this->caldavBackend->getNotificationsForPrincipal($this->principalUri);
+
+ foreach($notifications as $notification) {
+
+ $children[] = new Node(
+ $this->caldavBackend,
+ $this->principalUri,
+ $notification
+ );
+ }
+
+ return $children;
+
+ }
+
+ /**
+ * Returns the name of this object
+ *
+ * @return string
+ */
+ public function getName() {
+
+ return 'notifications';
+
+ }
+
+ /**
+ * Returns the owner principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getOwner() {
+
+ return $this->principalUri;
+
+ }
+
+ /**
+ * Returns a group principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getGroup() {
+
+ return null;
+
+ }
+
+ /**
+ * Returns a list of ACE's for this node.
+ *
+ * Each ACE has the following properties:
+ * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
+ * currently the only supported privileges
+ * * 'principal', a url to the principal who owns the node
+ * * 'protected' (optional), indicating that this ACE is not allowed to
+ * be updated.
+ *
+ * @return array
+ */
+ public function getACL() {
+
+ return array(
+ array(
+ 'principal' => $this->getOwner(),
+ 'privilege' => '{DAV:}read',
+ 'protected' => true,
+ ),
+ array(
+ 'principal' => $this->getOwner(),
+ 'privilege' => '{DAV:}write',
+ 'protected' => true,
+ )
+ );
+
+ }
+
+ /**
+ * Updates the ACL
+ *
+ * This method will receive a list of new ACE's as an array argument.
+ *
+ * @param array $acl
+ * @return void
+ */
+ public function setACL(array $acl) {
+
+ throw new DAV\Exception\NotImplemented('Updating ACLs is not implemented here');
+
+ }
+
+ /**
+ * Returns the list of supported privileges for this node.
+ *
+ * The returned data structure is a list of nested privileges.
+ * See SabreForRainLoop\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
+ * standard structure.
+ *
+ * If null is returned from this method, the default privilege set is used,
+ * which is fine for most common usecases.
+ *
+ * @return array|null
+ */
+ public function getSupportedPrivilegeSet() {
+
+ return null;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Notifications/ICollection.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Notifications/ICollection.php
new file mode 100644
index 0000000..f145f38
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Notifications/ICollection.php
@@ -0,0 +1,24 @@
+caldavBackend = $caldavBackend;
+ $this->principalUri = $principalUri;
+ $this->notification = $notification;
+
+ }
+
+ /**
+ * Returns the path name for this notification
+ *
+ * @return id
+ */
+ public function getName() {
+
+ return $this->notification->getId() . '.xml';
+
+ }
+
+ /**
+ * Returns the etag for the notification.
+ *
+ * The etag must be surrounded by litteral double-quotes.
+ *
+ * @return string
+ */
+ public function getETag() {
+
+ return $this->notification->getETag();
+
+ }
+
+ /**
+ * This method must return an xml element, using the
+ * SabreForRainLoop\CalDAV\Notifications\INotificationType classes.
+ *
+ * @return INotificationType
+ */
+ public function getNotificationType() {
+
+ return $this->notification;
+
+ }
+
+ /**
+ * Deletes this notification
+ *
+ * @return void
+ */
+ public function delete() {
+
+ $this->caldavBackend->deleteNotification($this->getOwner(), $this->notification);
+
+ }
+
+ /**
+ * Returns the owner principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getOwner() {
+
+ return $this->principalUri;
+
+ }
+
+ /**
+ * Returns a group principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getGroup() {
+
+ return null;
+
+ }
+
+ /**
+ * Returns a list of ACE's for this node.
+ *
+ * Each ACE has the following properties:
+ * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
+ * currently the only supported privileges
+ * * 'principal', a url to the principal who owns the node
+ * * 'protected' (optional), indicating that this ACE is not allowed to
+ * be updated.
+ *
+ * @return array
+ */
+ public function getACL() {
+
+ return array(
+ array(
+ 'principal' => $this->getOwner(),
+ 'privilege' => '{DAV:}read',
+ 'protected' => true,
+ ),
+ array(
+ 'principal' => $this->getOwner(),
+ 'privilege' => '{DAV:}write',
+ 'protected' => true,
+ )
+ );
+
+ }
+
+ /**
+ * Updates the ACL
+ *
+ * This method will receive a list of new ACE's as an array argument.
+ *
+ * @param array $acl
+ * @return void
+ */
+ public function setACL(array $acl) {
+
+ throw new DAV\Exception\NotImplemented('Updating ACLs is not implemented here');
+
+ }
+
+ /**
+ * Returns the list of supported privileges for this node.
+ *
+ * The returned data structure is a list of nested privileges.
+ * See SabreForRainLoop\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
+ * standard structure.
+ *
+ * If null is returned from this method, the default privilege set is used,
+ * which is fine for most common usecases.
+ *
+ * @return array|null
+ */
+ public function getSupportedPrivilegeSet() {
+
+ return null;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/Invite.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/Invite.php
new file mode 100644
index 0000000..2623755
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/Invite.php
@@ -0,0 +1,324 @@
+$value) {
+ if (!property_exists($this, $key)) {
+ throw new \InvalidArgumentException('Unknown option: ' . $key);
+ }
+ $this->$key = $value;
+ }
+
+ }
+
+ /**
+ * Serializes the notification as a single property.
+ *
+ * You should usually just encode the single top-level element of the
+ * notification.
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $node
+ * @return void
+ */
+ public function serialize(DAV\Server $server, \DOMElement $node) {
+
+ $prop = $node->ownerDocument->createElement('cs:invite-notification');
+ $node->appendChild($prop);
+
+ }
+
+ /**
+ * This method serializes the entire notification, as it is used in the
+ * response body.
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $node
+ * @return void
+ */
+ public function serializeBody(DAV\Server $server, \DOMElement $node) {
+
+ $doc = $node->ownerDocument;
+
+ $dt = $doc->createElement('cs:dtstamp');
+ $this->dtStamp->setTimezone(new \DateTimezone('GMT'));
+ $dt->appendChild($doc->createTextNode($this->dtStamp->format('Ymd\\THis\\Z')));
+ $node->appendChild($dt);
+
+ $prop = $doc->createElement('cs:invite-notification');
+ $node->appendChild($prop);
+
+ $uid = $doc->createElement('cs:uid');
+ $uid->appendChild( $doc->createTextNode($this->id) );
+ $prop->appendChild($uid);
+
+ $href = $doc->createElement('d:href');
+ $href->appendChild( $doc->createTextNode( $this->href ) );
+ $prop->appendChild($href);
+
+ $nodeName = null;
+ switch($this->type) {
+
+ case SharingPlugin::STATUS_ACCEPTED :
+ $nodeName = 'cs:invite-accepted';
+ break;
+ case SharingPlugin::STATUS_DECLINED :
+ $nodeName = 'cs:invite-declined';
+ break;
+ case SharingPlugin::STATUS_DELETED :
+ $nodeName = 'cs:invite-deleted';
+ break;
+ case SharingPlugin::STATUS_NORESPONSE :
+ $nodeName = 'cs:invite-noresponse';
+ break;
+
+ }
+ $prop->appendChild(
+ $doc->createElement($nodeName)
+ );
+ $hostHref = $doc->createElement('d:href', $server->getBaseUri() . $this->hostUrl);
+ $hostUrl = $doc->createElement('cs:hosturl');
+ $hostUrl->appendChild($hostHref);
+ $prop->appendChild($hostUrl);
+
+ $access = $doc->createElement('cs:access');
+ if ($this->readOnly) {
+ $access->appendChild($doc->createElement('cs:read'));
+ } else {
+ $access->appendChild($doc->createElement('cs:read-write'));
+ }
+ $prop->appendChild($access);
+
+ $organizerUrl = $doc->createElement('cs:organizer');
+ // If the organizer contains a 'mailto:' part, it means it should be
+ // treated as absolute.
+ if (strtolower(substr($this->organizer,0,7))==='mailto:') {
+ $organizerHref = new DAV\Property\Href($this->organizer, false);
+ } else {
+ $organizerHref = new DAV\Property\Href($this->organizer, true);
+ }
+ $organizerHref->serialize($server, $organizerUrl);
+
+ if ($this->commonName) {
+ $commonName = $doc->createElement('cs:common-name');
+ $commonName->appendChild($doc->createTextNode($this->commonName));
+ $organizerUrl->appendChild($commonName);
+
+ $commonNameOld = $doc->createElement('cs:organizer-cn');
+ $commonNameOld->appendChild($doc->createTextNode($this->commonName));
+ $prop->appendChild($commonNameOld);
+
+ }
+ if ($this->firstName) {
+ $firstName = $doc->createElement('cs:first-name');
+ $firstName->appendChild($doc->createTextNode($this->firstName));
+ $organizerUrl->appendChild($firstName);
+
+ $firstNameOld = $doc->createElement('cs:organizer-first');
+ $firstNameOld->appendChild($doc->createTextNode($this->firstName));
+ $prop->appendChild($firstNameOld);
+ }
+ if ($this->lastName) {
+ $lastName = $doc->createElement('cs:last-name');
+ $lastName->appendChild($doc->createTextNode($this->lastName));
+ $organizerUrl->appendChild($lastName);
+
+ $lastNameOld = $doc->createElement('cs:organizer-last');
+ $lastNameOld->appendChild($doc->createTextNode($this->lastName));
+ $prop->appendChild($lastNameOld);
+ }
+ $prop->appendChild($organizerUrl);
+
+ if ($this->summary) {
+ $summary = $doc->createElement('cs:summary');
+ $summary->appendChild($doc->createTextNode($this->summary));
+ $prop->appendChild($summary);
+ }
+ if ($this->supportedComponents) {
+
+ $xcomp = $doc->createElement('cal:supported-calendar-component-set');
+ $this->supportedComponents->serialize($server, $xcomp);
+ $prop->appendChild($xcomp);
+
+ }
+
+ }
+
+ /**
+ * Returns a unique id for this notification
+ *
+ * This is just the base url. This should generally be some kind of unique
+ * id.
+ *
+ * @return string
+ */
+ public function getId() {
+
+ return $this->id;
+
+ }
+
+ /**
+ * Returns the ETag for this notification.
+ *
+ * The ETag must be surrounded by literal double-quotes.
+ *
+ * @return string
+ */
+ public function getETag() {
+
+ return $this->etag;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/InviteReply.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/InviteReply.php
new file mode 100644
index 0000000..3964c94
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/InviteReply.php
@@ -0,0 +1,218 @@
+$value) {
+ if (!property_exists($this, $key)) {
+ throw new \InvalidArgumentException('Unknown option: ' . $key);
+ }
+ $this->$key = $value;
+ }
+
+ }
+
+ /**
+ * Serializes the notification as a single property.
+ *
+ * You should usually just encode the single top-level element of the
+ * notification.
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $node
+ * @return void
+ */
+ public function serialize(DAV\Server $server, \DOMElement $node) {
+
+ $prop = $node->ownerDocument->createElement('cs:invite-reply');
+ $node->appendChild($prop);
+
+ }
+
+ /**
+ * This method serializes the entire notification, as it is used in the
+ * response body.
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $node
+ * @return void
+ */
+ public function serializeBody(DAV\Server $server, \DOMElement $node) {
+
+ $doc = $node->ownerDocument;
+
+ $dt = $doc->createElement('cs:dtstamp');
+ $this->dtStamp->setTimezone(new \DateTimezone('GMT'));
+ $dt->appendChild($doc->createTextNode($this->dtStamp->format('Ymd\\THis\\Z')));
+ $node->appendChild($dt);
+
+ $prop = $doc->createElement('cs:invite-reply');
+ $node->appendChild($prop);
+
+ $uid = $doc->createElement('cs:uid');
+ $uid->appendChild($doc->createTextNode($this->id));
+ $prop->appendChild($uid);
+
+ $inReplyTo = $doc->createElement('cs:in-reply-to');
+ $inReplyTo->appendChild( $doc->createTextNode($this->inReplyTo) );
+ $prop->appendChild($inReplyTo);
+
+ $href = $doc->createElement('d:href');
+ $href->appendChild( $doc->createTextNode($this->href) );
+ $prop->appendChild($href);
+
+ $nodeName = null;
+ switch($this->type) {
+
+ case SharingPlugin::STATUS_ACCEPTED :
+ $nodeName = 'cs:invite-accepted';
+ break;
+ case SharingPlugin::STATUS_DECLINED :
+ $nodeName = 'cs:invite-declined';
+ break;
+
+ }
+ $prop->appendChild(
+ $doc->createElement($nodeName)
+ );
+ $hostHref = $doc->createElement('d:href', $server->getBaseUri() . $this->hostUrl);
+ $hostUrl = $doc->createElement('cs:hosturl');
+ $hostUrl->appendChild($hostHref);
+ $prop->appendChild($hostUrl);
+
+ if ($this->summary) {
+ $summary = $doc->createElement('cs:summary');
+ $summary->appendChild($doc->createTextNode($this->summary));
+ $prop->appendChild($summary);
+ }
+
+ }
+
+ /**
+ * Returns a unique id for this notification
+ *
+ * This is just the base url. This should generally be some kind of unique
+ * id.
+ *
+ * @return string
+ */
+ public function getId() {
+
+ return $this->id;
+
+ }
+
+ /**
+ * Returns the ETag for this notification.
+ *
+ * The ETag must be surrounded by literal double-quotes.
+ *
+ * @return string
+ */
+ public function getETag() {
+
+ return $this->etag;
+
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/SystemStatus.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/SystemStatus.php
new file mode 100644
index 0000000..dfe571a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Notifications/Notification/SystemStatus.php
@@ -0,0 +1,182 @@
+id = $id;
+ $this->type = $type;
+ $this->description = $description;
+ $this->href = $href;
+ $this->etag = $etag;
+
+ }
+
+ /**
+ * Serializes the notification as a single property.
+ *
+ * You should usually just encode the single top-level element of the
+ * notification.
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $node
+ * @return void
+ */
+ public function serialize(DAV\Server $server, \DOMElement $node) {
+
+ switch($this->type) {
+ case self::TYPE_LOW :
+ $type = 'low';
+ break;
+ case self::TYPE_MEDIUM :
+ $type = 'medium';
+ break;
+ default :
+ case self::TYPE_HIGH :
+ $type = 'high';
+ break;
+ }
+
+ $prop = $node->ownerDocument->createElement('cs:systemstatus');
+ $prop->setAttribute('type', $type);
+
+ $node->appendChild($prop);
+
+ }
+
+ /**
+ * This method serializes the entire notification, as it is used in the
+ * response body.
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $node
+ * @return void
+ */
+ public function serializeBody(DAV\Server $server, \DOMElement $node) {
+
+ switch($this->type) {
+ case self::TYPE_LOW :
+ $type = 'low';
+ break;
+ case self::TYPE_MEDIUM :
+ $type = 'medium';
+ break;
+ default :
+ case self::TYPE_HIGH :
+ $type = 'high';
+ break;
+ }
+
+ $prop = $node->ownerDocument->createElement('cs:systemstatus');
+ $prop->setAttribute('type', $type);
+
+ if ($this->description) {
+ $text = $node->ownerDocument->createTextNode($this->description);
+ $desc = $node->ownerDocument->createElement('cs:description');
+ $desc->appendChild($text);
+ $prop->appendChild($desc);
+ }
+ if ($this->href) {
+ $text = $node->ownerDocument->createTextNode($this->href);
+ $href = $node->ownerDocument->createElement('d:href');
+ $href->appendChild($text);
+ $prop->appendChild($href);
+ }
+
+ $node->appendChild($prop);
+
+ }
+
+ /**
+ * Returns a unique id for this notification
+ *
+ * This is just the base url. This should generally be some kind of unique
+ * id.
+ *
+ * @return string
+ */
+ public function getId() {
+
+ return $this->id;
+
+ }
+
+ /*
+ * Returns the ETag for this notification.
+ *
+ * The ETag must be surrounded by literal double-quotes.
+ *
+ * @return string
+ */
+ public function getETag() {
+
+ return $this->etag;
+
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Plugin.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Plugin.php
new file mode 100644
index 0000000..9ed5695
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Plugin.php
@@ -0,0 +1,1338 @@
+imipHandler = $imipHandler;
+
+ }
+
+ /**
+ * Use this method to tell the server this plugin defines additional
+ * HTTP methods.
+ *
+ * This method is passed a uri. It should only return HTTP methods that are
+ * available for the specified uri.
+ *
+ * @param string $uri
+ * @return array
+ */
+ public function getHTTPMethods($uri) {
+
+ // The MKCALENDAR is only available on unmapped uri's, whose
+ // parents extend IExtendedCollection
+ list($parent, $name) = DAV\URLUtil::splitPath($uri);
+
+ $node = $this->server->tree->getNodeForPath($parent);
+
+ if ($node instanceof DAV\IExtendedCollection) {
+ try {
+ $node->getChild($name);
+ } catch (DAV\Exception\NotFound $e) {
+ return array('MKCALENDAR');
+ }
+ }
+ return array();
+
+ }
+
+ /**
+ * Returns a list of features for the DAV: HTTP header.
+ *
+ * @return array
+ */
+ public function getFeatures() {
+
+ return array('calendar-access', 'calendar-proxy');
+
+ }
+
+ /**
+ * Returns a plugin name.
+ *
+ * Using this name other plugins will be able to access other plugins
+ * using DAV\Server::getPlugin
+ *
+ * @return string
+ */
+ public function getPluginName() {
+
+ return 'caldav';
+
+ }
+
+ /**
+ * Returns a list of reports this plugin supports.
+ *
+ * This will be used in the {DAV:}supported-report-set property.
+ * Note that you still need to subscribe to the 'report' event to actually
+ * implement them
+ *
+ * @param string $uri
+ * @return array
+ */
+ public function getSupportedReportSet($uri) {
+
+ $node = $this->server->tree->getNodeForPath($uri);
+
+ $reports = array();
+ if ($node instanceof ICalendar || $node instanceof ICalendarObject) {
+ $reports[] = '{' . self::NS_CALDAV . '}calendar-multiget';
+ $reports[] = '{' . self::NS_CALDAV . '}calendar-query';
+ }
+ if ($node instanceof ICalendar) {
+ $reports[] = '{' . self::NS_CALDAV . '}free-busy-query';
+ }
+ return $reports;
+
+ }
+
+ /**
+ * Initializes the plugin
+ *
+ * @param DAV\Server $server
+ * @return void
+ */
+ public function initialize(DAV\Server $server) {
+
+ $this->server = $server;
+
+ $server->subscribeEvent('unknownMethod',array($this,'unknownMethod'));
+ //$server->subscribeEvent('unknownMethod',array($this,'unknownMethod2'),1000);
+ $server->subscribeEvent('report',array($this,'report'));
+ $server->subscribeEvent('beforeGetProperties',array($this,'beforeGetProperties'));
+ $server->subscribeEvent('onHTMLActionsPanel', array($this,'htmlActionsPanel'));
+ $server->subscribeEvent('onBrowserPostAction', array($this,'browserPostAction'));
+ $server->subscribeEvent('beforeWriteContent', array($this, 'beforeWriteContent'));
+ $server->subscribeEvent('beforeCreateFile', array($this, 'beforeCreateFile'));
+ $server->subscribeEvent('beforeMethod', array($this,'beforeMethod'));
+
+ $server->xmlNamespaces[self::NS_CALDAV] = 'cal';
+ $server->xmlNamespaces[self::NS_CALENDARSERVER] = 'cs';
+
+ $server->propertyMap['{' . self::NS_CALDAV . '}supported-calendar-component-set'] = 'SabreForRainLoop\\CalDAV\\Property\\SupportedCalendarComponentSet';
+ $server->propertyMap['{' . self::NS_CALDAV . '}schedule-calendar-transp'] = 'SabreForRainLoop\\CalDAV\\Property\\ScheduleCalendarTransp';
+
+ $server->resourceTypeMapping['\\SabreForRainLoop\\CalDAV\\ICalendar'] = '{urn:ietf:params:xml:ns:caldav}calendar';
+ $server->resourceTypeMapping['\\SabreForRainLoop\\CalDAV\\Schedule\\IOutbox'] = '{urn:ietf:params:xml:ns:caldav}schedule-outbox';
+ $server->resourceTypeMapping['\\SabreForRainLoop\\CalDAV\\Principal\\IProxyRead'] = '{http://calendarserver.org/ns/}calendar-proxy-read';
+ $server->resourceTypeMapping['\\SabreForRainLoop\\CalDAV\\Principal\\IProxyWrite'] = '{http://calendarserver.org/ns/}calendar-proxy-write';
+ $server->resourceTypeMapping['\\SabreForRainLoop\\CalDAV\\Notifications\\ICollection'] = '{' . self::NS_CALENDARSERVER . '}notification';
+
+ array_push($server->protectedProperties,
+
+ '{' . self::NS_CALDAV . '}supported-calendar-component-set',
+ '{' . self::NS_CALDAV . '}supported-calendar-data',
+ '{' . self::NS_CALDAV . '}max-resource-size',
+ '{' . self::NS_CALDAV . '}min-date-time',
+ '{' . self::NS_CALDAV . '}max-date-time',
+ '{' . self::NS_CALDAV . '}max-instances',
+ '{' . self::NS_CALDAV . '}max-attendees-per-instance',
+ '{' . self::NS_CALDAV . '}calendar-home-set',
+ '{' . self::NS_CALDAV . '}supported-collation-set',
+ '{' . self::NS_CALDAV . '}calendar-data',
+
+ // scheduling extension
+ '{' . self::NS_CALDAV . '}schedule-inbox-URL',
+ '{' . self::NS_CALDAV . '}schedule-outbox-URL',
+ '{' . self::NS_CALDAV . '}calendar-user-address-set',
+ '{' . self::NS_CALDAV . '}calendar-user-type',
+
+ // CalendarServer extensions
+ '{' . self::NS_CALENDARSERVER . '}getctag',
+ '{' . self::NS_CALENDARSERVER . '}calendar-proxy-read-for',
+ '{' . self::NS_CALENDARSERVER . '}calendar-proxy-write-for',
+ '{' . self::NS_CALENDARSERVER . '}notification-URL',
+ '{' . self::NS_CALENDARSERVER . '}notificationtype'
+
+ );
+ }
+
+ /**
+ * This function handles support for the MKCALENDAR method
+ *
+ * @param string $method
+ * @param string $uri
+ * @return bool
+ */
+ public function unknownMethod($method, $uri) {
+
+ switch ($method) {
+ case 'MKCALENDAR' :
+ $this->httpMkCalendar($uri);
+ // false is returned to stop the propagation of the
+ // unknownMethod event.
+ return false;
+ case 'POST' :
+
+ // Checking if this is a text/calendar content type
+ $contentType = $this->server->httpRequest->getHeader('Content-Type');
+ if (strpos($contentType, 'text/calendar')!==0) {
+ return;
+ }
+
+ // Checking if we're talking to an outbox
+ try {
+ $node = $this->server->tree->getNodeForPath($uri);
+ } catch (DAV\Exception\NotFound $e) {
+ return;
+ }
+ if (!$node instanceof Schedule\IOutbox)
+ return;
+
+ $this->outboxRequest($node, $uri);
+ return false;
+
+ }
+
+ }
+
+ /**
+ * This functions handles REPORT requests specific to CalDAV
+ *
+ * @param string $reportName
+ * @param \DOMNode $dom
+ * @return bool
+ */
+ public function report($reportName,$dom) {
+
+ switch($reportName) {
+ case '{'.self::NS_CALDAV.'}calendar-multiget' :
+ $this->calendarMultiGetReport($dom);
+ return false;
+ case '{'.self::NS_CALDAV.'}calendar-query' :
+ $this->calendarQueryReport($dom);
+ return false;
+ case '{'.self::NS_CALDAV.'}free-busy-query' :
+ $this->freeBusyQueryReport($dom);
+ return false;
+
+ }
+
+
+ }
+
+ /**
+ * This function handles the MKCALENDAR HTTP method, which creates
+ * a new calendar.
+ *
+ * @param string $uri
+ * @return void
+ */
+ public function httpMkCalendar($uri) {
+
+ // Due to unforgivable bugs in iCal, we're completely disabling MKCALENDAR support
+ // for clients matching iCal in the user agent
+ //$ua = $this->server->httpRequest->getHeader('User-Agent');
+ //if (strpos($ua,'iCal/')!==false) {
+ // throw new \SabreForRainLoop\DAV\Exception\Forbidden('iCal has major bugs in it\'s RFC3744 support. Therefore we are left with no other choice but disabling this feature.');
+ //}
+
+ $body = $this->server->httpRequest->getBody(true);
+ $properties = array();
+
+ if ($body) {
+
+ $dom = DAV\XMLUtil::loadDOMDocument($body);
+
+ foreach($dom->firstChild->childNodes as $child) {
+
+ if (DAV\XMLUtil::toClarkNotation($child)!=='{DAV:}set') continue;
+ foreach(DAV\XMLUtil::parseProperties($child,$this->server->propertyMap) as $k=>$prop) {
+ $properties[$k] = $prop;
+ }
+
+ }
+ }
+
+ $resourceType = array('{DAV:}collection','{urn:ietf:params:xml:ns:caldav}calendar');
+
+ $this->server->createCollection($uri,$resourceType,$properties);
+
+ $this->server->httpResponse->sendStatus(201);
+ $this->server->httpResponse->setHeader('Content-Length',0);
+ }
+
+ /**
+ * beforeGetProperties
+ *
+ * This method handler is invoked before any after properties for a
+ * resource are fetched. This allows us to add in any CalDAV specific
+ * properties.
+ *
+ * @param string $path
+ * @param DAV\INode $node
+ * @param array $requestedProperties
+ * @param array $returnedProperties
+ * @return void
+ */
+ public function beforeGetProperties($path, DAV\INode $node, &$requestedProperties, &$returnedProperties) {
+
+ if ($node instanceof DAVACL\IPrincipal) {
+
+ // calendar-home-set property
+ $calHome = '{' . self::NS_CALDAV . '}calendar-home-set';
+ if (in_array($calHome,$requestedProperties)) {
+ $principalId = $node->getName();
+ $calendarHomePath = self::CALENDAR_ROOT . '/' . $principalId . '/';
+
+ unset($requestedProperties[array_search($calHome, $requestedProperties)]);
+ $returnedProperties[200][$calHome] = new DAV\Property\Href($calendarHomePath);
+
+ }
+
+ // schedule-outbox-URL property
+ $scheduleProp = '{' . self::NS_CALDAV . '}schedule-outbox-URL';
+ if (in_array($scheduleProp,$requestedProperties)) {
+ $principalId = $node->getName();
+ $outboxPath = self::CALENDAR_ROOT . '/' . $principalId . '/outbox';
+
+ unset($requestedProperties[array_search($scheduleProp, $requestedProperties)]);
+ $returnedProperties[200][$scheduleProp] = new DAV\Property\Href($outboxPath);
+
+ }
+
+ // calendar-user-address-set property
+ $calProp = '{' . self::NS_CALDAV . '}calendar-user-address-set';
+ if (in_array($calProp,$requestedProperties)) {
+
+ $addresses = $node->getAlternateUriSet();
+ $addresses[] = $this->server->getBaseUri() . DAV\URLUtil::encodePath($node->getPrincipalUrl() . '/');
+ unset($requestedProperties[array_search($calProp, $requestedProperties)]);
+ $returnedProperties[200][$calProp] = new DAV\Property\HrefList($addresses, false);
+
+ }
+
+ // These two properties are shortcuts for ical to easily find
+ // other principals this principal has access to.
+ $propRead = '{' . self::NS_CALENDARSERVER . '}calendar-proxy-read-for';
+ $propWrite = '{' . self::NS_CALENDARSERVER . '}calendar-proxy-write-for';
+ if (in_array($propRead,$requestedProperties) || in_array($propWrite,$requestedProperties)) {
+
+ $aclPlugin = $this->server->getPlugin('acl');
+ $membership = $aclPlugin->getPrincipalMembership($path);
+ $readList = array();
+ $writeList = array();
+
+ foreach($membership as $group) {
+
+ $groupNode = $this->server->tree->getNodeForPath($group);
+
+ // If the node is either ap proxy-read or proxy-write
+ // group, we grab the parent principal and add it to the
+ // list.
+ if ($groupNode instanceof Principal\IProxyRead) {
+ list($readList[]) = DAV\URLUtil::splitPath($group);
+ }
+ if ($groupNode instanceof Principal\IProxyWrite) {
+ list($writeList[]) = DAV\URLUtil::splitPath($group);
+ }
+
+ }
+ if (in_array($propRead,$requestedProperties)) {
+ unset($requestedProperties[$propRead]);
+ $returnedProperties[200][$propRead] = new DAV\Property\HrefList($readList);
+ }
+ if (in_array($propWrite,$requestedProperties)) {
+ unset($requestedProperties[$propWrite]);
+ $returnedProperties[200][$propWrite] = new DAV\Property\HrefList($writeList);
+ }
+
+ }
+
+ // notification-URL property
+ $notificationUrl = '{' . self::NS_CALENDARSERVER . '}notification-URL';
+ if (($index = array_search($notificationUrl, $requestedProperties)) !== false) {
+ $principalId = $node->getName();
+ $calendarHomePath = 'calendars/' . $principalId . '/notifications/';
+ unset($requestedProperties[$index]);
+ $returnedProperties[200][$notificationUrl] = new DAV\Property\Href($calendarHomePath);
+ }
+
+ } // instanceof IPrincipal
+
+ if ($node instanceof Notifications\INode) {
+
+ $propertyName = '{' . self::NS_CALENDARSERVER . '}notificationtype';
+ if (($index = array_search($propertyName, $requestedProperties)) !== false) {
+
+ $returnedProperties[200][$propertyName] =
+ $node->getNotificationType();
+
+ unset($requestedProperties[$index]);
+
+ }
+
+ } // instanceof Notifications_INode
+
+
+ if ($node instanceof ICalendarObject) {
+ // The calendar-data property is not supposed to be a 'real'
+ // property, but in large chunks of the spec it does act as such.
+ // Therefore we simply expose it as a property.
+ $calDataProp = '{' . Plugin::NS_CALDAV . '}calendar-data';
+ if (in_array($calDataProp, $requestedProperties)) {
+ unset($requestedProperties[$calDataProp]);
+ $val = $node->get();
+ if (is_resource($val))
+ $val = stream_get_contents($val);
+
+ // Taking out \r to not screw up the xml output
+ $returnedProperties[200][$calDataProp] = str_replace("\r","", $val);
+
+ }
+ }
+
+ }
+
+ /**
+ * This function handles the calendar-multiget REPORT.
+ *
+ * This report is used by the client to fetch the content of a series
+ * of urls. Effectively avoiding a lot of redundant requests.
+ *
+ * @param \DOMNode $dom
+ * @return void
+ */
+ public function calendarMultiGetReport($dom) {
+
+ $properties = array_keys(DAV\XMLUtil::parseProperties($dom->firstChild));
+ $hrefElems = $dom->getElementsByTagNameNS('urn:DAV','href');
+
+ $xpath = new \DOMXPath($dom);
+ $xpath->registerNameSpace('cal',Plugin::NS_CALDAV);
+ $xpath->registerNameSpace('dav','urn:DAV');
+
+ $expand = $xpath->query('/cal:calendar-multiget/dav:prop/cal:calendar-data/cal:expand');
+ if ($expand->length>0) {
+ $expandElem = $expand->item(0);
+ $start = $expandElem->getAttribute('start');
+ $end = $expandElem->getAttribute('end');
+ if(!$start || !$end) {
+ throw new DAV\Exception\BadRequest('The "start" and "end" attributes are required for the CALDAV:expand element');
+ }
+ $start = VObject\DateTimeParser::parseDateTime($start);
+ $end = VObject\DateTimeParser::parseDateTime($end);
+
+ if ($end <= $start) {
+ throw new DAV\Exception\BadRequest('The end-date must be larger than the start-date in the expand element.');
+ }
+
+ $expand = true;
+
+ } else {
+
+ $expand = false;
+
+ }
+
+ foreach($hrefElems as $elem) {
+ $uri = $this->server->calculateUri($elem->nodeValue);
+ list($objProps) = $this->server->getPropertiesForPath($uri,$properties);
+
+ if ($expand && isset($objProps[200]['{' . self::NS_CALDAV . '}calendar-data'])) {
+ $vObject = VObject\Reader::read($objProps[200]['{' . self::NS_CALDAV . '}calendar-data']);
+ $vObject->expand($start, $end);
+ $objProps[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize();
+ }
+
+ $propertyList[]=$objProps;
+
+ }
+
+ $prefer = $this->server->getHTTPPRefer();
+
+ $this->server->httpResponse->sendStatus(207);
+ $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
+ $this->server->httpResponse->setHeader('Vary','Brief,Prefer');
+ $this->server->httpResponse->sendBody($this->server->generateMultiStatus($propertyList, $prefer['return-minimal']));
+
+ }
+
+ /**
+ * This function handles the calendar-query REPORT
+ *
+ * This report is used by clients to request calendar objects based on
+ * complex conditions.
+ *
+ * @param \DOMNode $dom
+ * @return void
+ */
+ public function calendarQueryReport($dom) {
+
+ $parser = new CalendarQueryParser($dom);
+ $parser->parse();
+
+ $node = $this->server->tree->getNodeForPath($this->server->getRequestUri());
+ $depth = $this->server->getHTTPDepth(0);
+
+ // The default result is an empty array
+ $result = array();
+
+ // The calendarobject was requested directly. In this case we handle
+ // this locally.
+ if ($depth == 0 && $node instanceof ICalendarObject) {
+
+ $requestedCalendarData = true;
+ $requestedProperties = $parser->requestedProperties;
+
+ if (!in_array('{urn:ietf:params:xml:ns:caldav}calendar-data', $requestedProperties)) {
+
+ // We always retrieve calendar-data, as we need it for filtering.
+ $requestedProperties[] = '{urn:ietf:params:xml:ns:caldav}calendar-data';
+
+ // If calendar-data wasn't explicitly requested, we need to remove
+ // it after processing.
+ $requestedCalendarData = false;
+ }
+
+ $properties = $this->server->getPropertiesForPath(
+ $this->server->getRequestUri(),
+ $requestedProperties,
+ 0
+ );
+
+ // This array should have only 1 element, the first calendar
+ // object.
+ $properties = current($properties);
+
+ // If there wasn't any calendar-data returned somehow, we ignore
+ // this.
+ if (isset($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data'])) {
+
+ $validator = new CalendarQueryValidator();
+
+ $vObject = VObject\Reader::read($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']);
+ if ($validator->validate($vObject,$parser->filters)) {
+
+ // If the client didn't require the calendar-data property,
+ // we won't give it back.
+ if (!$requestedCalendarData) {
+ unset($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']);
+ } else {
+ if ($parser->expand) {
+ $vObject->expand($parser->expand['start'], $parser->expand['end']);
+ $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize();
+ }
+ }
+
+ $result = array($properties);
+
+ }
+
+ }
+
+ }
+ // If we're dealing with a calendar, the calendar itself is responsible
+ // for the calendar-query.
+ if ($node instanceof ICalendar && $depth = 1) {
+
+ $nodePaths = $node->calendarQuery($parser->filters);
+
+ foreach($nodePaths as $path) {
+
+ list($properties) =
+ $this->server->getPropertiesForPath($this->server->getRequestUri() . '/' . $path, $parser->requestedProperties);
+
+ if ($parser->expand) {
+ // We need to do some post-processing
+ $vObject = VObject\Reader::read($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']);
+ $vObject->expand($parser->expand['start'], $parser->expand['end']);
+ $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize();
+ }
+
+ $result[] = $properties;
+
+ }
+
+ }
+
+ $prefer = $this->server->getHTTPPRefer();
+
+ $this->server->httpResponse->sendStatus(207);
+ $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
+ $this->server->httpResponse->setHeader('Vary','Brief,Prefer');
+ $this->server->httpResponse->sendBody($this->server->generateMultiStatus($result, $prefer['return-minimal']));
+
+ }
+
+ /**
+ * This method is responsible for parsing the request and generating the
+ * response for the CALDAV:free-busy-query REPORT.
+ *
+ * @param \DOMNode $dom
+ * @return void
+ */
+ protected function freeBusyQueryReport(\DOMNode $dom) {
+
+ $start = null;
+ $end = null;
+
+ foreach($dom->firstChild->childNodes as $childNode) {
+
+ $clark = DAV\XMLUtil::toClarkNotation($childNode);
+ if ($clark == '{' . self::NS_CALDAV . '}time-range') {
+ $start = $childNode->getAttribute('start');
+ $end = $childNode->getAttribute('end');
+ break;
+ }
+
+ }
+ if ($start) {
+ $start = VObject\DateTimeParser::parseDateTime($start);
+ }
+ if ($end) {
+ $end = VObject\DateTimeParser::parseDateTime($end);
+ }
+
+ if (!$start && !$end) {
+ throw new DAV\Exception\BadRequest('The freebusy report must have a time-range filter');
+ }
+ $acl = $this->server->getPlugin('acl');
+
+ if (!$acl) {
+ throw new DAV\Exception('The ACL plugin must be loaded for free-busy queries to work');
+ }
+ $uri = $this->server->getRequestUri();
+ $acl->checkPrivileges($uri,'{' . self::NS_CALDAV . '}read-free-busy');
+
+ $calendar = $this->server->tree->getNodeForPath($uri);
+ if (!$calendar instanceof ICalendar) {
+ throw new DAV\Exception\NotImplemented('The free-busy-query REPORT is only implemented on calendars');
+ }
+
+ // Doing a calendar-query first, to make sure we get the most
+ // performance.
+ $urls = $calendar->calendarQuery(array(
+ 'name' => 'VCALENDAR',
+ 'comp-filters' => array(
+ array(
+ 'name' => 'VEVENT',
+ 'comp-filters' => array(),
+ 'prop-filters' => array(),
+ 'is-not-defined' => false,
+ 'time-range' => array(
+ 'start' => $start,
+ 'end' => $end,
+ ),
+ ),
+ ),
+ 'prop-filters' => array(),
+ 'is-not-defined' => false,
+ 'time-range' => null,
+ ));
+
+ $objects = array_map(function($url) use ($calendar) {
+ $obj = $calendar->getChild($url)->get();
+ return $obj;
+ }, $urls);
+
+ $generator = new VObject\FreeBusyGenerator();
+ $generator->setObjects($objects);
+ $generator->setTimeRange($start, $end);
+ $result = $generator->getResult();
+ $result = $result->serialize();
+
+ $this->server->httpResponse->sendStatus(200);
+ $this->server->httpResponse->setHeader('Content-Type', 'text/calendar');
+ $this->server->httpResponse->setHeader('Content-Length', strlen($result));
+ $this->server->httpResponse->sendBody($result);
+
+ }
+
+ /**
+ * This method is triggered before a file gets updated with new content.
+ *
+ * This plugin uses this method to ensure that CalDAV objects receive
+ * valid calendar data.
+ *
+ * @param string $path
+ * @param DAV\IFile $node
+ * @param resource $data
+ * @return void
+ */
+ public function beforeWriteContent($path, DAV\IFile $node, &$data) {
+
+ if (!$node instanceof ICalendarObject)
+ return;
+
+ $this->validateICalendar($data, $path);
+
+ }
+
+ /**
+ * This method is triggered before a new file is created.
+ *
+ * This plugin uses this method to ensure that newly created calendar
+ * objects contain valid calendar data.
+ *
+ * @param string $path
+ * @param resource $data
+ * @param DAV\ICollection $parentNode
+ * @return void
+ */
+ public function beforeCreateFile($path, &$data, DAV\ICollection $parentNode) {
+
+ if (!$parentNode instanceof Calendar)
+ return;
+
+ $this->validateICalendar($data, $path);
+
+ }
+
+ /**
+ * This event is triggered before any HTTP request is handled.
+ *
+ * We use this to intercept GET calls to notification nodes, and return the
+ * proper response.
+ *
+ * @param string $method
+ * @param string $path
+ * @return void
+ */
+ public function beforeMethod($method, $path) {
+
+ if ($method!=='GET') return;
+
+ try {
+ $node = $this->server->tree->getNodeForPath($path);
+ } catch (DAV\Exception\NotFound $e) {
+ return;
+ }
+
+ if (!$node instanceof Notifications\INode)
+ return;
+
+ if (!$this->server->checkPreconditions(true)) return false;
+ $dom = new \DOMDocument('1.0', 'UTF-8');
+
+ $dom->formatOutput = true;
+
+ $root = $dom->createElement('cs:notification');
+ foreach($this->server->xmlNamespaces as $namespace => $prefix) {
+ $root->setAttribute('xmlns:' . $prefix, $namespace);
+ }
+
+ $dom->appendChild($root);
+ $node->getNotificationType()->serializeBody($this->server, $root);
+
+ $this->server->httpResponse->setHeader('Content-Type','application/xml');
+ $this->server->httpResponse->setHeader('ETag',$node->getETag());
+ $this->server->httpResponse->sendStatus(200);
+ $this->server->httpResponse->sendBody($dom->saveXML());
+
+ return false;
+
+ }
+
+ /**
+ * Checks if the submitted iCalendar data is in fact, valid.
+ *
+ * An exception is thrown if it's not.
+ *
+ * @param resource|string $data
+ * @param string $path
+ * @return void
+ */
+ protected function validateICalendar(&$data, $path) {
+
+ // If it's a stream, we convert it to a string first.
+ if (is_resource($data)) {
+ $data = stream_get_contents($data);
+ }
+
+ // Converting the data to unicode, if needed.
+ $data = DAV\StringUtil::ensureUTF8($data);
+
+ try {
+
+ $vobj = VObject\Reader::read($data);
+
+ } catch (VObject\ParseException $e) {
+
+ throw new DAV\Exception\UnsupportedMediaType('This resource only supports valid iCalendar 2.0 data. Parse error: ' . $e->getMessage());
+
+ }
+
+ if ($vobj->name !== 'VCALENDAR') {
+ throw new DAV\Exception\UnsupportedMediaType('This collection can only support iCalendar objects.');
+ }
+
+ // Get the Supported Components for the target calendar
+ list($parentPath,$object) = DAV\URLUtil::splitPath($path);
+ $calendarProperties = $this->server->getProperties($parentPath,array('{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'));
+ $supportedComponents = $calendarProperties['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set']->getValue();
+
+ $foundType = null;
+ $foundUID = null;
+ foreach($vobj->getComponents() as $component) {
+ switch($component->name) {
+ case 'VTIMEZONE' :
+ continue 2;
+ case 'VEVENT' :
+ case 'VTODO' :
+ case 'VJOURNAL' :
+ if (is_null($foundType)) {
+ $foundType = $component->name;
+ if (!in_array($foundType, $supportedComponents)) {
+ throw new Exception\InvalidComponentType('This calendar only supports ' . implode(', ', $supportedComponents) . '. We found a ' . $foundType);
+ }
+ if (!isset($component->UID)) {
+ throw new DAV\Exception\BadRequest('Every ' . $component->name . ' component must have an UID');
+ }
+ $foundUID = (string)$component->UID;
+ } else {
+ if ($foundType !== $component->name) {
+ throw new DAV\Exception\BadRequest('A calendar object must only contain 1 component. We found a ' . $component->name . ' as well as a ' . $foundType);
+ }
+ if ($foundUID !== (string)$component->UID) {
+ throw new DAV\Exception\BadRequest('Every ' . $component->name . ' in this object must have identical UIDs');
+ }
+ }
+ break;
+ default :
+ throw new DAV\Exception\BadRequest('You are not allowed to create components of type: ' . $component->name . ' here');
+
+ }
+ }
+ if (!$foundType)
+ throw new DAV\Exception\BadRequest('iCalendar object must contain at least 1 of VEVENT, VTODO or VJOURNAL');
+
+ }
+
+ /**
+ * This method handles POST requests to the schedule-outbox.
+ *
+ * Currently, two types of requests are support:
+ * * FREEBUSY requests from RFC 6638
+ * * Simple iTIP messages from draft-desruisseaux-caldav-sched-04
+ *
+ * The latter is from an expired early draft of the CalDAV scheduling
+ * extensions, but iCal depends on a feature from that spec, so we
+ * implement it.
+ *
+ * @param Schedule\IOutbox $outboxNode
+ * @param string $outboxUri
+ * @return void
+ */
+ public function outboxRequest(Schedule\IOutbox $outboxNode, $outboxUri) {
+
+ // Parsing the request body
+ try {
+ $vObject = VObject\Reader::read($this->server->httpRequest->getBody(true));
+ } catch (VObject\ParseException $e) {
+ throw new DAV\Exception\BadRequest('The request body must be a valid iCalendar object. Parse error: ' . $e->getMessage());
+ }
+
+ // The incoming iCalendar object must have a METHOD property, and a
+ // component. The combination of both determines what type of request
+ // this is.
+ $componentType = null;
+ foreach($vObject->getComponents() as $component) {
+ if ($component->name !== 'VTIMEZONE') {
+ $componentType = $component->name;
+ break;
+ }
+ }
+ if (is_null($componentType)) {
+ throw new DAV\Exception\BadRequest('We expected at least one VTODO, VJOURNAL, VFREEBUSY or VEVENT component');
+ }
+
+ // Validating the METHOD
+ $method = strtoupper((string)$vObject->METHOD);
+ if (!$method) {
+ throw new DAV\Exception\BadRequest('A METHOD property must be specified in iTIP messages');
+ }
+
+ // So we support two types of requests:
+ //
+ // REQUEST with a VFREEBUSY component
+ // REQUEST, REPLY, ADD, CANCEL on VEVENT components
+
+ $acl = $this->server->getPlugin('acl');
+
+ if ($componentType === 'VFREEBUSY' && $method === 'REQUEST') {
+
+ $acl && $acl->checkPrivileges($outboxUri,'{' . Plugin::NS_CALDAV . '}schedule-query-freebusy');
+ $this->handleFreeBusyRequest($outboxNode, $vObject);
+
+ } elseif ($componentType === 'VEVENT' && in_array($method, array('REQUEST','REPLY','ADD','CANCEL'))) {
+
+ $acl && $acl->checkPrivileges($outboxUri,'{' . Plugin::NS_CALDAV . '}schedule-post-vevent');
+ $this->handleEventNotification($outboxNode, $vObject);
+
+ } else {
+
+ throw new DAV\Exception\NotImplemented('SabreDAV supports only VFREEBUSY (REQUEST) and VEVENT (REQUEST, REPLY, ADD, CANCEL)');
+
+ }
+
+ }
+
+ /**
+ * This method handles the REQUEST, REPLY, ADD and CANCEL methods for
+ * VEVENT iTip messages.
+ *
+ * @return void
+ */
+ protected function handleEventNotification(Schedule\IOutbox $outboxNode, VObject\Component $vObject) {
+
+ $originator = $this->server->httpRequest->getHeader('Originator');
+ $recipients = $this->server->httpRequest->getHeader('Recipient');
+
+ if (!$originator) {
+ throw new DAV\Exception\BadRequest('The Originator: header must be specified when making POST requests');
+ }
+ if (!$recipients) {
+ throw new DAV\Exception\BadRequest('The Recipient: header must be specified when making POST requests');
+ }
+
+ $recipients = explode(',',$recipients);
+ foreach($recipients as $k=>$recipient) {
+
+ $recipient = trim($recipient);
+ if (!preg_match('/^mailto:(.*)@(.*)$/i', $recipient)) {
+ throw new DAV\Exception\BadRequest('Recipients must start with mailto: and must be valid email address');
+ }
+ $recipient = substr($recipient, 7);
+ $recipients[$k] = $recipient;
+ }
+
+ // We need to make sure that 'originator' matches one of the email
+ // addresses of the selected principal.
+ $principal = $outboxNode->getOwner();
+ $props = $this->server->getProperties($principal,array(
+ '{' . self::NS_CALDAV . '}calendar-user-address-set',
+ ));
+
+ $addresses = array();
+ if (isset($props['{' . self::NS_CALDAV . '}calendar-user-address-set'])) {
+ $addresses = $props['{' . self::NS_CALDAV . '}calendar-user-address-set']->getHrefs();
+ }
+
+ $found = false;
+ foreach($addresses as $address) {
+
+ // Trimming the / on both sides, just in case..
+ if (rtrim(strtolower($originator),'/') === rtrim(strtolower($address),'/')) {
+ $found = true;
+ break;
+ }
+
+ }
+
+ if (!$found) {
+ throw new DAV\Exception\Forbidden('The addresses specified in the Originator header did not match any addresses in the owners calendar-user-address-set header');
+ }
+
+ // If the Originator header was a url, and not a mailto: address..
+ // we're going to try to pull the mailto: from the vobject body.
+ if (strtolower(substr($originator,0,7)) !== 'mailto:') {
+ $originator = (string)$vObject->VEVENT->ORGANIZER;
+
+ }
+ if (strtolower(substr($originator,0,7)) !== 'mailto:') {
+ throw new DAV\Exception\Forbidden('Could not find mailto: address in both the Orignator header, and the ORGANIZER property in the VEVENT');
+ }
+ $originator = substr($originator,7);
+
+ $result = $this->iMIPMessage($originator, $recipients, $vObject, $principal);
+ $this->server->httpResponse->sendStatus(200);
+ $this->server->httpResponse->setHeader('Content-Type','application/xml');
+ $this->server->httpResponse->sendBody($this->generateScheduleResponse($result));
+
+ }
+
+ /**
+ * Sends an iMIP message by email.
+ *
+ * This method must return an array with status codes per recipient.
+ * This should look something like:
+ *
+ * array(
+ * 'user1@example.org' => '2.0;Success'
+ * )
+ *
+ * Formatting for this status code can be found at:
+ * https://tools.ietf.org/html/rfc5545#section-3.8.8.3
+ *
+ * A list of valid status codes can be found at:
+ * https://tools.ietf.org/html/rfc5546#section-3.6
+ *
+ * @param string $originator
+ * @param array $recipients
+ * @param VObject\Component $vObject
+ * @param string $principal Principal url
+ * @return array
+ */
+ protected function iMIPMessage($originator, array $recipients, VObject\Component $vObject, $principal) {
+
+ if (!$this->imipHandler) {
+ $resultStatus = '5.2;This server does not support this operation';
+ } else {
+ $this->imipHandler->sendMessage($originator, $recipients, $vObject, $principal);
+ $resultStatus = '2.0;Success';
+ }
+
+ $result = array();
+ foreach($recipients as $recipient) {
+ $result[$recipient] = $resultStatus;
+ }
+
+ return $result;
+
+ }
+
+ /**
+ * Generates a schedule-response XML body
+ *
+ * The recipients array is a key->value list, containing email addresses
+ * and iTip status codes. See the iMIPMessage method for a description of
+ * the value.
+ *
+ * @param array $recipients
+ * @return string
+ */
+ public function generateScheduleResponse(array $recipients) {
+
+ $dom = new \DOMDocument('1.0','utf-8');
+ $dom->formatOutput = true;
+ $xscheduleResponse = $dom->createElement('cal:schedule-response');
+ $dom->appendChild($xscheduleResponse);
+
+ foreach($this->server->xmlNamespaces as $namespace=>$prefix) {
+
+ $xscheduleResponse->setAttribute('xmlns:' . $prefix, $namespace);
+
+ }
+
+ foreach($recipients as $recipient=>$status) {
+ $xresponse = $dom->createElement('cal:response');
+
+ $xrecipient = $dom->createElement('cal:recipient');
+ $xrecipient->appendChild($dom->createTextNode($recipient));
+ $xresponse->appendChild($xrecipient);
+
+ $xrequestStatus = $dom->createElement('cal:request-status');
+ $xrequestStatus->appendChild($dom->createTextNode($status));
+ $xresponse->appendChild($xrequestStatus);
+
+ $xscheduleResponse->appendChild($xresponse);
+
+ }
+
+ return $dom->saveXML();
+
+ }
+
+ /**
+ * This method is responsible for parsing a free-busy query request and
+ * returning it's result.
+ *
+ * @param Schedule\IOutbox $outbox
+ * @param string $request
+ * @return string
+ */
+ protected function handleFreeBusyRequest(Schedule\IOutbox $outbox, VObject\Component $vObject) {
+
+ $vFreeBusy = $vObject->VFREEBUSY;
+ $organizer = $vFreeBusy->organizer;
+
+ $organizer = (string)$organizer;
+
+ // Validating if the organizer matches the owner of the inbox.
+ $owner = $outbox->getOwner();
+
+ $caldavNS = '{' . Plugin::NS_CALDAV . '}';
+
+ $uas = $caldavNS . 'calendar-user-address-set';
+ $props = $this->server->getProperties($owner,array($uas));
+
+ if (empty($props[$uas]) || !in_array($organizer, $props[$uas]->getHrefs())) {
+ throw new DAV\Exception\Forbidden('The organizer in the request did not match any of the addresses for the owner of this inbox');
+ }
+
+ if (!isset($vFreeBusy->ATTENDEE)) {
+ throw new DAV\Exception\BadRequest('You must at least specify 1 attendee');
+ }
+
+ $attendees = array();
+ foreach($vFreeBusy->ATTENDEE as $attendee) {
+ $attendees[]= (string)$attendee;
+ }
+
+
+ if (!isset($vFreeBusy->DTSTART) || !isset($vFreeBusy->DTEND)) {
+ throw new DAV\Exception\BadRequest('DTSTART and DTEND must both be specified');
+ }
+
+ $startRange = $vFreeBusy->DTSTART->getDateTime();
+ $endRange = $vFreeBusy->DTEND->getDateTime();
+
+ $results = array();
+ foreach($attendees as $attendee) {
+ $results[] = $this->getFreeBusyForEmail($attendee, $startRange, $endRange, $vObject);
+ }
+
+ $dom = new \DOMDocument('1.0','utf-8');
+ $dom->formatOutput = true;
+ $scheduleResponse = $dom->createElement('cal:schedule-response');
+ foreach($this->server->xmlNamespaces as $namespace=>$prefix) {
+
+ $scheduleResponse->setAttribute('xmlns:' . $prefix,$namespace);
+
+ }
+ $dom->appendChild($scheduleResponse);
+
+ foreach($results as $result) {
+ $response = $dom->createElement('cal:response');
+
+ $recipient = $dom->createElement('cal:recipient');
+ $recipientHref = $dom->createElement('d:href');
+
+ $recipientHref->appendChild($dom->createTextNode($result['href']));
+ $recipient->appendChild($recipientHref);
+ $response->appendChild($recipient);
+
+ $reqStatus = $dom->createElement('cal:request-status');
+ $reqStatus->appendChild($dom->createTextNode($result['request-status']));
+ $response->appendChild($reqStatus);
+
+ if (isset($result['calendar-data'])) {
+
+ $calendardata = $dom->createElement('cal:calendar-data');
+ $calendardata->appendChild($dom->createTextNode(str_replace("\r\n","\n",$result['calendar-data']->serialize())));
+ $response->appendChild($calendardata);
+
+ }
+ $scheduleResponse->appendChild($response);
+ }
+
+ $this->server->httpResponse->sendStatus(200);
+ $this->server->httpResponse->setHeader('Content-Type','application/xml');
+ $this->server->httpResponse->sendBody($dom->saveXML());
+
+ }
+
+ /**
+ * Returns free-busy information for a specific address. The returned
+ * data is an array containing the following properties:
+ *
+ * calendar-data : A VFREEBUSY VObject
+ * request-status : an iTip status code.
+ * href: The principal's email address, as requested
+ *
+ * The following request status codes may be returned:
+ * * 2.0;description
+ * * 3.7;description
+ *
+ * @param string $email address
+ * @param \DateTime $start
+ * @param \DateTime $end
+ * @param VObject\Component $request
+ * @return array
+ */
+ protected function getFreeBusyForEmail($email, \DateTime $start, \DateTime $end, VObject\Component $request) {
+
+ $caldavNS = '{' . Plugin::NS_CALDAV . '}';
+
+ $aclPlugin = $this->server->getPlugin('acl');
+ if (substr($email,0,7)==='mailto:') $email = substr($email,7);
+
+ $result = $aclPlugin->principalSearch(
+ array('{http://sabredav.org/ns}email-address' => $email),
+ array(
+ '{DAV:}principal-URL', $caldavNS . 'calendar-home-set',
+ '{http://sabredav.org/ns}email-address',
+ )
+ );
+
+ if (!count($result)) {
+ return array(
+ 'request-status' => '3.7;Could not find principal',
+ 'href' => 'mailto:' . $email,
+ );
+ }
+
+ if (!isset($result[0][200][$caldavNS . 'calendar-home-set'])) {
+ return array(
+ 'request-status' => '3.7;No calendar-home-set property found',
+ 'href' => 'mailto:' . $email,
+ );
+ }
+ $homeSet = $result[0][200][$caldavNS . 'calendar-home-set']->getHref();
+
+ // Grabbing the calendar list
+ $objects = array();
+ foreach($this->server->tree->getNodeForPath($homeSet)->getChildren() as $node) {
+ if (!$node instanceof ICalendar) {
+ continue;
+ }
+ $aclPlugin->checkPrivileges($homeSet . $node->getName() ,$caldavNS . 'read-free-busy');
+
+ // Getting the list of object uris within the time-range
+ $urls = $node->calendarQuery(array(
+ 'name' => 'VCALENDAR',
+ 'comp-filters' => array(
+ array(
+ 'name' => 'VEVENT',
+ 'comp-filters' => array(),
+ 'prop-filters' => array(),
+ 'is-not-defined' => false,
+ 'time-range' => array(
+ 'start' => $start,
+ 'end' => $end,
+ ),
+ ),
+ ),
+ 'prop-filters' => array(),
+ 'is-not-defined' => false,
+ 'time-range' => null,
+ ));
+
+ $calObjects = array_map(function($url) use ($node) {
+ $obj = $node->getChild($url)->get();
+ return $obj;
+ }, $urls);
+
+ $objects = array_merge($objects,$calObjects);
+
+ }
+
+ $vcalendar = new VObject\Component\VCalendar();
+ $vcalendar->VERSION = '2.0';
+ $vcalendar->METHOD = 'REPLY';
+ $vcalendar->CALSCALE = 'GREGORIAN';
+ $vcalendar->PRODID = '-//SabreDAV//SabreDAV ' . DAV\Version::VERSION . '//EN';
+
+ $generator = new VObject\FreeBusyGenerator();
+ $generator->setObjects($objects);
+ $generator->setTimeRange($start, $end);
+ $generator->setBaseObject($vcalendar);
+
+ $result = $generator->getResult();
+
+ $vcalendar->VFREEBUSY->ATTENDEE = 'mailto:' . $email;
+ $vcalendar->VFREEBUSY->UID = (string)$request->VFREEBUSY->UID;
+ $vcalendar->VFREEBUSY->ORGANIZER = clone $request->VFREEBUSY->ORGANIZER;
+
+ return array(
+ 'calendar-data' => $result,
+ 'request-status' => '2.0;Success',
+ 'href' => 'mailto:' . $email,
+ );
+ }
+
+ /**
+ * This method is used to generate HTML output for the
+ * DAV\Browser\Plugin. This allows us to generate an interface users
+ * can use to create new calendars.
+ *
+ * @param DAV\INode $node
+ * @param string $output
+ * @return bool
+ */
+ public function htmlActionsPanel(DAV\INode $node, &$output) {
+
+ if (!$node instanceof UserCalendars)
+ return;
+
+ $output.= '
+ ';
+
+ return false;
+
+ }
+
+ /**
+ * This method allows us to intercept the 'mkcalendar' sabreAction. This
+ * action enables the user to create new calendars from the browser plugin.
+ *
+ * @param string $uri
+ * @param string $action
+ * @param array $postVars
+ * @return bool
+ */
+ public function browserPostAction($uri, $action, array $postVars) {
+
+ if ($action!=='mkcalendar')
+ return;
+
+ $resourceType = array('{DAV:}collection','{urn:ietf:params:xml:ns:caldav}calendar');
+ $properties = array();
+ if (isset($postVars['{DAV:}displayname'])) {
+ $properties['{DAV:}displayname'] = $postVars['{DAV:}displayname'];
+ }
+ $this->server->createCollection($uri . '/' . $postVars['name'],$resourceType,$properties);
+ return false;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Principal/Collection.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Principal/Collection.php
new file mode 100644
index 0000000..e4559c8
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Principal/Collection.php
@@ -0,0 +1,32 @@
+principalBackend, $principalInfo);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyRead.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyRead.php
new file mode 100644
index 0000000..f2215eb
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Principal/IProxyRead.php
@@ -0,0 +1,19 @@
+principalInfo = $principalInfo;
+ $this->principalBackend = $principalBackend;
+
+ }
+
+ /**
+ * Returns this principals name.
+ *
+ * @return string
+ */
+ public function getName() {
+
+ return 'calendar-proxy-read';
+
+ }
+
+ /**
+ * Returns the last modification time
+ *
+ * @return null
+ */
+ public function getLastModified() {
+
+ return null;
+
+ }
+
+ /**
+ * Deletes the current node
+ *
+ * @throws DAV\Exception\Forbidden
+ * @return void
+ */
+ public function delete() {
+
+ throw new DAV\Exception\Forbidden('Permission denied to delete node');
+
+ }
+
+ /**
+ * Renames the node
+ *
+ * @throws DAV\Exception\Forbidden
+ * @param string $name The new name
+ * @return void
+ */
+ public function setName($name) {
+
+ throw new DAV\Exception\Forbidden('Permission denied to rename file');
+
+ }
+
+
+ /**
+ * Returns a list of alternative urls for a principal
+ *
+ * This can for example be an email address, or ldap url.
+ *
+ * @return array
+ */
+ public function getAlternateUriSet() {
+
+ return array();
+
+ }
+
+ /**
+ * Returns the full principal url
+ *
+ * @return string
+ */
+ public function getPrincipalUrl() {
+
+ return $this->principalInfo['uri'] . '/' . $this->getName();
+
+ }
+
+ /**
+ * Returns the list of group members
+ *
+ * If this principal is a group, this function should return
+ * all member principal uri's for the group.
+ *
+ * @return array
+ */
+ public function getGroupMemberSet() {
+
+ return $this->principalBackend->getGroupMemberSet($this->getPrincipalUrl());
+
+ }
+
+ /**
+ * Returns the list of groups this principal is member of
+ *
+ * If this principal is a member of a (list of) groups, this function
+ * should return a list of principal uri's for it's members.
+ *
+ * @return array
+ */
+ public function getGroupMembership() {
+
+ return $this->principalBackend->getGroupMembership($this->getPrincipalUrl());
+
+ }
+
+ /**
+ * Sets a list of group members
+ *
+ * If this principal is a group, this method sets all the group members.
+ * The list of members is always overwritten, never appended to.
+ *
+ * This method should throw an exception if the members could not be set.
+ *
+ * @param array $principals
+ * @return void
+ */
+ public function setGroupMemberSet(array $principals) {
+
+ $this->principalBackend->setGroupMemberSet($this->getPrincipalUrl(), $principals);
+
+ }
+
+ /**
+ * Returns the displayname
+ *
+ * This should be a human readable name for the principal.
+ * If none is available, return the nodename.
+ *
+ * @return string
+ */
+ public function getDisplayName() {
+
+ return $this->getName();
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyWrite.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyWrite.php
new file mode 100644
index 0000000..1ebaf6a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Principal/ProxyWrite.php
@@ -0,0 +1,180 @@
+principalInfo = $principalInfo;
+ $this->principalBackend = $principalBackend;
+
+ }
+
+ /**
+ * Returns this principals name.
+ *
+ * @return string
+ */
+ public function getName() {
+
+ return 'calendar-proxy-write';
+
+ }
+
+ /**
+ * Returns the last modification time
+ *
+ * @return null
+ */
+ public function getLastModified() {
+
+ return null;
+
+ }
+
+ /**
+ * Deletes the current node
+ *
+ * @throws DAV\Exception\Forbidden
+ * @return void
+ */
+ public function delete() {
+
+ throw new DAV\Exception\Forbidden('Permission denied to delete node');
+
+ }
+
+ /**
+ * Renames the node
+ *
+ * @throws DAV\Exception\Forbidden
+ * @param string $name The new name
+ * @return void
+ */
+ public function setName($name) {
+
+ throw new DAV\Exception\Forbidden('Permission denied to rename file');
+
+ }
+
+
+ /**
+ * Returns a list of alternative urls for a principal
+ *
+ * This can for example be an email address, or ldap url.
+ *
+ * @return array
+ */
+ public function getAlternateUriSet() {
+
+ return array();
+
+ }
+
+ /**
+ * Returns the full principal url
+ *
+ * @return string
+ */
+ public function getPrincipalUrl() {
+
+ return $this->principalInfo['uri'] . '/' . $this->getName();
+
+ }
+
+ /**
+ * Returns the list of group members
+ *
+ * If this principal is a group, this function should return
+ * all member principal uri's for the group.
+ *
+ * @return array
+ */
+ public function getGroupMemberSet() {
+
+ return $this->principalBackend->getGroupMemberSet($this->getPrincipalUrl());
+
+ }
+
+ /**
+ * Returns the list of groups this principal is member of
+ *
+ * If this principal is a member of a (list of) groups, this function
+ * should return a list of principal uri's for it's members.
+ *
+ * @return array
+ */
+ public function getGroupMembership() {
+
+ return $this->principalBackend->getGroupMembership($this->getPrincipalUrl());
+
+ }
+
+ /**
+ * Sets a list of group members
+ *
+ * If this principal is a group, this method sets all the group members.
+ * The list of members is always overwritten, never appended to.
+ *
+ * This method should throw an exception if the members could not be set.
+ *
+ * @param array $principals
+ * @return void
+ */
+ public function setGroupMemberSet(array $principals) {
+
+ $this->principalBackend->setGroupMemberSet($this->getPrincipalUrl(), $principals);
+
+ }
+
+ /**
+ * Returns the displayname
+ *
+ * This should be a human readable name for the principal.
+ * If none is available, return the nodename.
+ *
+ * @return string
+ */
+ public function getDisplayName() {
+
+ return $this->getName();
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Principal/User.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Principal/User.php
new file mode 100644
index 0000000..1887f8a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Principal/User.php
@@ -0,0 +1,134 @@
+principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/' . $name);
+ if (!$principal) {
+ throw new DAV\Exception\NotFound('Node with name ' . $name . ' was not found');
+ }
+ if ($name === 'calendar-proxy-read')
+ return new ProxyRead($this->principalBackend, $this->principalProperties);
+
+ if ($name === 'calendar-proxy-write')
+ return new ProxyWrite($this->principalBackend, $this->principalProperties);
+
+ throw new DAV\Exception\NotFound('Node with name ' . $name . ' was not found');
+
+ }
+
+ /**
+ * Returns an array with all the child nodes
+ *
+ * @return DAV\INode[]
+ */
+ public function getChildren() {
+
+ $r = array();
+ if ($this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/calendar-proxy-read')) {
+ $r[] = new ProxyRead($this->principalBackend, $this->principalProperties);
+ }
+ if ($this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/calendar-proxy-write')) {
+ $r[] = new ProxyWrite($this->principalBackend, $this->principalProperties);
+ }
+
+ return $r;
+
+ }
+
+ /**
+ * Returns whether or not the child node exists
+ *
+ * @param string $name
+ * @return bool
+ */
+ public function childExists($name) {
+
+ try {
+ $this->getChild($name);
+ return true;
+ } catch (DAV\Exception\NotFound $e) {
+ return false;
+ }
+
+ }
+
+ /**
+ * Returns a list of ACE's for this node.
+ *
+ * Each ACE has the following properties:
+ * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
+ * currently the only supported privileges
+ * * 'principal', a url to the principal who owns the node
+ * * 'protected' (optional), indicating that this ACE is not allowed to
+ * be updated.
+ *
+ * @return array
+ */
+ public function getACL() {
+
+ $acl = parent::getACL();
+ $acl[] = array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->principalProperties['uri'] . '/calendar-proxy-read',
+ 'protected' => true,
+ );
+ $acl[] = array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->principalProperties['uri'] . '/calendar-proxy-write',
+ 'protected' => true,
+ );
+ return $acl;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/AllowedSharingModes.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/AllowedSharingModes.php
new file mode 100644
index 0000000..97b888a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/AllowedSharingModes.php
@@ -0,0 +1,74 @@
+canBeShared = $canBeShared;
+ $this->canBePublished = $canBePublished;
+
+ }
+
+ /**
+ * Serializes the property in a DOMDocument
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $node
+ * @return void
+ */
+ public function serialize(DAV\Server $server, \DOMElement $node) {
+
+ $doc = $node->ownerDocument;
+ if ($this->canBeShared) {
+ $xcomp = $doc->createElement('cs:can-be-shared');
+ $node->appendChild($xcomp);
+ }
+ if ($this->canBePublished) {
+ $xcomp = $doc->createElement('cs:can-be-published');
+ $node->appendChild($xcomp);
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/Invite.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/Invite.php
new file mode 100644
index 0000000..7a8683a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/Invite.php
@@ -0,0 +1,227 @@
+users = $users;
+ $this->organizer = $organizer;
+
+ }
+
+ /**
+ * Returns the list of users, as it was passed to the constructor.
+ *
+ * @return array
+ */
+ public function getValue() {
+
+ return $this->users;
+
+ }
+
+ /**
+ * Serializes the property in a DOMDocument
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $node
+ * @return void
+ */
+ public function serialize(DAV\Server $server,\DOMElement $node) {
+
+ $doc = $node->ownerDocument;
+
+ if (!is_null($this->organizer)) {
+
+ $xorganizer = $doc->createElement('cs:organizer');
+
+ $href = $doc->createElement('d:href');
+ $href->appendChild($doc->createTextNode($this->organizer['href']));
+ $xorganizer->appendChild($href);
+
+ if (isset($this->organizer['commonName']) && $this->organizer['commonName']) {
+ $commonName = $doc->createElement('cs:common-name');
+ $commonName->appendChild($doc->createTextNode($this->organizer['commonName']));
+ $xorganizer->appendChild($commonName);
+ }
+ if (isset($this->organizer['firstName']) && $this->organizer['firstName']) {
+ $firstName = $doc->createElement('cs:first-name');
+ $firstName->appendChild($doc->createTextNode($this->organizer['firstName']));
+ $xorganizer->appendChild($firstName);
+ }
+ if (isset($this->organizer['lastName']) && $this->organizer['lastName']) {
+ $lastName = $doc->createElement('cs:last-name');
+ $lastName->appendChild($doc->createTextNode($this->organizer['lastName']));
+ $xorganizer->appendChild($lastName);
+ }
+
+ $node->appendChild($xorganizer);
+
+
+ }
+
+ foreach($this->users as $user) {
+
+ $xuser = $doc->createElement('cs:user');
+
+ $href = $doc->createElement('d:href');
+ $href->appendChild($doc->createTextNode($user['href']));
+ $xuser->appendChild($href);
+
+ if (isset($user['commonName']) && $user['commonName']) {
+ $commonName = $doc->createElement('cs:common-name');
+ $commonName->appendChild($doc->createTextNode($user['commonName']));
+ $xuser->appendChild($commonName);
+ }
+
+ switch($user['status']) {
+
+ case SharingPlugin::STATUS_ACCEPTED :
+ $status = $doc->createElement('cs:invite-accepted');
+ $xuser->appendChild($status);
+ break;
+ case SharingPlugin::STATUS_DECLINED :
+ $status = $doc->createElement('cs:invite-declined');
+ $xuser->appendChild($status);
+ break;
+ case SharingPlugin::STATUS_NORESPONSE :
+ $status = $doc->createElement('cs:invite-noresponse');
+ $xuser->appendChild($status);
+ break;
+ case SharingPlugin::STATUS_INVALID :
+ $status = $doc->createElement('cs:invite-invalid');
+ $xuser->appendChild($status);
+ break;
+
+ }
+
+ $xaccess = $doc->createElement('cs:access');
+
+ if ($user['readOnly']) {
+ $xaccess->appendChild(
+ $doc->createElement('cs:read')
+ );
+ } else {
+ $xaccess->appendChild(
+ $doc->createElement('cs:read-write')
+ );
+ }
+ $xuser->appendChild($xaccess);
+
+ if (isset($user['summary']) && $user['summary']) {
+ $summary = $doc->createElement('cs:summary');
+ $summary->appendChild($doc->createTextNode($user['summary']));
+ $xuser->appendChild($summary);
+ }
+
+ $node->appendChild($xuser);
+
+ }
+
+
+ }
+
+ /**
+ * Unserializes the property.
+ *
+ * This static method should return a an instance of this object.
+ *
+ * @param \DOMElement $prop
+ * @return DAV\IProperty
+ */
+ static function unserialize(\DOMElement $prop) {
+
+ $xpath = new \DOMXPath($prop->ownerDocument);
+ $xpath->registerNamespace('cs', CalDAV\Plugin::NS_CALENDARSERVER);
+ $xpath->registerNamespace('d', 'urn:DAV');
+
+ $users = array();
+
+ foreach($xpath->query('cs:user', $prop) as $user) {
+
+ $status = null;
+ if ($xpath->evaluate('boolean(cs:invite-accepted)', $user)) {
+ $status = SharingPlugin::STATUS_ACCEPTED;
+ } elseif ($xpath->evaluate('boolean(cs:invite-declined)', $user)) {
+ $status = SharingPlugin::STATUS_DECLINED;
+ } elseif ($xpath->evaluate('boolean(cs:invite-noresponse)', $user)) {
+ $status = SharingPlugin::STATUS_NORESPONSE;
+ } elseif ($xpath->evaluate('boolean(cs:invite-invalid)', $user)) {
+ $status = SharingPlugin::STATUS_INVALID;
+ } else {
+ throw new DAV\Exception('Every cs:user property must have one of cs:invite-accepted, cs:invite-declined, cs:invite-noresponse or cs:invite-invalid');
+ }
+ $users[] = array(
+ 'href' => $xpath->evaluate('string(d:href)', $user),
+ 'commonName' => $xpath->evaluate('string(cs:common-name)', $user),
+ 'readOnly' => $xpath->evaluate('boolean(cs:access/cs:read)', $user),
+ 'summary' => $xpath->evaluate('string(cs:summary)', $user),
+ 'status' => $status,
+ );
+
+ }
+
+ return new self($users);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/ScheduleCalendarTransp.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/ScheduleCalendarTransp.php
new file mode 100644
index 0000000..328ac76
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/ScheduleCalendarTransp.php
@@ -0,0 +1,102 @@
+value = $value;
+
+ }
+
+ /**
+ * Returns the current value
+ *
+ * @return string
+ */
+ public function getValue() {
+
+ return $this->value;
+
+ }
+
+ /**
+ * Serializes the property in a DOMDocument
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $node
+ * @return void
+ */
+ public function serialize(DAV\Server $server,\DOMElement $node) {
+
+ $doc = $node->ownerDocument;
+ switch($this->value) {
+ case self::TRANSPARENT :
+ $xval = $doc->createElement('cal:transparent');
+ break;
+ case self::OPAQUE :
+ $xval = $doc->createElement('cal:opaque');
+ break;
+ }
+
+ $node->appendChild($xval);
+
+ }
+
+ /**
+ * Unserializes the DOMElement back into a Property class.
+ *
+ * @param \DOMElement $node
+ * @return ScheduleCalendarTransp
+ */
+ static function unserialize(\DOMElement $node) {
+
+ $value = null;
+ foreach($node->childNodes as $childNode) {
+ switch(DAV\XMLUtil::toClarkNotation($childNode)) {
+ case '{' . CalDAV\Plugin::NS_CALDAV . '}opaque' :
+ $value = self::OPAQUE;
+ break;
+ case '{' . CalDAV\Plugin::NS_CALDAV . '}transparent' :
+ $value = self::TRANSPARENT;
+ break;
+ }
+ }
+ if (is_null($value))
+ return null;
+
+ return new self($value);
+
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarComponentSet.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarComponentSet.php
new file mode 100644
index 0000000..c533762
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarComponentSet.php
@@ -0,0 +1,88 @@
+components = $components;
+
+ }
+
+ /**
+ * Returns the list of supported components
+ *
+ * @return array
+ */
+ public function getValue() {
+
+ return $this->components;
+
+ }
+
+ /**
+ * Serializes the property in a DOMDocument
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $node
+ * @return void
+ */
+ public function serialize(DAV\Server $server,\DOMElement $node) {
+
+ $doc = $node->ownerDocument;
+ foreach($this->components as $component) {
+
+ $xcomp = $doc->createElement('cal:comp');
+ $xcomp->setAttribute('name',$component);
+ $node->appendChild($xcomp);
+
+ }
+
+ }
+
+ /**
+ * Unserializes the DOMElement back into a Property class.
+ *
+ * @param \DOMElement $node
+ * @return Property_SupportedCalendarComponentSet
+ */
+ static function unserialize(\DOMElement $node) {
+
+ $components = array();
+ foreach($node->childNodes as $childNode) {
+ if (DAV\XMLUtil::toClarkNotation($childNode)==='{' . CalDAV\Plugin::NS_CALDAV . '}comp') {
+ $components[] = $childNode->getAttribute('name');
+ }
+ }
+ return new self($components);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarData.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarData.php
new file mode 100644
index 0000000..ed742da
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCalendarData.php
@@ -0,0 +1,40 @@
+ownerDocument;
+
+ $prefix = isset($server->xmlNamespaces[Plugin::NS_CALDAV])?$server->xmlNamespaces[Plugin::NS_CALDAV]:'cal';
+
+ $caldata = $doc->createElement($prefix . ':calendar-data');
+ $caldata->setAttribute('content-type','text/calendar');
+ $caldata->setAttribute('version','2.0');
+
+ $node->appendChild($caldata);
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCollationSet.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCollationSet.php
new file mode 100644
index 0000000..7c853f2
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Property/SupportedCollationSet.php
@@ -0,0 +1,45 @@
+ownerDocument;
+
+ $prefix = $node->lookupPrefix('urn:ietf:params:xml:ns:caldav');
+ if (!$prefix) $prefix = 'cal';
+
+ $node->appendChild(
+ $doc->createElement($prefix . ':supported-collation','i;ascii-casemap')
+ );
+ $node->appendChild(
+ $doc->createElement($prefix . ':supported-collation','i;octet')
+ );
+ $node->appendChild(
+ $doc->createElement($prefix . ':supported-collation','i;unicode-casemap')
+ );
+
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Schedule/IMip.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Schedule/IMip.php
new file mode 100644
index 0000000..0efacff
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Schedule/IMip.php
@@ -0,0 +1,111 @@
+senderEmail = $senderEmail;
+
+ }
+
+ /**
+ * Sends one or more iTip messages through email.
+ *
+ * @param string $originator Originator Email
+ * @param array $recipients Array of email addresses
+ * @param VObject\Component $vObject
+ * @param string $principal Principal Url of the originator
+ * @return void
+ */
+ public function sendMessage($originator, array $recipients, VObject\Component $vObject, $principal) {
+
+ foreach($recipients as $recipient) {
+
+ $to = $recipient;
+ $replyTo = $originator;
+ $subject = 'SabreDAV iTIP message';
+
+ switch(strtoupper($vObject->METHOD)) {
+ case 'REPLY' :
+ $subject = 'Response for: ' . $vObject->VEVENT->SUMMARY;
+ break;
+ case 'REQUEST' :
+ $subject = 'Invitation for: ' .$vObject->VEVENT->SUMMARY;
+ break;
+ case 'CANCEL' :
+ $subject = 'Cancelled event: ' . $vObject->VEVENT->SUMMARY;
+ break;
+ }
+
+ $headers = array();
+ $headers[] = 'Reply-To: ' . $replyTo;
+ $headers[] = 'From: ' . $this->senderEmail;
+ $headers[] = 'Content-Type: text/calendar; method=' . (string)$vObject->method . '; charset=utf-8';
+ if (DAV\Server::$exposeVersion) {
+ $headers[] = 'X-Sabre-Version: ' . DAV\Version::VERSION . '-' . DAV\Version::STABILITY;
+ }
+
+ $vcalBody = $vObject->serialize();
+
+ $this->mail($to, $subject, $vcalBody, $headers);
+
+ }
+
+ }
+
+ // @codeCoverageIgnoreStart
+ // This is deemed untestable in a reasonable manner
+
+ /**
+ * This function is reponsible for sending the actual email.
+ *
+ * @param string $to Recipient email address
+ * @param string $subject Subject of the email
+ * @param string $body iCalendar body
+ * @param array $headers List of headers
+ * @return void
+ */
+ protected function mail($to, $subject, $body, array $headers) {
+
+
+ mail($to, $subject, $body, implode("\r\n", $headers));
+
+ }
+
+ // @codeCoverageIgnoreEnd
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Schedule/IOutbox.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Schedule/IOutbox.php
new file mode 100644
index 0000000..e9edc51
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Schedule/IOutbox.php
@@ -0,0 +1,16 @@
+principalUri = $principalUri;
+
+ }
+
+ /**
+ * Returns the name of the node.
+ *
+ * This is used to generate the url.
+ *
+ * @return string
+ */
+ public function getName() {
+
+ return 'outbox';
+
+ }
+
+ /**
+ * Returns an array with all the child nodes
+ *
+ * @return \SabreForRainLoop\DAV\INode[]
+ */
+ public function getChildren() {
+
+ return array();
+
+ }
+
+ /**
+ * Returns the owner principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getOwner() {
+
+ return $this->principalUri;
+
+ }
+
+ /**
+ * Returns a group principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getGroup() {
+
+ return null;
+
+ }
+
+ /**
+ * Returns a list of ACE's for this node.
+ *
+ * Each ACE has the following properties:
+ * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
+ * currently the only supported privileges
+ * * 'principal', a url to the principal who owns the node
+ * * 'protected' (optional), indicating that this ACE is not allowed to
+ * be updated.
+ *
+ * @return array
+ */
+ public function getACL() {
+
+ return array(
+ array(
+ 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
+ 'principal' => $this->getOwner(),
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
+ 'principal' => $this->getOwner(),
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->getOwner(),
+ 'protected' => true,
+ ),
+ );
+
+ }
+
+ /**
+ * Updates the ACL
+ *
+ * This method will receive a list of new ACE's.
+ *
+ * @param array $acl
+ * @return void
+ */
+ public function setACL(array $acl) {
+
+ throw new DAV\Exception\MethodNotAllowed('You\'re not allowed to update the ACL');
+
+ }
+
+ /**
+ * Returns the list of supported privileges for this node.
+ *
+ * The returned data structure is a list of nested privileges.
+ * See SabreForRainLoop\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
+ * standard structure.
+ *
+ * If null is returned from this method, the default privilege set is used,
+ * which is fine for most common usecases.
+ *
+ * @return array|null
+ */
+ public function getSupportedPrivilegeSet() {
+
+ $default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet();
+ $default['aggregates'][] = array(
+ 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
+ );
+ $default['aggregates'][] = array(
+ 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
+ );
+
+ return $default;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/ShareableCalendar.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/ShareableCalendar.php
new file mode 100644
index 0000000..43b051a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/ShareableCalendar.php
@@ -0,0 +1,72 @@
+caldavBackend->updateShares($this->calendarInfo['id'], $add, $remove);
+
+ }
+
+ /**
+ * Returns the list of people whom this calendar is shared with.
+ *
+ * Every element in this array should have the following properties:
+ * * href - Often a mailto: address
+ * * commonName - Optional, for example a first + last name
+ * * status - See the SabreForRainLoop\CalDAV\SharingPlugin::STATUS_ constants.
+ * * readOnly - boolean
+ * * summary - Optional, a description for the share
+ *
+ * @return array
+ */
+ public function getShares() {
+
+ return $this->caldavBackend->getShares($this->calendarInfo['id']);
+
+ }
+
+ /**
+ * Marks this calendar as published.
+ *
+ * Publishing a calendar should automatically create a read-only, public,
+ * subscribable calendar.
+ *
+ * @param bool $value
+ * @return void
+ */
+ public function setPublishStatus($value) {
+
+ $this->caldavBackend->setPublishStatus($this->calendarInfo['id'], $value);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/SharedCalendar.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/SharedCalendar.php
new file mode 100644
index 0000000..fda7515
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/SharedCalendar.php
@@ -0,0 +1,116 @@
+calendarInfo['{http://calendarserver.org/ns/}shared-url'];
+
+ }
+
+ /**
+ * Returns the owner principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getOwner() {
+
+ return $this->calendarInfo['{http://sabredav.org/ns}owner-principal'];
+
+ }
+
+ /**
+ * Returns a list of ACE's for this node.
+ *
+ * Each ACE has the following properties:
+ * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
+ * currently the only supported privileges
+ * * 'principal', a url to the principal who owns the node
+ * * 'protected' (optional), indicating that this ACE is not allowed to
+ * be updated.
+ *
+ * @return array
+ */
+ public function getACL() {
+
+ // The top-level ACL only contains access information for the true
+ // owner of the calendar, so we need to add the information for the
+ // sharee.
+ $acl = parent::getACL();
+ $acl[] = array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->calendarInfo['principaluri'],
+ 'protected' => true,
+ );
+ if (!$this->calendarInfo['{http://sabredav.org/ns}read-only']) {
+ $acl[] = array(
+ 'privilege' => '{DAV:}write',
+ 'principal' => $this->calendarInfo['principaluri'],
+ 'protected' => true,
+ );
+ }
+ return $acl;
+
+ }
+
+ /**
+ * Returns the list of people whom this calendar is shared with.
+ *
+ * Every element in this array should have the following properties:
+ * * href - Often a mailto: address
+ * * commonName - Optional, for example a first + last name
+ * * status - See the SabreForRainLoop\CalDAV\SharingPlugin::STATUS_ constants.
+ * * readOnly - boolean
+ * * summary - Optional, a description for the share
+ *
+ * @return array
+ */
+ public function getShares() {
+
+ return $this->caldavBackend->getShares($this->calendarInfo['id']);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/SharingPlugin.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/SharingPlugin.php
new file mode 100644
index 0000000..7a89075
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/SharingPlugin.php
@@ -0,0 +1,526 @@
+server = $server;
+ $server->resourceTypeMapping['SabreForRainLoop\\CalDAV\\ISharedCalendar'] = '{' . Plugin::NS_CALENDARSERVER . '}shared';
+
+ array_push(
+ $this->server->protectedProperties,
+ '{' . Plugin::NS_CALENDARSERVER . '}invite',
+ '{' . Plugin::NS_CALENDARSERVER . '}allowed-sharing-modes',
+ '{' . Plugin::NS_CALENDARSERVER . '}shared-url'
+ );
+
+ $this->server->subscribeEvent('beforeGetProperties', array($this, 'beforeGetProperties'));
+ $this->server->subscribeEvent('afterGetProperties', array($this, 'afterGetProperties'));
+ $this->server->subscribeEvent('updateProperties', array($this, 'updateProperties'));
+ $this->server->subscribeEvent('unknownMethod', array($this,'unknownMethod'));
+
+ }
+
+ /**
+ * This event is triggered when properties are requested for a certain
+ * node.
+ *
+ * This allows us to inject any properties early.
+ *
+ * @param string $path
+ * @param DAV\INode $node
+ * @param array $requestedProperties
+ * @param array $returnedProperties
+ * @return void
+ */
+ public function beforeGetProperties($path, DAV\INode $node, &$requestedProperties, &$returnedProperties) {
+
+ if ($node instanceof IShareableCalendar) {
+ if (($index = array_search('{' . Plugin::NS_CALENDARSERVER . '}invite', $requestedProperties))!==false) {
+
+ unset($requestedProperties[$index]);
+ $returnedProperties[200]['{' . Plugin::NS_CALENDARSERVER . '}invite'] =
+ new Property\Invite(
+ $node->getShares()
+ );
+
+ }
+
+ }
+
+ if ($node instanceof ISharedCalendar) {
+
+ if (($index = array_search('{' . Plugin::NS_CALENDARSERVER . '}shared-url', $requestedProperties))!==false) {
+
+ unset($requestedProperties[$index]);
+ $returnedProperties[200]['{' . Plugin::NS_CALENDARSERVER . '}shared-url'] =
+ new DAV\Property\Href(
+ $node->getSharedUrl()
+ );
+
+ }
+ // The 'invite' property is slightly different for the 'shared'
+ // instance of the calendar, as it also contains the owner
+ // information.
+ if (($index = array_search('{' . Plugin::NS_CALENDARSERVER . '}invite', $requestedProperties))!==false) {
+
+ unset($requestedProperties[$index]);
+
+ // Fetching owner information
+ $props = $this->server->getPropertiesForPath($node->getOwner(), array(
+ '{http://sabredav.org/ns}email-address',
+ '{DAV:}displayname',
+ ), 1);
+
+ $ownerInfo = array(
+ 'href' => $node->getOwner(),
+ );
+
+ if (isset($props[0][200])) {
+
+ // We're mapping the internal webdav properties to the
+ // elements caldav-sharing expects.
+ if (isset($props[0][200]['{http://sabredav.org/ns}email-address'])) {
+ $ownerInfo['href'] = 'mailto:' . $props[0][200]['{http://sabredav.org/ns}email-address'];
+ }
+ if (isset($props[0][200]['{DAV:}displayname'])) {
+ $ownerInfo['commonName'] = $props[0][200]['{DAV:}displayname'];
+ }
+
+ }
+
+ $returnedProperties[200]['{' . Plugin::NS_CALENDARSERVER . '}invite'] =
+ new Property\Invite(
+ $node->getShares(),
+ $ownerInfo
+ );
+
+ }
+
+
+ }
+
+ }
+
+ /**
+ * This method is triggered *after* all properties have been retrieved.
+ * This allows us to inject the correct resourcetype for calendars that
+ * have been shared.
+ *
+ * @param string $path
+ * @param array $properties
+ * @param DAV\INode $node
+ * @return void
+ */
+ public function afterGetProperties($path, &$properties, DAV\INode $node) {
+
+ if ($node instanceof IShareableCalendar) {
+ if (isset($properties[200]['{DAV:}resourcetype'])) {
+ if (count($node->getShares())>0) {
+ $properties[200]['{DAV:}resourcetype']->add(
+ '{' . Plugin::NS_CALENDARSERVER . '}shared-owner'
+ );
+ }
+ }
+ $propName = '{' . Plugin::NS_CALENDARSERVER . '}allowed-sharing-modes';
+ if (array_key_exists($propName, $properties[404])) {
+ unset($properties[404][$propName]);
+ $properties[200][$propName] = new Property\AllowedSharingModes(true,false);
+ }
+
+ }
+
+ }
+
+ /**
+ * This method is trigged when a user attempts to update a node's
+ * properties.
+ *
+ * A previous draft of the sharing spec stated that it was possible to use
+ * PROPPATCH to remove 'shared-owner' from the resourcetype, thus unsharing
+ * the calendar.
+ *
+ * Even though this is no longer in the current spec, we keep this around
+ * because OS X 10.7 may still make use of this feature.
+ *
+ * @param array $mutations
+ * @param array $result
+ * @param DAV\INode $node
+ * @return void
+ */
+ public function updateProperties(array &$mutations, array &$result, DAV\INode $node) {
+
+ if (!$node instanceof IShareableCalendar)
+ return;
+
+ if (!isset($mutations['{DAV:}resourcetype'])) {
+ return;
+ }
+
+ // Only doing something if shared-owner is indeed not in the list.
+ if($mutations['{DAV:}resourcetype']->is('{' . Plugin::NS_CALENDARSERVER . '}shared-owner')) return;
+
+ $shares = $node->getShares();
+ $remove = array();
+ foreach($shares as $share) {
+ $remove[] = $share['href'];
+ }
+ $node->updateShares(array(), $remove);
+
+ // We're marking this update as 200 OK
+ $result[200]['{DAV:}resourcetype'] = null;
+
+ // Removing it from the mutations list
+ unset($mutations['{DAV:}resourcetype']);
+
+ }
+
+ /**
+ * This event is triggered when the server didn't know how to handle a
+ * certain request.
+ *
+ * We intercept this to handle POST requests on calendars.
+ *
+ * @param string $method
+ * @param string $uri
+ * @return null|bool
+ */
+ public function unknownMethod($method, $uri) {
+
+ if ($method!=='POST') {
+ return;
+ }
+
+ // Only handling xml
+ $contentType = $this->server->httpRequest->getHeader('Content-Type');
+ if (strpos($contentType,'application/xml')===false && strpos($contentType,'text/xml')===false)
+ return;
+
+ // Making sure the node exists
+ try {
+ $node = $this->server->tree->getNodeForPath($uri);
+ } catch (DAV\Exception\NotFound $e) {
+ return;
+ }
+
+ $requestBody = $this->server->httpRequest->getBody(true);
+
+ // If this request handler could not deal with this POST request, it
+ // will return 'null' and other plugins get a chance to handle the
+ // request.
+ //
+ // However, we already requested the full body. This is a problem,
+ // because a body can only be read once. This is why we preemptively
+ // re-populated the request body with the existing data.
+ $this->server->httpRequest->setBody($requestBody);
+
+ $dom = DAV\XMLUtil::loadDOMDocument($requestBody);
+
+ $documentType = DAV\XMLUtil::toClarkNotation($dom->firstChild);
+
+ switch($documentType) {
+
+ // Dealing with the 'share' document, which modified invitees on a
+ // calendar.
+ case '{' . Plugin::NS_CALENDARSERVER . '}share' :
+
+ // We can only deal with IShareableCalendar objects
+ if (!$node instanceof IShareableCalendar) {
+ return;
+ }
+
+ // Getting ACL info
+ $acl = $this->server->getPlugin('acl');
+
+ // If there's no ACL support, we allow everything
+ if ($acl) {
+ $acl->checkPrivileges($uri, '{DAV:}write');
+ }
+
+ $mutations = $this->parseShareRequest($dom);
+
+ $node->updateShares($mutations[0], $mutations[1]);
+
+ $this->server->httpResponse->sendStatus(200);
+ // Adding this because sending a response body may cause issues,
+ // and I wanted some type of indicator the response was handled.
+ $this->server->httpResponse->setHeader('X-Sabre-Status', 'everything-went-well');
+
+ // Breaking the event chain
+ return false;
+
+ // The invite-reply document is sent when the user replies to an
+ // invitation of a calendar share.
+ case '{'. Plugin::NS_CALENDARSERVER.'}invite-reply' :
+
+ // This only works on the calendar-home-root node.
+ if (!$node instanceof UserCalendars) {
+ return;
+ }
+
+ // Getting ACL info
+ $acl = $this->server->getPlugin('acl');
+
+ // If there's no ACL support, we allow everything
+ if ($acl) {
+ $acl->checkPrivileges($uri, '{DAV:}write');
+ }
+
+ $message = $this->parseInviteReplyRequest($dom);
+
+ $url = $node->shareReply(
+ $message['href'],
+ $message['status'],
+ $message['calendarUri'],
+ $message['inReplyTo'],
+ $message['summary']
+ );
+
+ $this->server->httpResponse->sendStatus(200);
+ // Adding this because sending a response body may cause issues,
+ // and I wanted some type of indicator the response was handled.
+ $this->server->httpResponse->setHeader('X-Sabre-Status', 'everything-went-well');
+
+ if ($url) {
+ $dom = new \DOMDocument('1.0', 'UTF-8');
+ $dom->formatOutput = true;
+
+ $root = $dom->createElement('cs:shared-as');
+ foreach($this->server->xmlNamespaces as $namespace => $prefix) {
+ $root->setAttribute('xmlns:' . $prefix, $namespace);
+ }
+
+ $dom->appendChild($root);
+ $href = new DAV\Property\Href($url);
+
+ $href->serialize($this->server, $root);
+ $this->server->httpResponse->setHeader('Content-Type','application/xml');
+ $this->server->httpResponse->sendBody($dom->saveXML());
+
+ }
+
+ // Breaking the event chain
+ return false;
+
+ case '{' . Plugin::NS_CALENDARSERVER . '}publish-calendar' :
+
+ // We can only deal with IShareableCalendar objects
+ if (!$node instanceof IShareableCalendar) {
+ return;
+ }
+
+ // Getting ACL info
+ $acl = $this->server->getPlugin('acl');
+
+ // If there's no ACL support, we allow everything
+ if ($acl) {
+ $acl->checkPrivileges($uri, '{DAV:}write');
+ }
+
+ $node->setPublishStatus(true);
+
+ // iCloud sends back the 202, so we will too.
+ $this->server->httpResponse->sendStatus(202);
+
+ // Adding this because sending a response body may cause issues,
+ // and I wanted some type of indicator the response was handled.
+ $this->server->httpResponse->setHeader('X-Sabre-Status', 'everything-went-well');
+
+ // Breaking the event chain
+ return false;
+
+ case '{' . Plugin::NS_CALENDARSERVER . '}unpublish-calendar' :
+
+ // We can only deal with IShareableCalendar objects
+ if (!$node instanceof IShareableCalendar) {
+ return;
+ }
+
+ // Getting ACL info
+ $acl = $this->server->getPlugin('acl');
+
+ // If there's no ACL support, we allow everything
+ if ($acl) {
+ $acl->checkPrivileges($uri, '{DAV:}write');
+ }
+
+ $node->setPublishStatus(false);
+
+ $this->server->httpResponse->sendStatus(200);
+
+ // Adding this because sending a response body may cause issues,
+ // and I wanted some type of indicator the response was handled.
+ $this->server->httpResponse->setHeader('X-Sabre-Status', 'everything-went-well');
+
+ // Breaking the event chain
+ return false;
+
+ }
+
+
+
+ }
+
+ /**
+ * Parses the 'share' POST request.
+ *
+ * This method returns an array, containing two arrays.
+ * The first array is a list of new sharees. Every element is a struct
+ * containing a:
+ * * href element. (usually a mailto: address)
+ * * commonName element (often a first and lastname, but can also be
+ * false)
+ * * readOnly (true or false)
+ * * summary (A description of the share, can also be false)
+ *
+ * The second array is a list of sharees that are to be removed. This is
+ * just a simple array with 'hrefs'.
+ *
+ * @param \DOMDocument $dom
+ * @return array
+ */
+ protected function parseShareRequest(\DOMDocument $dom) {
+
+ $xpath = new \DOMXPath($dom);
+ $xpath->registerNamespace('cs', Plugin::NS_CALENDARSERVER);
+ $xpath->registerNamespace('d', 'urn:DAV');
+
+ $set = array();
+ $elems = $xpath->query('cs:set');
+
+ for($i=0; $i < $elems->length; $i++) {
+
+ $xset = $elems->item($i);
+ $set[] = array(
+ 'href' => $xpath->evaluate('string(d:href)', $xset),
+ 'commonName' => $xpath->evaluate('string(cs:common-name)', $xset),
+ 'summary' => $xpath->evaluate('string(cs:summary)', $xset),
+ 'readOnly' => $xpath->evaluate('boolean(cs:read)', $xset)!==false
+ );
+
+ }
+
+ $remove = array();
+ $elems = $xpath->query('cs:remove');
+
+ for($i=0; $i < $elems->length; $i++) {
+
+ $xremove = $elems->item($i);
+ $remove[] = $xpath->evaluate('string(d:href)', $xremove);
+
+ }
+
+ return array($set, $remove);
+
+ }
+
+ /**
+ * Parses the 'invite-reply' POST request.
+ *
+ * This method returns an array, containing the following properties:
+ * * href - The sharee who is replying
+ * * status - One of the self::STATUS_* constants
+ * * calendarUri - The url of the shared calendar
+ * * inReplyTo - The unique id of the share invitation.
+ * * summary - Optional description of the reply.
+ *
+ * @param \DOMDocument $dom
+ * @return array
+ */
+ protected function parseInviteReplyRequest(\DOMDocument $dom) {
+
+ $xpath = new \DOMXPath($dom);
+ $xpath->registerNamespace('cs', Plugin::NS_CALENDARSERVER);
+ $xpath->registerNamespace('d', 'urn:DAV');
+
+ $hostHref = $xpath->evaluate('string(cs:hosturl/d:href)');
+ if (!$hostHref) {
+ throw new DAV\Exception\BadRequest('The {' . Plugin::NS_CALENDARSERVER . '}hosturl/{DAV:}href element is required');
+ }
+
+ return array(
+ 'href' => $xpath->evaluate('string(d:href)'),
+ 'calendarUri' => $this->server->calculateUri($hostHref),
+ 'inReplyTo' => $xpath->evaluate('string(cs:in-reply-to)'),
+ 'summary' => $xpath->evaluate('string(cs:summary)'),
+ 'status' => $xpath->evaluate('boolean(cs:invite-accepted)')?self::STATUS_ACCEPTED:self::STATUS_DECLINED
+ );
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/UserCalendars.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/UserCalendars.php
new file mode 100644
index 0000000..17f7956
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/UserCalendars.php
@@ -0,0 +1,342 @@
+caldavBackend = $caldavBackend;
+ $this->principalInfo = $principalInfo;
+
+ }
+
+ /**
+ * Returns the name of this object
+ *
+ * @return string
+ */
+ public function getName() {
+
+ list(,$name) = DAV\URLUtil::splitPath($this->principalInfo['uri']);
+ return $name;
+
+ }
+
+ /**
+ * Updates the name of this object
+ *
+ * @param string $name
+ * @return void
+ */
+ public function setName($name) {
+
+ throw new DAV\Exception\Forbidden();
+
+ }
+
+ /**
+ * Deletes this object
+ *
+ * @return void
+ */
+ public function delete() {
+
+ throw new DAV\Exception\Forbidden();
+
+ }
+
+ /**
+ * Returns the last modification date
+ *
+ * @return int
+ */
+ public function getLastModified() {
+
+ return null;
+
+ }
+
+ /**
+ * Creates a new file under this object.
+ *
+ * This is currently not allowed
+ *
+ * @param string $filename
+ * @param resource $data
+ * @return void
+ */
+ public function createFile($filename, $data=null) {
+
+ throw new DAV\Exception\MethodNotAllowed('Creating new files in this collection is not supported');
+
+ }
+
+ /**
+ * Creates a new directory under this object.
+ *
+ * This is currently not allowed.
+ *
+ * @param string $filename
+ * @return void
+ */
+ public function createDirectory($filename) {
+
+ throw new DAV\Exception\MethodNotAllowed('Creating new collections in this collection is not supported');
+
+ }
+
+ /**
+ * Returns a single calendar, by name
+ *
+ * @param string $name
+ * @todo needs optimizing
+ * @return Calendar
+ */
+ public function getChild($name) {
+
+ foreach($this->getChildren() as $child) {
+ if ($name==$child->getName())
+ return $child;
+
+ }
+ throw new DAV\Exception\NotFound('Calendar with name \'' . $name . '\' could not be found');
+
+ }
+
+ /**
+ * Checks if a calendar exists.
+ *
+ * @param string $name
+ * @todo needs optimizing
+ * @return bool
+ */
+ public function childExists($name) {
+
+ foreach($this->getChildren() as $child) {
+ if ($name==$child->getName())
+ return true;
+
+ }
+ return false;
+
+ }
+
+ /**
+ * Returns a list of calendars
+ *
+ * @return array
+ */
+ public function getChildren() {
+
+ $calendars = $this->caldavBackend->getCalendarsForUser($this->principalInfo['uri']);
+ $objs = array();
+ foreach($calendars as $calendar) {
+ if ($this->caldavBackend instanceof Backend\SharingSupport) {
+ if (isset($calendar['{http://calendarserver.org/ns/}shared-url'])) {
+ $objs[] = new SharedCalendar($this->caldavBackend, $calendar);
+ } else {
+ $objs[] = new ShareableCalendar($this->caldavBackend, $calendar);
+ }
+ } else {
+ $objs[] = new Calendar($this->caldavBackend, $calendar);
+ }
+ }
+ $objs[] = new Schedule\Outbox($this->principalInfo['uri']);
+
+ // We're adding a notifications node, if it's supported by the backend.
+ if ($this->caldavBackend instanceof Backend\NotificationSupport) {
+ $objs[] = new Notifications\Collection($this->caldavBackend, $this->principalInfo['uri']);
+ }
+ return $objs;
+
+ }
+
+ /**
+ * Creates a new calendar
+ *
+ * @param string $name
+ * @param array $resourceType
+ * @param array $properties
+ * @return void
+ */
+ public function createExtendedCollection($name, array $resourceType, array $properties) {
+
+ $isCalendar = false;
+ foreach($resourceType as $rt) {
+ switch ($rt) {
+ case '{DAV:}collection' :
+ case '{http://calendarserver.org/ns/}shared-owner' :
+ // ignore
+ break;
+ case '{urn:ietf:params:xml:ns:caldav}calendar' :
+ $isCalendar = true;
+ break;
+ default :
+ throw new DAV\Exception\InvalidResourceType('Unknown resourceType: ' . $rt);
+ }
+ }
+ if (!$isCalendar) {
+ throw new DAV\Exception\InvalidResourceType('You can only create calendars in this collection');
+ }
+ $this->caldavBackend->createCalendar($this->principalInfo['uri'], $name, $properties);
+
+ }
+
+ /**
+ * Returns the owner principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getOwner() {
+
+ return $this->principalInfo['uri'];
+
+ }
+
+ /**
+ * Returns a group principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getGroup() {
+
+ return null;
+
+ }
+
+ /**
+ * Returns a list of ACE's for this node.
+ *
+ * Each ACE has the following properties:
+ * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
+ * currently the only supported privileges
+ * * 'principal', a url to the principal who owns the node
+ * * 'protected' (optional), indicating that this ACE is not allowed to
+ * be updated.
+ *
+ * @return array
+ */
+ public function getACL() {
+
+ return array(
+ array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->principalInfo['uri'],
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}write',
+ 'principal' => $this->principalInfo['uri'],
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->principalInfo['uri'] . '/calendar-proxy-write',
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}write',
+ 'principal' => $this->principalInfo['uri'] . '/calendar-proxy-write',
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->principalInfo['uri'] . '/calendar-proxy-read',
+ 'protected' => true,
+ ),
+
+ );
+
+ }
+
+ /**
+ * Updates the ACL
+ *
+ * This method will receive a list of new ACE's.
+ *
+ * @param array $acl
+ * @return void
+ */
+ public function setACL(array $acl) {
+
+ throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported');
+
+ }
+
+ /**
+ * Returns the list of supported privileges for this node.
+ *
+ * The returned data structure is a list of nested privileges.
+ * See SabreForRainLoop\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
+ * standard structure.
+ *
+ * If null is returned from this method, the default privilege set is used,
+ * which is fine for most common usecases.
+ *
+ * @return array|null
+ */
+ public function getSupportedPrivilegeSet() {
+
+ return null;
+
+ }
+
+ /**
+ * This method is called when a user replied to a request to share.
+ *
+ * This method should return the url of the newly created calendar if the
+ * share was accepted.
+ *
+ * @param string href The sharee who is replying (often a mailto: address)
+ * @param int status One of the SharingPlugin::STATUS_* constants
+ * @param string $calendarUri The url to the calendar thats being shared
+ * @param string $inReplyTo The unique id this message is a response to
+ * @param string $summary A description of the reply
+ * @return null|string
+ */
+ public function shareReply($href, $status, $calendarUri, $inReplyTo, $summary = null) {
+
+ if (!$this->caldavBackend instanceof Backend\SharingSupport) {
+ throw new DAV\Exception\NotImplemented('Sharing support is not implemented by this backend.');
+ }
+
+ return $this->caldavBackend->shareReply($href, $status, $calendarUri, $inReplyTo, $summary);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Version.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Version.php
new file mode 100644
index 0000000..b85b340
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CalDAV/Version.php
@@ -0,0 +1,24 @@
+carddavBackend = $carddavBackend;
+ $this->addressBookInfo = $addressBookInfo;
+
+ }
+
+ /**
+ * Returns the name of the addressbook
+ *
+ * @return string
+ */
+ public function getName() {
+
+ return $this->addressBookInfo['uri'];
+
+ }
+
+ /**
+ * Returns a card
+ *
+ * @param string $name
+ * @return \ICard
+ */
+ public function getChild($name) {
+
+ $obj = $this->carddavBackend->getCard($this->addressBookInfo['id'],$name);
+ if (!$obj) throw new DAV\Exception\NotFound('Card not found');
+ return new Card($this->carddavBackend,$this->addressBookInfo,$obj);
+
+ }
+
+ /**
+ * Returns the full list of cards
+ *
+ * @return array
+ */
+ public function getChildren() {
+
+ $objs = $this->carddavBackend->getCards($this->addressBookInfo['id']);
+ $children = array();
+ foreach($objs as $obj) {
+ $children[] = new Card($this->carddavBackend,$this->addressBookInfo,$obj);
+ }
+ return $children;
+
+ }
+
+ /**
+ * Creates a new directory
+ *
+ * We actually block this, as subdirectories are not allowed in addressbooks.
+ *
+ * @param string $name
+ * @return void
+ */
+ public function createDirectory($name) {
+
+ throw new DAV\Exception\MethodNotAllowed('Creating collections in addressbooks is not allowed');
+
+ }
+
+ /**
+ * Creates a new file
+ *
+ * The contents of the new file must be a valid VCARD.
+ *
+ * This method may return an ETag.
+ *
+ * @param string $name
+ * @param resource $vcardData
+ * @return string|null
+ */
+ public function createFile($name,$vcardData = null) {
+
+ if (is_resource($vcardData)) {
+ $vcardData = stream_get_contents($vcardData);
+ }
+ // Converting to UTF-8, if needed
+ $vcardData = DAV\StringUtil::ensureUTF8($vcardData);
+
+ return $this->carddavBackend->createCard($this->addressBookInfo['id'],$name,$vcardData);
+
+ }
+
+ /**
+ * Deletes the entire addressbook.
+ *
+ * @return void
+ */
+ public function delete() {
+
+ $this->carddavBackend->deleteAddressBook($this->addressBookInfo['id']);
+
+ }
+
+ /**
+ * Renames the addressbook
+ *
+ * @param string $newName
+ * @return void
+ */
+ public function setName($newName) {
+
+ throw new DAV\Exception\MethodNotAllowed('Renaming addressbooks is not yet supported');
+
+ }
+
+ /**
+ * Returns the last modification date as a unix timestamp.
+ *
+ * @return void
+ */
+ public function getLastModified() {
+
+ return null;
+
+ }
+
+ /**
+ * Updates properties on this node,
+ *
+ * The properties array uses the propertyName in clark-notation as key,
+ * and the array value for the property value. In the case a property
+ * should be deleted, the property value will be null.
+ *
+ * This method must be atomic. If one property cannot be changed, the
+ * entire operation must fail.
+ *
+ * If the operation was successful, true can be returned.
+ * If the operation failed, false can be returned.
+ *
+ * Deletion of a non-existent property is always successful.
+ *
+ * Lastly, it is optional to return detailed information about any
+ * failures. In this case an array should be returned with the following
+ * structure:
+ *
+ * array(
+ * 403 => array(
+ * '{DAV:}displayname' => null,
+ * ),
+ * 424 => array(
+ * '{DAV:}owner' => null,
+ * )
+ * )
+ *
+ * In this example it was forbidden to update {DAV:}displayname.
+ * (403 Forbidden), which in turn also caused {DAV:}owner to fail
+ * (424 Failed Dependency) because the request needs to be atomic.
+ *
+ * @param array $mutations
+ * @return bool|array
+ */
+ public function updateProperties($mutations) {
+
+ return $this->carddavBackend->updateAddressBook($this->addressBookInfo['id'], $mutations);
+
+ }
+
+ /**
+ * Returns a list of properties for this nodes.
+ *
+ * The properties list is a list of propertynames the client requested,
+ * encoded in clark-notation {xmlnamespace}tagname
+ *
+ * If the array is empty, it means 'all properties' were requested.
+ *
+ * @param array $properties
+ * @return array
+ */
+ public function getProperties($properties) {
+
+ $response = array();
+ foreach($properties as $propertyName) {
+
+ if (isset($this->addressBookInfo[$propertyName])) {
+
+ $response[$propertyName] = $this->addressBookInfo[$propertyName];
+
+ }
+
+ }
+
+ return $response;
+
+ }
+
+ /**
+ * Returns the owner principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getOwner() {
+
+ return $this->addressBookInfo['principaluri'];
+
+ }
+
+ /**
+ * Returns a group principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getGroup() {
+
+ return null;
+
+ }
+
+ /**
+ * Returns a list of ACE's for this node.
+ *
+ * Each ACE has the following properties:
+ * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
+ * currently the only supported privileges
+ * * 'principal', a url to the principal who owns the node
+ * * 'protected' (optional), indicating that this ACE is not allowed to
+ * be updated.
+ *
+ * @return array
+ */
+ public function getACL() {
+
+ return array(
+ array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->addressBookInfo['principaluri'],
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}write',
+ 'principal' => $this->addressBookInfo['principaluri'],
+ 'protected' => true,
+ ),
+
+ );
+
+ }
+
+ /**
+ * Updates the ACL
+ *
+ * This method will receive a list of new ACE's.
+ *
+ * @param array $acl
+ * @return void
+ */
+ public function setACL(array $acl) {
+
+ throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported');
+
+ }
+
+ /**
+ * Returns the list of supported privileges for this node.
+ *
+ * The returned data structure is a list of nested privileges.
+ * See SabreForRainLoop\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
+ * standard structure.
+ *
+ * If null is returned from this method, the default privilege set is used,
+ * which is fine for most common usecases.
+ *
+ * @return array|null
+ */
+ public function getSupportedPrivilegeSet() {
+
+ return null;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/AddressBookQueryParser.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/AddressBookQueryParser.php
new file mode 100644
index 0000000..579937e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/AddressBookQueryParser.php
@@ -0,0 +1,221 @@
+dom = $dom;
+
+ $this->xpath = new \DOMXPath($dom);
+ $this->xpath->registerNameSpace('card',Plugin::NS_CARDDAV);
+
+ }
+
+ /**
+ * Parses the request.
+ *
+ * @return void
+ */
+ public function parse() {
+
+ $filterNode = null;
+
+ $limit = $this->xpath->evaluate('number(/card:addressbook-query/card:limit/card:nresults)');
+ if (is_nan($limit)) $limit = null;
+
+ $filter = $this->xpath->query('/card:addressbook-query/card:filter');
+
+ // According to the CardDAV spec there needs to be exactly 1 filter
+ // element. However, KDE 4.8.2 contains a bug that will encode 0 filter
+ // elements, so this is a workaround for that.
+ //
+ // See: https://bugs.kde.org/show_bug.cgi?id=300047
+ if ($filter->length === 0) {
+ $test = null;
+ $filter = null;
+ } elseif ($filter->length === 1) {
+ $filter = $filter->item(0);
+ $test = $this->xpath->evaluate('string(@test)', $filter);
+ } else {
+ throw new DAV\Exception\BadRequest('Only one filter element is allowed');
+ }
+
+ if (!$test) $test = self::TEST_ANYOF;
+ if ($test !== self::TEST_ANYOF && $test !== self::TEST_ALLOF) {
+ throw new DAV\Exception\BadRequest('The test attribute must either hold "anyof" or "allof"');
+ }
+
+ $propFilters = array();
+
+ $propFilterNodes = $this->xpath->query('card:prop-filter', $filter);
+ for($ii=0; $ii < $propFilterNodes->length; $ii++) {
+
+ $propFilters[] = $this->parsePropFilterNode($propFilterNodes->item($ii));
+
+
+ }
+
+ $this->filters = $propFilters;
+ $this->limit = $limit;
+ $this->requestedProperties = array_keys(DAV\XMLUtil::parseProperties($this->dom->firstChild));
+ $this->test = $test;
+
+ }
+
+ /**
+ * Parses the prop-filter xml element
+ *
+ * @param \DOMElement $propFilterNode
+ * @return array
+ */
+ protected function parsePropFilterNode(\DOMElement $propFilterNode) {
+
+ $propFilter = array();
+ $propFilter['name'] = $propFilterNode->getAttribute('name');
+ $propFilter['test'] = $propFilterNode->getAttribute('test');
+ if (!$propFilter['test']) $propFilter['test'] = 'anyof';
+
+ $propFilter['is-not-defined'] = $this->xpath->query('card:is-not-defined', $propFilterNode)->length>0;
+
+ $paramFilterNodes = $this->xpath->query('card:param-filter', $propFilterNode);
+
+ $propFilter['param-filters'] = array();
+
+
+ for($ii=0;$ii<$paramFilterNodes->length;$ii++) {
+
+ $propFilter['param-filters'][] = $this->parseParamFilterNode($paramFilterNodes->item($ii));
+
+ }
+ $propFilter['text-matches'] = array();
+ $textMatchNodes = $this->xpath->query('card:text-match', $propFilterNode);
+
+ for($ii=0;$ii<$textMatchNodes->length;$ii++) {
+
+ $propFilter['text-matches'][] = $this->parseTextMatchNode($textMatchNodes->item($ii));
+
+ }
+
+ return $propFilter;
+
+ }
+
+ /**
+ * Parses the param-filter element
+ *
+ * @param \DOMElement $paramFilterNode
+ * @return array
+ */
+ public function parseParamFilterNode(\DOMElement $paramFilterNode) {
+
+ $paramFilter = array();
+ $paramFilter['name'] = $paramFilterNode->getAttribute('name');
+ $paramFilter['is-not-defined'] = $this->xpath->query('card:is-not-defined', $paramFilterNode)->length>0;
+ $paramFilter['text-match'] = null;
+
+ $textMatch = $this->xpath->query('card:text-match', $paramFilterNode);
+ if ($textMatch->length>0) {
+ $paramFilter['text-match'] = $this->parseTextMatchNode($textMatch->item(0));
+ }
+
+ return $paramFilter;
+
+ }
+
+ /**
+ * Text match
+ *
+ * @param \DOMElement $textMatchNode
+ * @return array
+ */
+ public function parseTextMatchNode(\DOMElement $textMatchNode) {
+
+ $matchType = $textMatchNode->getAttribute('match-type');
+ if (!$matchType) $matchType = 'contains';
+
+ if (!in_array($matchType, array('contains', 'equals', 'starts-with', 'ends-with'))) {
+ throw new DAV\Exception\BadRequest('Unknown match-type: ' . $matchType);
+ }
+
+ $negateCondition = $textMatchNode->getAttribute('negate-condition');
+ $negateCondition = $negateCondition==='yes';
+ $collation = $textMatchNode->getAttribute('collation');
+ if (!$collation) $collation = 'i;unicode-casemap';
+
+ return array(
+ 'negate-condition' => $negateCondition,
+ 'collation' => $collation,
+ 'match-type' => $matchType,
+ 'value' => $textMatchNode->nodeValue
+ );
+
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/AddressBookRoot.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/AddressBookRoot.php
new file mode 100644
index 0000000..5cbd918
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/AddressBookRoot.php
@@ -0,0 +1,80 @@
+carddavBackend = $carddavBackend;
+ parent::__construct($principalBackend, $principalPrefix);
+
+ }
+
+ /**
+ * Returns the name of the node
+ *
+ * @return string
+ */
+ public function getName() {
+
+ return Plugin::ADDRESSBOOK_ROOT;
+
+ }
+
+ /**
+ * This method returns a node for a principal.
+ *
+ * The passed array contains principal information, and is guaranteed to
+ * at least contain a uri item. Other properties may or may not be
+ * supplied by the authentication backend.
+ *
+ * @param array $principal
+ * @return \SabreForRainLoop\DAV\INode
+ */
+ public function getChildForPrincipal(array $principal) {
+
+ return new UserAddressBooks($this->carddavBackend, $principal['uri']);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/Backend/AbstractBackend.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/Backend/AbstractBackend.php
new file mode 100644
index 0000000..14504d6
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/Backend/AbstractBackend.php
@@ -0,0 +1,18 @@
+pdo = $pdo;
+ $this->addressBooksTableName = $addressBooksTableName;
+ $this->cardsTableName = $cardsTableName;
+
+ }
+
+ /**
+ * Returns the list of addressbooks for a specific user.
+ *
+ * @param string $principalUri
+ * @return array
+ */
+ public function getAddressBooksForUser($principalUri) {
+
+ $stmt = $this->pdo->prepare('SELECT id, uri, displayname, principaluri, description, ctag FROM '.$this->addressBooksTableName.' WHERE principaluri = ?');
+ $stmt->execute(array($principalUri));
+
+ $addressBooks = array();
+
+ foreach($stmt->fetchAll() as $row) {
+
+ $addressBooks[] = array(
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ 'principaluri' => $row['principaluri'],
+ '{DAV:}displayname' => $row['displayname'],
+ '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'],
+ '{http://calendarserver.org/ns/}getctag' => $row['ctag'],
+ '{' . CardDAV\Plugin::NS_CARDDAV . '}supported-address-data' =>
+ new CardDAV\Property\SupportedAddressData(),
+ );
+
+ }
+
+ return $addressBooks;
+
+ }
+
+
+ /**
+ * Updates an addressbook's properties
+ *
+ * See SabreForRainLoop\DAV\IProperties for a description of the mutations array, as
+ * well as the return value.
+ *
+ * @param mixed $addressBookId
+ * @param array $mutations
+ * @see SabreForRainLoop\DAV\IProperties::updateProperties
+ * @return bool|array
+ */
+ public function updateAddressBook($addressBookId, array $mutations) {
+
+ $updates = array();
+
+ foreach($mutations as $property=>$newValue) {
+
+ switch($property) {
+ case '{DAV:}displayname' :
+ $updates['displayname'] = $newValue;
+ break;
+ case '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' :
+ $updates['description'] = $newValue;
+ break;
+ default :
+ // If any unsupported values were being updated, we must
+ // let the entire request fail.
+ return false;
+ }
+
+ }
+
+ // No values are being updated?
+ if (!$updates) {
+ return false;
+ }
+
+ $query = 'UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 ';
+ foreach($updates as $key=>$value) {
+ $query.=', `' . $key . '` = :' . $key . ' ';
+ }
+ $query.=' WHERE id = :addressbookid';
+
+ $stmt = $this->pdo->prepare($query);
+ $updates['addressbookid'] = $addressBookId;
+
+ $stmt->execute($updates);
+
+ return true;
+
+ }
+
+ /**
+ * Creates a new address book
+ *
+ * @param string $principalUri
+ * @param string $url Just the 'basename' of the url.
+ * @param array $properties
+ * @return void
+ */
+ public function createAddressBook($principalUri, $url, array $properties) {
+
+ $values = array(
+ 'displayname' => null,
+ 'description' => null,
+ 'principaluri' => $principalUri,
+ 'uri' => $url,
+ );
+
+ foreach($properties as $property=>$newValue) {
+
+ switch($property) {
+ case '{DAV:}displayname' :
+ $values['displayname'] = $newValue;
+ break;
+ case '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' :
+ $values['description'] = $newValue;
+ break;
+ default :
+ throw new DAV\Exception\BadRequest('Unknown property: ' . $property);
+ }
+
+ }
+
+ $query = 'INSERT INTO ' . $this->addressBooksTableName . ' (uri, displayname, description, principaluri, ctag) VALUES (:uri, :displayname, :description, :principaluri, 1)';
+ $stmt = $this->pdo->prepare($query);
+ $stmt->execute($values);
+
+ }
+
+ /**
+ * Deletes an entire addressbook and all its contents
+ *
+ * @param int $addressBookId
+ * @return void
+ */
+ public function deleteAddressBook($addressBookId) {
+
+ $stmt = $this->pdo->prepare('DELETE FROM ' . $this->cardsTableName . ' WHERE addressbookid = ?');
+ $stmt->execute(array($addressBookId));
+
+ $stmt = $this->pdo->prepare('DELETE FROM ' . $this->addressBooksTableName . ' WHERE id = ?');
+ $stmt->execute(array($addressBookId));
+
+ }
+
+ /**
+ * Returns all cards for a specific addressbook id.
+ *
+ * This method should return the following properties for each card:
+ * * carddata - raw vcard data
+ * * uri - Some unique url
+ * * lastmodified - A unix timestamp
+ *
+ * It's recommended to also return the following properties:
+ * * etag - A unique etag. This must change every time the card changes.
+ * * size - The size of the card in bytes.
+ *
+ * If these last two properties are provided, less time will be spent
+ * calculating them. If they are specified, you can also ommit carddata.
+ * This may speed up certain requests, especially with large cards.
+ *
+ * @param mixed $addressbookId
+ * @return array
+ */
+ public function getCards($addressbookId) {
+
+ $stmt = $this->pdo->prepare('SELECT id, carddata, uri, lastmodified FROM ' . $this->cardsTableName . ' WHERE addressbookid = ?');
+ $stmt->execute(array($addressbookId));
+
+ return $stmt->fetchAll(\PDO::FETCH_ASSOC);
+
+
+ }
+
+ /**
+ * Returns a specfic card.
+ *
+ * The same set of properties must be returned as with getCards. The only
+ * exception is that 'carddata' is absolutely required.
+ *
+ * @param mixed $addressBookId
+ * @param string $cardUri
+ * @return array
+ */
+ public function getCard($addressBookId, $cardUri) {
+
+ $stmt = $this->pdo->prepare('SELECT id, carddata, uri, lastmodified FROM ' . $this->cardsTableName . ' WHERE addressbookid = ? AND uri = ? LIMIT 1');
+ $stmt->execute(array($addressBookId, $cardUri));
+
+ $result = $stmt->fetchAll(\PDO::FETCH_ASSOC);
+
+ return (count($result)>0?$result[0]:false);
+
+ }
+
+ /**
+ * Creates a new card.
+ *
+ * The addressbook id will be passed as the first argument. This is the
+ * same id as it is returned from the getAddressbooksForUser method.
+ *
+ * The cardUri is a base uri, and doesn't include the full path. The
+ * cardData argument is the vcard body, and is passed as a string.
+ *
+ * It is possible to return an ETag from this method. This ETag is for the
+ * newly created resource, and must be enclosed with double quotes (that
+ * is, the string itself must contain the double quotes).
+ *
+ * You should only return the ETag if you store the carddata as-is. If a
+ * subsequent GET request on the same card does not have the same body,
+ * byte-by-byte and you did return an ETag here, clients tend to get
+ * confused.
+ *
+ * If you don't return an ETag, you can just return null.
+ *
+ * @param mixed $addressBookId
+ * @param string $cardUri
+ * @param string $cardData
+ * @return string|null
+ */
+ public function createCard($addressBookId, $cardUri, $cardData) {
+
+ $stmt = $this->pdo->prepare('INSERT INTO ' . $this->cardsTableName . ' (carddata, uri, lastmodified, addressbookid) VALUES (?, ?, ?, ?)');
+
+ $result = $stmt->execute(array($cardData, $cardUri, time(), $addressBookId));
+
+ $stmt2 = $this->pdo->prepare('UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 WHERE id = ?');
+ $stmt2->execute(array($addressBookId));
+
+ return '"' . md5($cardData) . '"';
+
+ }
+
+ /**
+ * Updates a card.
+ *
+ * The addressbook id will be passed as the first argument. This is the
+ * same id as it is returned from the getAddressbooksForUser method.
+ *
+ * The cardUri is a base uri, and doesn't include the full path. The
+ * cardData argument is the vcard body, and is passed as a string.
+ *
+ * It is possible to return an ETag from this method. This ETag should
+ * match that of the updated resource, and must be enclosed with double
+ * quotes (that is: the string itself must contain the actual quotes).
+ *
+ * You should only return the ETag if you store the carddata as-is. If a
+ * subsequent GET request on the same card does not have the same body,
+ * byte-by-byte and you did return an ETag here, clients tend to get
+ * confused.
+ *
+ * If you don't return an ETag, you can just return null.
+ *
+ * @param mixed $addressBookId
+ * @param string $cardUri
+ * @param string $cardData
+ * @return string|null
+ */
+ public function updateCard($addressBookId, $cardUri, $cardData) {
+
+ $stmt = $this->pdo->prepare('UPDATE ' . $this->cardsTableName . ' SET carddata = ?, lastmodified = ? WHERE uri = ? AND addressbookid =?');
+ $stmt->execute(array($cardData, time(), $cardUri, $addressBookId));
+
+ $stmt2 = $this->pdo->prepare('UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 WHERE id = ?');
+ $stmt2->execute(array($addressBookId));
+
+ return '"' . md5($cardData) . '"';
+
+ }
+
+ /**
+ * Deletes a card
+ *
+ * @param mixed $addressBookId
+ * @param string $cardUri
+ * @return bool
+ */
+ public function deleteCard($addressBookId, $cardUri) {
+
+ $stmt = $this->pdo->prepare('DELETE FROM ' . $this->cardsTableName . ' WHERE addressbookid = ? AND uri = ?');
+ $stmt->execute(array($addressBookId, $cardUri));
+
+ $stmt2 = $this->pdo->prepare('UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 WHERE id = ?');
+ $stmt2->execute(array($addressBookId));
+
+ return $stmt->rowCount()===1;
+
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/Card.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/Card.php
new file mode 100644
index 0000000..dba09ec
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/Card.php
@@ -0,0 +1,260 @@
+carddavBackend = $carddavBackend;
+ $this->addressBookInfo = $addressBookInfo;
+ $this->cardData = $cardData;
+
+ }
+
+ /**
+ * Returns the uri for this object
+ *
+ * @return string
+ */
+ public function getName() {
+
+ return $this->cardData['uri'];
+
+ }
+
+ /**
+ * Returns the VCard-formatted object
+ *
+ * @return string
+ */
+ public function get() {
+
+ // Pre-populating 'carddata' is optional. If we don't yet have it
+ // already, we fetch it from the backend.
+ if (!isset($this->cardData['carddata'])) {
+ $this->cardData = $this->carddavBackend->getCard($this->addressBookInfo['id'], $this->cardData['uri']);
+ }
+ return $this->cardData['carddata'];
+
+ }
+
+ /**
+ * Updates the VCard-formatted object
+ *
+ * @param string $cardData
+ * @return string|null
+ */
+ public function put($cardData) {
+
+ if (is_resource($cardData))
+ $cardData = stream_get_contents($cardData);
+
+ // Converting to UTF-8, if needed
+ $cardData = DAV\StringUtil::ensureUTF8($cardData);
+
+ $etag = $this->carddavBackend->updateCard($this->addressBookInfo['id'],$this->cardData['uri'],$cardData);
+ $this->cardData['carddata'] = $cardData;
+ $this->cardData['etag'] = $etag;
+
+ return $etag;
+
+ }
+
+ /**
+ * Deletes the card
+ *
+ * @return void
+ */
+ public function delete() {
+
+ $this->carddavBackend->deleteCard($this->addressBookInfo['id'],$this->cardData['uri']);
+
+ }
+
+ /**
+ * Returns the mime content-type
+ *
+ * @return string
+ */
+ public function getContentType() {
+
+ return 'text/x-vcard; charset=utf-8';
+
+ }
+
+ /**
+ * Returns an ETag for this object
+ *
+ * @return string
+ */
+ public function getETag() {
+
+ if (isset($this->cardData['etag'])) {
+ return $this->cardData['etag'];
+ } else {
+ $data = $this->get();
+ if (is_string($data)) {
+ return '"' . md5($data) . '"';
+ } else {
+ // We refuse to calculate the md5 if it's a stream.
+ return null;
+ }
+ }
+
+ }
+
+ /**
+ * Returns the last modification date as a unix timestamp
+ *
+ * @return int
+ */
+ public function getLastModified() {
+
+ return isset($this->cardData['lastmodified'])?$this->cardData['lastmodified']:null;
+
+ }
+
+ /**
+ * Returns the size of this object in bytes
+ *
+ * @return int
+ */
+ public function getSize() {
+
+ if (array_key_exists('size', $this->cardData)) {
+ return $this->cardData['size'];
+ } else {
+ return strlen($this->get());
+ }
+
+ }
+
+ /**
+ * Returns the owner principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getOwner() {
+
+ return $this->addressBookInfo['principaluri'];
+
+ }
+
+ /**
+ * Returns a group principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getGroup() {
+
+ return null;
+
+ }
+
+ /**
+ * Returns a list of ACE's for this node.
+ *
+ * Each ACE has the following properties:
+ * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
+ * currently the only supported privileges
+ * * 'principal', a url to the principal who owns the node
+ * * 'protected' (optional), indicating that this ACE is not allowed to
+ * be updated.
+ *
+ * @return array
+ */
+ public function getACL() {
+
+ return array(
+ array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->addressBookInfo['principaluri'],
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}write',
+ 'principal' => $this->addressBookInfo['principaluri'],
+ 'protected' => true,
+ ),
+ );
+
+ }
+
+ /**
+ * Updates the ACL
+ *
+ * This method will receive a list of new ACE's.
+ *
+ * @param array $acl
+ * @return void
+ */
+ public function setACL(array $acl) {
+
+ throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported');
+
+ }
+
+ /**
+ * Returns the list of supported privileges for this node.
+ *
+ * The returned data structure is a list of nested privileges.
+ * See SabreForRainLoop\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
+ * standard structure.
+ *
+ * If null is returned from this method, the default privilege set is used,
+ * which is fine for most common usecases.
+ *
+ * @return array|null
+ */
+ public function getSupportedPrivilegeSet() {
+
+ return null;
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/IAddressBook.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/IAddressBook.php
new file mode 100644
index 0000000..a8d74c6
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/IAddressBook.php
@@ -0,0 +1,20 @@
+subscribeEvent('beforeGetProperties', array($this, 'beforeGetProperties'));
+ $server->subscribeEvent('afterGetProperties', array($this, 'afterGetProperties'));
+ $server->subscribeEvent('updateProperties', array($this, 'updateProperties'));
+ $server->subscribeEvent('report', array($this,'report'));
+ $server->subscribeEvent('onHTMLActionsPanel', array($this,'htmlActionsPanel'));
+ $server->subscribeEvent('onBrowserPostAction', array($this,'browserPostAction'));
+ $server->subscribeEvent('beforeWriteContent', array($this, 'beforeWriteContent'));
+ $server->subscribeEvent('beforeCreateFile', array($this, 'beforeCreateFile'));
+
+ /* Namespaces */
+ $server->xmlNamespaces[self::NS_CARDDAV] = 'card';
+
+ /* Mapping Interfaces to {DAV:}resourcetype values */
+ $server->resourceTypeMapping['SabreForRainLoop\\CardDAV\\IAddressBook'] = '{' . self::NS_CARDDAV . '}addressbook';
+ $server->resourceTypeMapping['SabreForRainLoop\\CardDAV\\IDirectory'] = '{' . self::NS_CARDDAV . '}directory';
+
+ /* Adding properties that may never be changed */
+ $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}supported-address-data';
+ $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}max-resource-size';
+ $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}addressbook-home-set';
+ $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}supported-collation-set';
+
+ $server->propertyMap['{http://calendarserver.org/ns/}me-card'] = 'SabreForRainLoop\\DAV\\Property\\Href';
+
+ $this->server = $server;
+
+ }
+
+ /**
+ * Returns a list of supported features.
+ *
+ * This is used in the DAV: header in the OPTIONS and PROPFIND requests.
+ *
+ * @return array
+ */
+ public function getFeatures() {
+
+ return array('addressbook');
+
+ }
+
+ /**
+ * Returns a list of reports this plugin supports.
+ *
+ * This will be used in the {DAV:}supported-report-set property.
+ * Note that you still need to subscribe to the 'report' event to actually
+ * implement them
+ *
+ * @param string $uri
+ * @return array
+ */
+ public function getSupportedReportSet($uri) {
+
+ $node = $this->server->tree->getNodeForPath($uri);
+ if ($node instanceof IAddressBook || $node instanceof ICard) {
+ return array(
+ '{' . self::NS_CARDDAV . '}addressbook-multiget',
+ '{' . self::NS_CARDDAV . '}addressbook-query',
+ );
+ }
+ return array();
+
+ }
+
+
+ /**
+ * Adds all CardDAV-specific properties
+ *
+ * @param string $path
+ * @param DAV\INode $node
+ * @param array $requestedProperties
+ * @param array $returnedProperties
+ * @return void
+ */
+ public function beforeGetProperties($path, DAV\INode $node, array &$requestedProperties, array &$returnedProperties) {
+
+ if ($node instanceof DAVACL\IPrincipal) {
+
+ // calendar-home-set property
+ $addHome = '{' . self::NS_CARDDAV . '}addressbook-home-set';
+ if (in_array($addHome,$requestedProperties)) {
+ $principalId = $node->getName();
+ $addressbookHomePath = self::ADDRESSBOOK_ROOT . '/' . $principalId . '/';
+ unset($requestedProperties[array_search($addHome, $requestedProperties)]);
+ $returnedProperties[200][$addHome] = new DAV\Property\Href($addressbookHomePath);
+ }
+
+ $directories = '{' . self::NS_CARDDAV . '}directory-gateway';
+ if ($this->directories && in_array($directories, $requestedProperties)) {
+ unset($requestedProperties[array_search($directories, $requestedProperties)]);
+ $returnedProperties[200][$directories] = new DAV\Property\HrefList($this->directories);
+ }
+
+ }
+
+ if ($node instanceof ICard) {
+
+ // The address-data property is not supposed to be a 'real'
+ // property, but in large chunks of the spec it does act as such.
+ // Therefore we simply expose it as a property.
+ $addressDataProp = '{' . self::NS_CARDDAV . '}address-data';
+ if (in_array($addressDataProp, $requestedProperties)) {
+ unset($requestedProperties[$addressDataProp]);
+ $val = $node->get();
+ if (is_resource($val))
+ $val = stream_get_contents($val);
+
+ $returnedProperties[200][$addressDataProp] = $val;
+
+ }
+ }
+
+ if ($node instanceof UserAddressBooks) {
+
+ $meCardProp = '{http://calendarserver.org/ns/}me-card';
+ if (in_array($meCardProp, $requestedProperties)) {
+
+ $props = $this->server->getProperties($node->getOwner(), array('{http://sabredav.org/ns}vcard-url'));
+ if (isset($props['{http://sabredav.org/ns}vcard-url'])) {
+
+ $returnedProperties[200][$meCardProp] = new DAV\Property\Href(
+ $props['{http://sabredav.org/ns}vcard-url']
+ );
+ $pos = array_search($meCardProp, $requestedProperties);
+ unset($requestedProperties[$pos]);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /**
+ * This event is triggered when a PROPPATCH method is executed
+ *
+ * @param array $mutations
+ * @param array $result
+ * @param DAV\INode $node
+ * @return bool
+ */
+ public function updateProperties(&$mutations, &$result, DAV\INode $node) {
+
+ if (!$node instanceof UserAddressBooks) {
+ return true;
+ }
+
+ $meCard = '{http://calendarserver.org/ns/}me-card';
+
+ // The only property we care about
+ if (!isset($mutations[$meCard]))
+ return true;
+
+ $value = $mutations[$meCard];
+ unset($mutations[$meCard]);
+
+ if ($value instanceof DAV\Property\IHref) {
+ $value = $value->getHref();
+ $value = $this->server->calculateUri($value);
+ } elseif (!is_null($value)) {
+ $result[400][$meCard] = null;
+ return false;
+ }
+
+ $innerResult = $this->server->updateProperties(
+ $node->getOwner(),
+ array(
+ '{http://sabredav.org/ns}vcard-url' => $value,
+ )
+ );
+
+ $closureResult = false;
+ foreach($innerResult as $status => $props) {
+ if (is_array($props) && array_key_exists('{http://sabredav.org/ns}vcard-url', $props)) {
+ $result[$status][$meCard] = null;
+ $closureResult = ($status>=200 && $status<300);
+ }
+
+ }
+
+ return $result;
+
+ }
+
+ /**
+ * This functions handles REPORT requests specific to CardDAV
+ *
+ * @param string $reportName
+ * @param \DOMNode $dom
+ * @return bool
+ */
+ public function report($reportName,$dom) {
+
+ switch($reportName) {
+ case '{'.self::NS_CARDDAV.'}addressbook-multiget' :
+ $this->addressbookMultiGetReport($dom);
+ return false;
+ case '{'.self::NS_CARDDAV.'}addressbook-query' :
+ $this->addressBookQueryReport($dom);
+ return false;
+ default :
+ return;
+
+ }
+
+
+ }
+
+ /**
+ * This function handles the addressbook-multiget REPORT.
+ *
+ * This report is used by the client to fetch the content of a series
+ * of urls. Effectively avoiding a lot of redundant requests.
+ *
+ * @param \DOMNode $dom
+ * @return void
+ */
+ public function addressbookMultiGetReport($dom) {
+
+ $properties = array_keys(DAV\XMLUtil::parseProperties($dom->firstChild));
+
+ $hrefElems = $dom->getElementsByTagNameNS('urn:DAV','href');
+ $propertyList = array();
+
+ foreach($hrefElems as $elem) {
+
+ $uri = $this->server->calculateUri($elem->nodeValue);
+ list($propertyList[]) = $this->server->getPropertiesForPath($uri,$properties);
+
+ }
+
+ $prefer = $this->server->getHTTPPRefer();
+
+ $this->server->httpResponse->sendStatus(207);
+ $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
+ $this->server->httpResponse->setHeader('Vary','Brief,Prefer');
+ $this->server->httpResponse->sendBody($this->server->generateMultiStatus($propertyList, $prefer['return-minimal']));
+
+ }
+
+ /**
+ * This method is triggered before a file gets updated with new content.
+ *
+ * This plugin uses this method to ensure that Card nodes receive valid
+ * vcard data.
+ *
+ * @param string $path
+ * @param DAV\IFile $node
+ * @param resource $data
+ * @return void
+ */
+ public function beforeWriteContent($path, DAV\IFile $node, &$data) {
+
+ if (!$node instanceof ICard)
+ return;
+
+ $this->validateVCard($data);
+
+ }
+
+ /**
+ * This method is triggered before a new file is created.
+ *
+ * This plugin uses this method to ensure that Card nodes receive valid
+ * vcard data.
+ *
+ * @param string $path
+ * @param resource $data
+ * @param DAV\ICollection $parentNode
+ * @return void
+ */
+ public function beforeCreateFile($path, &$data, DAV\ICollection $parentNode) {
+
+ if (!$parentNode instanceof IAddressBook)
+ return;
+
+ $this->validateVCard($data);
+
+ }
+
+ /**
+ * Checks if the submitted iCalendar data is in fact, valid.
+ *
+ * An exception is thrown if it's not.
+ *
+ * @param resource|string $data
+ * @return void
+ */
+ protected function validateVCard(&$data) {
+
+ // If it's a stream, we convert it to a string first.
+ if (is_resource($data)) {
+ $data = stream_get_contents($data);
+ }
+
+ // Converting the data to unicode, if needed.
+ $data = DAV\StringUtil::ensureUTF8($data);
+
+ try {
+
+ $vobj = VObject\Reader::read($data);
+
+ } catch (VObject\ParseException $e) {
+
+ throw new DAV\Exception\UnsupportedMediaType('This resource only supports valid vcard data. Parse error: ' . $e->getMessage());
+
+ }
+
+ if ($vobj->name !== 'VCARD') {
+ throw new DAV\Exception\UnsupportedMediaType('This collection can only support vcard objects.');
+ }
+
+ if (!isset($vobj->UID)) {
+ // No UID in vcards is invalid, but we'll just add it in anyway.
+ $vobj->add('UID', DAV\UUIDUtil::getUUID());
+ $data = $vobj->serialize();
+ }
+
+ }
+
+
+ /**
+ * This function handles the addressbook-query REPORT
+ *
+ * This report is used by the client to filter an addressbook based on a
+ * complex query.
+ *
+ * @param \DOMNode $dom
+ * @return void
+ */
+ protected function addressbookQueryReport($dom) {
+
+ $query = new AddressBookQueryParser($dom);
+ $query->parse();
+
+ $depth = $this->server->getHTTPDepth(0);
+
+ if ($depth==0) {
+ $candidateNodes = array(
+ $this->server->tree->getNodeForPath($this->server->getRequestUri())
+ );
+ } else {
+ $candidateNodes = $this->server->tree->getChildren($this->server->getRequestUri());
+ }
+
+ $validNodes = array();
+ foreach($candidateNodes as $node) {
+
+ if (!$node instanceof ICard)
+ continue;
+
+ $blob = $node->get();
+ if (is_resource($blob)) {
+ $blob = stream_get_contents($blob);
+ }
+
+ if (!$this->validateFilters($blob, $query->filters, $query->test)) {
+ continue;
+ }
+
+ $validNodes[] = $node;
+
+ if ($query->limit && $query->limit <= count($validNodes)) {
+ // We hit the maximum number of items, we can stop now.
+ break;
+ }
+
+ }
+
+ $result = array();
+ foreach($validNodes as $validNode) {
+
+ if ($depth==0) {
+ $href = $this->server->getRequestUri();
+ } else {
+ $href = $this->server->getRequestUri() . '/' . $validNode->getName();
+ }
+
+ list($result[]) = $this->server->getPropertiesForPath($href, $query->requestedProperties, 0);
+
+ }
+
+ $prefer = $this->server->getHTTPPRefer();
+
+ $this->server->httpResponse->sendStatus(207);
+ $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
+ $this->server->httpResponse->setHeader('Vary','Brief,Prefer');
+ $this->server->httpResponse->sendBody($this->server->generateMultiStatus($result, $prefer['return-minimal']));
+
+ }
+
+ /**
+ * Validates if a vcard makes it throught a list of filters.
+ *
+ * @param string $vcardData
+ * @param array $filters
+ * @param string $test anyof or allof (which means OR or AND)
+ * @return bool
+ */
+ public function validateFilters($vcardData, array $filters, $test) {
+
+ $vcard = VObject\Reader::read($vcardData);
+
+ if (!$filters) return true;
+
+ foreach($filters as $filter) {
+
+ $isDefined = isset($vcard->{$filter['name']});
+ if ($filter['is-not-defined']) {
+ if ($isDefined) {
+ $success = false;
+ } else {
+ $success = true;
+ }
+ } elseif ((!$filter['param-filters'] && !$filter['text-matches']) || !$isDefined) {
+
+ // We only need to check for existence
+ $success = $isDefined;
+
+ } else {
+
+ $vProperties = $vcard->select($filter['name']);
+
+ $results = array();
+ if ($filter['param-filters']) {
+ $results[] = $this->validateParamFilters($vProperties, $filter['param-filters'], $filter['test']);
+ }
+ if ($filter['text-matches']) {
+ $texts = array();
+ foreach($vProperties as $vProperty)
+ $texts[] = $vProperty->getValue();
+
+ $results[] = $this->validateTextMatches($texts, $filter['text-matches'], $filter['test']);
+ }
+
+ if (count($results)===1) {
+ $success = $results[0];
+ } else {
+ if ($filter['test'] === 'anyof') {
+ $success = $results[0] || $results[1];
+ } else {
+ $success = $results[0] && $results[1];
+ }
+ }
+
+ } // else
+
+ // There are two conditions where we can already determine whether
+ // or not this filter succeeds.
+ if ($test==='anyof' && $success) {
+ return true;
+ }
+ if ($test==='allof' && !$success) {
+ return false;
+ }
+
+ } // foreach
+
+ // If we got all the way here, it means we haven't been able to
+ // determine early if the test failed or not.
+ //
+ // This implies for 'anyof' that the test failed, and for 'allof' that
+ // we succeeded. Sounds weird, but makes sense.
+ return $test==='allof';
+
+ }
+
+ /**
+ * Validates if a param-filter can be applied to a specific property.
+ *
+ * @todo currently we're only validating the first parameter of the passed
+ * property. Any subsequence parameters with the same name are
+ * ignored.
+ * @param array $vProperties
+ * @param array $filters
+ * @param string $test
+ * @return bool
+ */
+ protected function validateParamFilters(array $vProperties, array $filters, $test) {
+
+ foreach($filters as $filter) {
+
+ $isDefined = false;
+ foreach($vProperties as $vProperty) {
+ $isDefined = isset($vProperty[$filter['name']]);
+ if ($isDefined) break;
+ }
+
+ if ($filter['is-not-defined']) {
+ if ($isDefined) {
+ $success = false;
+ } else {
+ $success = true;
+ }
+
+ // If there's no text-match, we can just check for existence
+ } elseif (!$filter['text-match'] || !$isDefined) {
+
+ $success = $isDefined;
+
+ } else {
+
+ $success = false;
+ foreach($vProperties as $vProperty) {
+ // If we got all the way here, we'll need to validate the
+ // text-match filter.
+ $success = DAV\StringUtil::textMatch($vProperty[$filter['name']]->getValue(), $filter['text-match']['value'], $filter['text-match']['collation'], $filter['text-match']['match-type']);
+ if ($success) break;
+ }
+ if ($filter['text-match']['negate-condition']) {
+ $success = !$success;
+ }
+
+ } // else
+
+ // There are two conditions where we can already determine whether
+ // or not this filter succeeds.
+ if ($test==='anyof' && $success) {
+ return true;
+ }
+ if ($test==='allof' && !$success) {
+ return false;
+ }
+
+ }
+
+ // If we got all the way here, it means we haven't been able to
+ // determine early if the test failed or not.
+ //
+ // This implies for 'anyof' that the test failed, and for 'allof' that
+ // we succeeded. Sounds weird, but makes sense.
+ return $test==='allof';
+
+ }
+
+ /**
+ * Validates if a text-filter can be applied to a specific property.
+ *
+ * @param array $texts
+ * @param array $filters
+ * @param string $test
+ * @return bool
+ */
+ protected function validateTextMatches(array $texts, array $filters, $test) {
+
+ foreach($filters as $filter) {
+
+ $success = false;
+ foreach($texts as $haystack) {
+ $success = DAV\StringUtil::textMatch($haystack, $filter['value'], $filter['collation'], $filter['match-type']);
+
+ // Breaking on the first match
+ if ($success) break;
+ }
+ if ($filter['negate-condition']) {
+ $success = !$success;
+ }
+
+ if ($success && $test==='anyof')
+ return true;
+
+ if (!$success && $test=='allof')
+ return false;
+
+
+ }
+
+ // If we got all the way here, it means we haven't been able to
+ // determine early if the test failed or not.
+ //
+ // This implies for 'anyof' that the test failed, and for 'allof' that
+ // we succeeded. Sounds weird, but makes sense.
+ return $test==='allof';
+
+ }
+
+ /**
+ * This event is triggered after webdav-properties have been retrieved.
+ *
+ * @return bool
+ */
+ public function afterGetProperties($uri, &$properties) {
+
+ // If the request was made using the SOGO connector, we must rewrite
+ // the content-type property. By default SabreDAV will send back
+ // text/x-vcard; charset=utf-8, but for SOGO we must strip that last
+ // part.
+ if (!isset($properties[200]['{DAV:}getcontenttype']))
+ return;
+
+ if (strpos($this->server->httpRequest->getHeader('User-Agent'),'Thunderbird')===false) {
+ return;
+ }
+
+ if (strpos($properties[200]['{DAV:}getcontenttype'],'text/x-vcard')===0) {
+ $properties[200]['{DAV:}getcontenttype'] = 'text/x-vcard';
+ }
+
+ }
+
+ /**
+ * This method is used to generate HTML output for the
+ * SabreForRainLoop\DAV\Browser\Plugin. This allows us to generate an interface users
+ * can use to create new calendars.
+ *
+ * @param DAV\INode $node
+ * @param string $output
+ * @return bool
+ */
+ public function htmlActionsPanel(DAV\INode $node, &$output) {
+
+ if (!$node instanceof UserAddressBooks)
+ return;
+
+ $output.= '
+ ';
+
+ return false;
+
+ }
+
+ /**
+ * This method allows us to intercept the 'mkcalendar' sabreAction. This
+ * action enables the user to create new calendars from the browser plugin.
+ *
+ * @param string $uri
+ * @param string $action
+ * @param array $postVars
+ * @return bool
+ */
+ public function browserPostAction($uri, $action, array $postVars) {
+
+ if ($action!=='mkaddressbook')
+ return;
+
+ $resourceType = array('{DAV:}collection','{urn:ietf:params:xml:ns:carddav}addressbook');
+ $properties = array();
+ if (isset($postVars['{DAV:}displayname'])) {
+ $properties['{DAV:}displayname'] = $postVars['{DAV:}displayname'];
+ }
+ $this->server->createCollection($uri . '/' . $postVars['name'],$resourceType,$properties);
+ return false;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/Property/SupportedAddressData.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/Property/SupportedAddressData.php
new file mode 100644
index 0000000..084c06f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/Property/SupportedAddressData.php
@@ -0,0 +1,72 @@
+ 'text/vcard', 'version' => '3.0'),
+ // array('contentType' => 'text/vcard', 'version' => '4.0'),
+ );
+ }
+
+ $this->supportedData = $supportedData;
+
+ }
+
+ /**
+ * Serializes the property in a DOMDocument
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $node
+ * @return void
+ */
+ public function serialize(DAV\Server $server,\DOMElement $node) {
+
+ $doc = $node->ownerDocument;
+
+ $prefix =
+ isset($server->xmlNamespaces[CardDAV\Plugin::NS_CARDDAV]) ?
+ $server->xmlNamespaces[CardDAV\Plugin::NS_CARDDAV] :
+ 'card';
+
+ foreach($this->supportedData as $supported) {
+
+ $caldata = $doc->createElementNS(CardDAV\Plugin::NS_CARDDAV, $prefix . ':address-data-type');
+ $caldata->setAttribute('content-type',$supported['contentType']);
+ $caldata->setAttribute('version',$supported['version']);
+ $node->appendChild($caldata);
+
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/UserAddressBooks.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/UserAddressBooks.php
new file mode 100644
index 0000000..0970fe3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/UserAddressBooks.php
@@ -0,0 +1,260 @@
+carddavBackend = $carddavBackend;
+ $this->principalUri = $principalUri;
+
+ }
+
+ /**
+ * Returns the name of this object
+ *
+ * @return string
+ */
+ public function getName() {
+
+ list(,$name) = DAV\URLUtil::splitPath($this->principalUri);
+ return $name;
+
+ }
+
+ /**
+ * Updates the name of this object
+ *
+ * @param string $name
+ * @return void
+ */
+ public function setName($name) {
+
+ throw new DAV\Exception\MethodNotAllowed();
+
+ }
+
+ /**
+ * Deletes this object
+ *
+ * @return void
+ */
+ public function delete() {
+
+ throw new DAV\Exception\MethodNotAllowed();
+
+ }
+
+ /**
+ * Returns the last modification date
+ *
+ * @return int
+ */
+ public function getLastModified() {
+
+ return null;
+
+ }
+
+ /**
+ * Creates a new file under this object.
+ *
+ * This is currently not allowed
+ *
+ * @param string $filename
+ * @param resource $data
+ * @return void
+ */
+ public function createFile($filename, $data=null) {
+
+ throw new DAV\Exception\MethodNotAllowed('Creating new files in this collection is not supported');
+
+ }
+
+ /**
+ * Creates a new directory under this object.
+ *
+ * This is currently not allowed.
+ *
+ * @param string $filename
+ * @return void
+ */
+ public function createDirectory($filename) {
+
+ throw new DAV\Exception\MethodNotAllowed('Creating new collections in this collection is not supported');
+
+ }
+
+ /**
+ * Returns a single calendar, by name
+ *
+ * @param string $name
+ * @todo needs optimizing
+ * @return \AddressBook
+ */
+ public function getChild($name) {
+
+ foreach($this->getChildren() as $child) {
+ if ($name==$child->getName())
+ return $child;
+
+ }
+ throw new DAV\Exception\NotFound('Addressbook with name \'' . $name . '\' could not be found');
+
+ }
+
+ /**
+ * Returns a list of addressbooks
+ *
+ * @return array
+ */
+ public function getChildren() {
+
+ $addressbooks = $this->carddavBackend->getAddressbooksForUser($this->principalUri);
+ $objs = array();
+ foreach($addressbooks as $addressbook) {
+ $objs[] = new AddressBook($this->carddavBackend, $addressbook);
+ }
+ return $objs;
+
+ }
+
+ /**
+ * Creates a new addressbook
+ *
+ * @param string $name
+ * @param array $resourceType
+ * @param array $properties
+ * @return void
+ */
+ public function createExtendedCollection($name, array $resourceType, array $properties) {
+
+ if (!in_array('{'.Plugin::NS_CARDDAV.'}addressbook',$resourceType) || count($resourceType)!==2) {
+ throw new DAV\Exception\InvalidResourceType('Unknown resourceType for this collection');
+ }
+ $this->carddavBackend->createAddressBook($this->principalUri, $name, $properties);
+
+ }
+
+ /**
+ * Returns the owner principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getOwner() {
+
+ return $this->principalUri;
+
+ }
+
+ /**
+ * Returns a group principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getGroup() {
+
+ return null;
+
+ }
+
+ /**
+ * Returns a list of ACE's for this node.
+ *
+ * Each ACE has the following properties:
+ * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
+ * currently the only supported privileges
+ * * 'principal', a url to the principal who owns the node
+ * * 'protected' (optional), indicating that this ACE is not allowed to
+ * be updated.
+ *
+ * @return array
+ */
+ public function getACL() {
+
+ return array(
+ array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->principalUri,
+ 'protected' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}write',
+ 'principal' => $this->principalUri,
+ 'protected' => true,
+ ),
+
+ );
+
+ }
+
+ /**
+ * Updates the ACL
+ *
+ * This method will receive a list of new ACE's.
+ *
+ * @param array $acl
+ * @return void
+ */
+ public function setACL(array $acl) {
+
+ throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported');
+
+ }
+
+ /**
+ * Returns the list of supported privileges for this node.
+ *
+ * The returned data structure is a list of nested privileges.
+ * See SabreForRainLoop\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
+ * standard structure.
+ *
+ * If null is returned from this method, the default privilege set is used,
+ * which is fine for most common usecases.
+ *
+ * @return array|null
+ */
+ public function getSupportedPrivilegeSet() {
+
+ return null;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/VCFExportPlugin.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/VCFExportPlugin.php
new file mode 100644
index 0000000..081bdd2
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/VCFExportPlugin.php
@@ -0,0 +1,108 @@
+server = $server;
+ $this->server->subscribeEvent('beforeMethod',array($this,'beforeMethod'), 90);
+
+ }
+
+ /**
+ * 'beforeMethod' event handles. This event handles intercepts GET requests ending
+ * with ?export
+ *
+ * @param string $method
+ * @param string $uri
+ * @return bool
+ */
+ public function beforeMethod($method, $uri) {
+
+ if ($method!='GET') return;
+ if ($this->server->httpRequest->getQueryString()!='export') return;
+
+ // splitting uri
+ list($uri) = explode('?',$uri,2);
+
+ $node = $this->server->tree->getNodeForPath($uri);
+
+ if (!($node instanceof IAddressBook)) return;
+
+ // Checking ACL, if available.
+ if ($aclPlugin = $this->server->getPlugin('acl')) {
+ $aclPlugin->checkPrivileges($uri, '{DAV:}read');
+ }
+
+ $this->server->httpResponse->setHeader('Content-Type','text/directory');
+ $this->server->httpResponse->sendStatus(200);
+
+ $nodes = $this->server->getPropertiesForPath($uri, array(
+ '{' . Plugin::NS_CARDDAV . '}address-data',
+ ),1);
+
+ $this->server->httpResponse->sendBody($this->generateVCF($nodes));
+
+ // Returning false to break the event chain
+ return false;
+
+ }
+
+ /**
+ * Merges all vcard objects, and builds one big vcf export
+ *
+ * @param array $nodes
+ * @return string
+ */
+ public function generateVCF(array $nodes) {
+
+ $output = "";
+
+ foreach($nodes as $node) {
+
+ if (!isset($node[200]['{' . Plugin::NS_CARDDAV . '}address-data'])) {
+ continue;
+ }
+ $nodeData = $node[200]['{' . Plugin::NS_CARDDAV . '}address-data'];
+
+ // Parsing this node so VObject can clean up the output.
+ $output .=
+ VObject\Reader::read($nodeData)->serialize();
+
+ }
+
+ return $output;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/Version.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/Version.php
new file mode 100644
index 0000000..d3ce981
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/CardDAV/Version.php
@@ -0,0 +1,26 @@
+currentUser;
+ }
+
+
+ /**
+ * Authenticates the user based on the current request.
+ *
+ * If authentication is successful, true must be returned.
+ * If authentication fails, an exception must be thrown.
+ *
+ * @param DAV\Server $server
+ * @param string $realm
+ * @throws DAV\Exception\NotAuthenticated
+ * @return bool
+ */
+ public function authenticate(DAV\Server $server, $realm) {
+
+ $auth = new HTTP\BasicAuth();
+ $auth->setHTTPRequest($server->httpRequest);
+ $auth->setHTTPResponse($server->httpResponse);
+ $auth->setRealm($realm);
+ $userpass = $auth->getUserPass();
+ if (!$userpass) {
+ $auth->requireLogin();
+ throw new DAV\Exception\NotAuthenticated('No basic authentication headers were found');
+ }
+
+ // Authenticates the user
+ if (!$this->validateUserPass($userpass[0],$userpass[1])) {
+ $auth->requireLogin();
+ throw new DAV\Exception\NotAuthenticated('Username or password does not match');
+ }
+ $this->currentUser = $userpass[0];
+ return true;
+ }
+
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractDigest.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractDigest.php
new file mode 100644
index 0000000..ca642c6
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Auth/Backend/AbstractDigest.php
@@ -0,0 +1,101 @@
+setHTTPRequest($server->httpRequest);
+ $digest->setHTTPResponse($server->httpResponse);
+
+ $digest->setRealm($realm);
+ $digest->init();
+
+ $username = $digest->getUsername();
+
+ // No username was given
+ if (!$username) {
+ $digest->requireLogin();
+ throw new DAV\Exception\NotAuthenticated('No digest authentication headers were found');
+ }
+
+ $hash = $this->getDigestHash($realm, $username);
+ // If this was false, the user account didn't exist
+ if ($hash===false || is_null($hash)) {
+ $digest->requireLogin();
+ throw new DAV\Exception\NotAuthenticated('The supplied username was not on file');
+ }
+ if (!is_string($hash)) {
+ throw new DAV\Exception('The returned value from getDigestHash must be a string or null');
+ }
+
+ // If this was false, the password or part of the hash was incorrect.
+ if (!$digest->validateA1($hash)) {
+ $digest->requireLogin();
+ throw new DAV\Exception\NotAuthenticated('Incorrect username');
+ }
+
+ $this->currentUser = $username;
+ return true;
+
+ }
+
+ /**
+ * Returns the currently logged in username.
+ *
+ * @return string|null
+ */
+ public function getCurrentUser() {
+
+ return $this->currentUser;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Auth/Backend/Apache.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Auth/Backend/Apache.php
new file mode 100644
index 0000000..be19a68
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Auth/Backend/Apache.php
@@ -0,0 +1,63 @@
+httpRequest->getRawServerValue('REMOTE_USER');
+ if (is_null($remoteUser)) {
+ throw new DAV\Exception('We did not receive the $_SERVER[REMOTE_USER] property. This means that apache might have been misconfigured');
+ }
+
+ $this->remoteUser = $remoteUser;
+ return true;
+
+ }
+
+ /**
+ * Returns information about the currently logged in user.
+ *
+ * If nobody is currently logged in, this method should return null.
+ *
+ * @return array|null
+ */
+ public function getCurrentUser() {
+
+ return $this->remoteUser;
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Auth/Backend/BackendInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Auth/Backend/BackendInterface.php
new file mode 100644
index 0000000..1193489
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Auth/Backend/BackendInterface.php
@@ -0,0 +1,36 @@
+loadFile($filename);
+
+ }
+
+ /**
+ * Loads an htdigest-formatted file. This method can be called multiple times if
+ * more than 1 file is used.
+ *
+ * @param string $filename
+ * @return void
+ */
+ public function loadFile($filename) {
+
+ foreach(file($filename,FILE_IGNORE_NEW_LINES) as $line) {
+
+ if (substr_count($line, ":") !== 2)
+ throw new DAV\Exception('Malformed htdigest file. Every line should contain 2 colons');
+
+ list($username,$realm,$A1) = explode(':',$line);
+
+ if (!preg_match('/^[a-zA-Z0-9]{32}$/', $A1))
+ throw new DAV\Exception('Malformed htdigest file. Invalid md5 hash');
+
+ $this->users[$realm . ':' . $username] = $A1;
+
+ }
+
+ }
+
+ /**
+ * Returns a users' information
+ *
+ * @param string $realm
+ * @param string $username
+ * @return string
+ */
+ public function getDigestHash($realm, $username) {
+
+ return isset($this->users[$realm . ':' . $username])?$this->users[$realm . ':' . $username]:false;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Auth/Backend/PDO.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Auth/Backend/PDO.php
new file mode 100644
index 0000000..7e8e31d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Auth/Backend/PDO.php
@@ -0,0 +1,65 @@
+pdo = $pdo;
+ $this->tableName = $tableName;
+
+ }
+
+ /**
+ * Returns the digest hash for a user.
+ *
+ * @param string $realm
+ * @param string $username
+ * @return string|null
+ */
+ public function getDigestHash($realm,$username) {
+
+ $stmt = $this->pdo->prepare('SELECT username, digesta1 FROM '.$this->tableName.' WHERE username = ?');
+ $stmt->execute(array($username));
+ $result = $stmt->fetchAll();
+
+ if (!count($result)) return;
+
+ return $result[0]['digesta1'];
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Auth/Plugin.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Auth/Plugin.php
new file mode 100644
index 0000000..ade6a5f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Auth/Plugin.php
@@ -0,0 +1,112 @@
+authBackend = $authBackend;
+ $this->realm = $realm;
+
+ }
+
+ /**
+ * Initializes the plugin. This function is automatically called by the server
+ *
+ * @param DAV\Server $server
+ * @return void
+ */
+ public function initialize(DAV\Server $server) {
+
+ $this->server = $server;
+ $this->server->subscribeEvent('beforeMethod',array($this,'beforeMethod'),10);
+
+ }
+
+ /**
+ * Returns a plugin name.
+ *
+ * Using this name other plugins will be able to access other plugins
+ * using DAV\Server::getPlugin
+ *
+ * @return string
+ */
+ public function getPluginName() {
+
+ return 'auth';
+
+ }
+
+ /**
+ * Returns the current users' principal uri.
+ *
+ * If nobody is logged in, this will return null.
+ *
+ * @return string|null
+ */
+ public function getCurrentUser() {
+
+ $userInfo = $this->authBackend->getCurrentUser();
+ if (!$userInfo) return null;
+
+ return $userInfo;
+
+ }
+
+ /**
+ * This method is called before any HTTP method and forces users to be authenticated
+ *
+ * @param string $method
+ * @param string $uri
+ * @throws SabreForRainLoop\DAV\Exception\NotAuthenticated
+ * @return bool
+ */
+ public function beforeMethod($method, $uri) {
+
+ $this->authBackend->authenticate($this->server,$this->realm);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/GuessContentType.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/GuessContentType.php
new file mode 100644
index 0000000..c787fdd
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/GuessContentType.php
@@ -0,0 +1,99 @@
+ 'image/jpeg',
+ 'gif' => 'image/gif',
+ 'png' => 'image/png',
+
+ // groupware
+ 'ics' => 'text/calendar',
+ 'vcf' => 'text/x-vcard',
+
+ // text
+ 'txt' => 'text/plain',
+
+ );
+
+ /**
+ * Initializes the plugin
+ *
+ * @param DAV\Server $server
+ * @return void
+ */
+ public function initialize(DAV\Server $server) {
+
+ // Using a relatively low priority (200) to allow other extensions
+ // to set the content-type first.
+ $server->subscribeEvent('afterGetProperties',array($this,'afterGetProperties'),200);
+
+ }
+
+ /**
+ * Handler for teh afterGetProperties event
+ *
+ * @param string $path
+ * @param array $properties
+ * @return void
+ */
+ public function afterGetProperties($path, &$properties) {
+
+ if (array_key_exists('{DAV:}getcontenttype', $properties[404])) {
+
+ list(, $fileName) = DAV\URLUtil::splitPath($path);
+ $contentType = $this->getContentType($fileName);
+
+ if ($contentType) {
+ $properties[200]['{DAV:}getcontenttype'] = $contentType;
+ unset($properties[404]['{DAV:}getcontenttype']);
+ }
+
+ }
+
+ }
+
+ /**
+ * Simple method to return the contenttype
+ *
+ * @param string $fileName
+ * @return string
+ */
+ protected function getContentType($fileName) {
+
+ // Just grabbing the extension
+ $extension = strtolower(substr($fileName,strrpos($fileName,'.')+1));
+ if (isset($this->extensionMap[$extension]))
+ return $this->extensionMap[$extension];
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/MapGetToPropFind.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/MapGetToPropFind.php
new file mode 100644
index 0000000..3792252
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/MapGetToPropFind.php
@@ -0,0 +1,57 @@
+server = $server;
+ $this->server->subscribeEvent('beforeMethod',array($this,'httpGetInterceptor'));
+ }
+
+ /**
+ * This method intercepts GET requests to non-files, and changes it into an HTTP PROPFIND request
+ *
+ * @param string $method
+ * @param string $uri
+ * @return bool
+ */
+ public function httpGetInterceptor($method, $uri) {
+
+ if ($method!='GET') return true;
+
+ $node = $this->server->tree->getNodeForPath($uri);
+ if ($node instanceof DAV\IFile) return;
+
+ $this->server->invokeMethod('PROPFIND',$uri);
+ return false;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/Plugin.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/Plugin.php
new file mode 100644
index 0000000..d19ba58
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/Plugin.php
@@ -0,0 +1,491 @@
+ 'icons/file',
+ 'SabreForRainLoop\\DAV\\ICollection' => 'icons/collection',
+ 'SabreForRainLoop\\DAVACL\\IPrincipal' => 'icons/principal',
+ 'SabreForRainLoop\\CalDAV\\ICalendar' => 'icons/calendar',
+ 'SabreForRainLoop\\CardDAV\\IAddressBook' => 'icons/addressbook',
+ 'SabreForRainLoop\\CardDAV\\ICard' => 'icons/card',
+ );
+
+ /**
+ * The file extension used for all icons
+ *
+ * @var string
+ */
+ public $iconExtension = '.png';
+
+ /**
+ * reference to server class
+ *
+ * @var SabreForRainLoop\DAV\Server
+ */
+ protected $server;
+
+ /**
+ * enablePost turns on the 'actions' panel, which allows people to create
+ * folders and upload files straight from a browser.
+ *
+ * @var bool
+ */
+ protected $enablePost = true;
+
+ /**
+ * By default the browser plugin will generate a favicon and other images.
+ * To turn this off, set this property to false.
+ *
+ * @var bool
+ */
+ protected $enableAssets = true;
+
+ /**
+ * Creates the object.
+ *
+ * By default it will allow file creation and uploads.
+ * Specify the first argument as false to disable this
+ *
+ * @param bool $enablePost
+ * @param bool $enableAssets
+ */
+ public function __construct($enablePost=true, $enableAssets = true) {
+
+ $this->enablePost = $enablePost;
+ $this->enableAssets = $enableAssets;
+
+ }
+
+ /**
+ * Initializes the plugin and subscribes to events
+ *
+ * @param DAV\Server $server
+ * @return void
+ */
+ public function initialize(DAV\Server $server) {
+
+ $this->server = $server;
+ $this->server->subscribeEvent('beforeMethod',array($this,'httpGetInterceptor'));
+ $this->server->subscribeEvent('onHTMLActionsPanel', array($this, 'htmlActionsPanel'),200);
+ if ($this->enablePost) $this->server->subscribeEvent('unknownMethod',array($this,'httpPOSTHandler'));
+ }
+
+ /**
+ * This method intercepts GET requests to collections and returns the html
+ *
+ * @param string $method
+ * @param string $uri
+ * @return bool
+ */
+ public function httpGetInterceptor($method, $uri) {
+
+ if ($method !== 'GET') return true;
+
+ // We're not using straight-up $_GET, because we want everything to be
+ // unit testable.
+ $getVars = array();
+ parse_str($this->server->httpRequest->getQueryString(), $getVars);
+
+ if (isset($getVars['sabreAction']) && $getVars['sabreAction'] === 'asset' && isset($getVars['assetName'])) {
+ $this->serveAsset($getVars['assetName']);
+ return false;
+ }
+
+ try {
+ $node = $this->server->tree->getNodeForPath($uri);
+ } catch (DAV\Exception\NotFound $e) {
+ // We're simply stopping when the file isn't found to not interfere
+ // with other plugins.
+ return;
+ }
+ if ($node instanceof DAV\IFile)
+ return;
+
+ $this->server->httpResponse->sendStatus(200);
+ $this->server->httpResponse->setHeader('Content-Type','text/html; charset=utf-8');
+
+ $this->server->httpResponse->sendBody(
+ $this->generateDirectoryIndex($uri)
+ );
+
+ return false;
+
+ }
+
+ /**
+ * Handles POST requests for tree operations.
+ *
+ * @param string $method
+ * @param string $uri
+ * @return bool
+ */
+ public function httpPOSTHandler($method, $uri) {
+
+ if ($method!='POST') return;
+ $contentType = $this->server->httpRequest->getHeader('Content-Type');
+ list($contentType) = explode(';', $contentType);
+ if ($contentType !== 'application/x-www-form-urlencoded' &&
+ $contentType !== 'multipart/form-data') {
+ return;
+ }
+ $postVars = $this->server->httpRequest->getPostVars();
+
+ if (!isset($postVars['sabreAction']))
+ return;
+
+ if ($this->server->broadcastEvent('onBrowserPostAction', array($uri, $postVars['sabreAction'], $postVars))) {
+
+ switch($postVars['sabreAction']) {
+
+ case 'mkcol' :
+ if (isset($postVars['name']) && trim($postVars['name'])) {
+ // Using basename() because we won't allow slashes
+ list(, $folderName) = DAV\URLUtil::splitPath(trim($postVars['name']));
+ $this->server->createDirectory($uri . '/' . $folderName);
+ }
+ break;
+ case 'put' :
+ if ($_FILES) $file = current($_FILES);
+ else break;
+
+ list(, $newName) = DAV\URLUtil::splitPath(trim($file['name']));
+ if (isset($postVars['name']) && trim($postVars['name']))
+ $newName = trim($postVars['name']);
+
+ // Making sure we only have a 'basename' component
+ list(, $newName) = DAV\URLUtil::splitPath($newName);
+
+ if (is_uploaded_file($file['tmp_name'])) {
+ $this->server->createFile($uri . '/' . $newName, fopen($file['tmp_name'],'r'));
+ }
+ break;
+
+ }
+
+ }
+ $this->server->httpResponse->setHeader('Location',$this->server->httpRequest->getUri());
+ $this->server->httpResponse->sendStatus(302);
+ return false;
+
+ }
+
+ /**
+ * Escapes a string for html.
+ *
+ * @param string $value
+ * @return string
+ */
+ public function escapeHTML($value) {
+
+ return htmlspecialchars($value,ENT_QUOTES,'UTF-8');
+
+ }
+
+ /**
+ * Generates the html directory index for a given url
+ *
+ * @param string $path
+ * @return string
+ */
+ public function generateDirectoryIndex($path) {
+
+ $version = '';
+ if (DAV\Server::$exposeVersion) {
+ $version = DAV\Version::VERSION ."-". DAV\Version::STABILITY;
+ }
+
+ $html = "
+
+ Index for " . $this->escapeHTML($path) . "/ - SabreDAV " . $version . "
+
+ ";
+
+ if ($this->enableAssets) {
+ $html.=' ';
+ }
+
+ $html .= "
+
+ Index for " . $this->escapeHTML($path) . "/
+
+ Name Type Size Last modified
+ ";
+
+ $files = $this->server->getPropertiesForPath($path,array(
+ '{DAV:}displayname',
+ '{DAV:}resourcetype',
+ '{DAV:}getcontenttype',
+ '{DAV:}getcontentlength',
+ '{DAV:}getlastmodified',
+ ),1);
+
+ $parent = $this->server->tree->getNodeForPath($path);
+
+
+ if ($path) {
+
+ list($parentUri) = DAV\URLUtil::splitPath($path);
+ $fullPath = DAV\URLUtil::encodePath($this->server->getBaseUri() . $parentUri);
+
+ $icon = $this->enableAssets?' ':'';
+ $html.= "
+ $icon
+ ..
+ [parent]
+
+
+ ";
+
+ }
+
+ foreach($files as $file) {
+
+ // This is the current directory, we can skip it
+ if (rtrim($file['href'],'/')==$path) continue;
+
+ list(, $name) = DAV\URLUtil::splitPath($file['href']);
+
+ $type = null;
+
+
+ if (isset($file[200]['{DAV:}resourcetype'])) {
+ $type = $file[200]['{DAV:}resourcetype']->getValue();
+
+ // resourcetype can have multiple values
+ if (!is_array($type)) $type = array($type);
+
+ foreach($type as $k=>$v) {
+
+ // Some name mapping is preferred
+ switch($v) {
+ case '{DAV:}collection' :
+ $type[$k] = 'Collection';
+ break;
+ case '{DAV:}principal' :
+ $type[$k] = 'Principal';
+ break;
+ case '{urn:ietf:params:xml:ns:carddav}addressbook' :
+ $type[$k] = 'Addressbook';
+ break;
+ case '{urn:ietf:params:xml:ns:caldav}calendar' :
+ $type[$k] = 'Calendar';
+ break;
+ case '{urn:ietf:params:xml:ns:caldav}schedule-inbox' :
+ $type[$k] = 'Schedule Inbox';
+ break;
+ case '{urn:ietf:params:xml:ns:caldav}schedule-outbox' :
+ $type[$k] = 'Schedule Outbox';
+ break;
+ case '{http://calendarserver.org/ns/}calendar-proxy-read' :
+ $type[$k] = 'Proxy-Read';
+ break;
+ case '{http://calendarserver.org/ns/}calendar-proxy-write' :
+ $type[$k] = 'Proxy-Write';
+ break;
+ }
+
+ }
+ $type = implode(', ', $type);
+ }
+
+ // If no resourcetype was found, we attempt to use
+ // the contenttype property
+ if (!$type && isset($file[200]['{DAV:}getcontenttype'])) {
+ $type = $file[200]['{DAV:}getcontenttype'];
+ }
+ if (!$type) $type = 'Unknown';
+
+ $size = isset($file[200]['{DAV:}getcontentlength'])?(int)$file[200]['{DAV:}getcontentlength']:'';
+ $lastmodified = isset($file[200]['{DAV:}getlastmodified'])?$file[200]['{DAV:}getlastmodified']->getTime()->format(\DateTime::ATOM):'';
+
+ $fullPath = DAV\URLUtil::encodePath('/' . trim($this->server->getBaseUri() . ($path?$path . '/':'') . $name,'/'));
+
+ $displayName = isset($file[200]['{DAV:}displayname'])?$file[200]['{DAV:}displayname']:$name;
+
+ $displayName = $this->escapeHTML($displayName);
+ $type = $this->escapeHTML($type);
+
+ $icon = '';
+
+ if ($this->enableAssets) {
+ $node = $this->server->tree->getNodeForPath(($path?$path.'/':'') . $name);
+ foreach(array_reverse($this->iconMap) as $class=>$iconName) {
+
+ if ($node instanceof $class) {
+ $icon = ' ';
+ break;
+ }
+
+
+ }
+
+ }
+
+ $html.= "
+ $icon
+ {$displayName}
+ {$type}
+ {$size}
+ {$lastmodified}
+ ";
+
+ }
+
+ $html.= " ";
+
+ $output = '';
+
+ if ($this->enablePost) {
+ $this->server->broadcastEvent('onHTMLActionsPanel',array($parent, &$output));
+ }
+
+ $html.=$output;
+
+ $html.= "
+ Generated by SabreDAV " . $version . " (c)2007-2013 http://code.google.com/p/sabredav/
+
+ ";
+
+ return $html;
+
+ }
+
+ /**
+ * This method is used to generate the 'actions panel' output for
+ * collections.
+ *
+ * This specifically generates the interfaces for creating new files, and
+ * creating new directories.
+ *
+ * @param DAV\INode $node
+ * @param mixed $output
+ * @return void
+ */
+ public function htmlActionsPanel(DAV\INode $node, &$output) {
+
+ if (!$node instanceof DAV\ICollection)
+ return;
+
+ // We also know fairly certain that if an object is a non-extended
+ // SimpleCollection, we won't need to show the panel either.
+ if (get_class($node)==='SabreForRainLoop\\DAV\\SimpleCollection')
+ return;
+
+ $output.= '
+
+ ';
+
+ }
+
+ /**
+ * This method takes a path/name of an asset and turns it into url
+ * suiteable for http access.
+ *
+ * @param string $assetName
+ * @return string
+ */
+ protected function getAssetUrl($assetName) {
+
+ return $this->server->getBaseUri() . '?sabreAction=asset&assetName=' . urlencode($assetName);
+
+ }
+
+ /**
+ * This method returns a local pathname to an asset.
+ *
+ * @param string $assetName
+ * @return string
+ */
+ protected function getLocalAssetPath($assetName) {
+
+ $assetDir = __DIR__ . '/assets/';
+ $path = $assetDir . $assetName;
+
+ // Making sure people aren't trying to escape from the base path.
+ if (strpos(realpath($path), realpath($assetDir)) === 0) {
+ return $path;
+ }
+ throw new DAV\Exception\Forbidden('Path does not exist, or escaping from the base path was detected');
+ }
+
+ /**
+ * This method reads an asset from disk and generates a full http response.
+ *
+ * @param string $assetName
+ * @return void
+ */
+ protected function serveAsset($assetName) {
+
+ $assetPath = $this->getLocalAssetPath($assetName);
+ if (!file_exists($assetPath)) {
+ throw new DAV\Exception\NotFound('Could not find an asset with this name');
+ }
+ // Rudimentary mime type detection
+ switch(strtolower(substr($assetPath,strpos($assetPath,'.')+1))) {
+
+ case 'ico' :
+ $mime = 'image/vnd.microsoft.icon';
+ break;
+
+ case 'png' :
+ $mime = 'image/png';
+ break;
+
+ default:
+ $mime = 'application/octet-stream';
+ break;
+
+ }
+
+ $this->server->httpResponse->setHeader('Content-Type', $mime);
+ $this->server->httpResponse->setHeader('Content-Length', filesize($assetPath));
+ $this->server->httpResponse->setHeader('Cache-Control', 'public, max-age=1209600');
+ $this->server->httpResponse->sendStatus(200);
+ $this->server->httpResponse->sendBody(fopen($assetPath,'r'));
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/favicon.ico b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/favicon.ico
new file mode 100644
index 0000000..2b2c10a
Binary files /dev/null and b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/favicon.ico differ
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/addressbook.png b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/addressbook.png
new file mode 100644
index 0000000..c9acc84
Binary files /dev/null and b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/addressbook.png differ
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/calendar.png b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/calendar.png
new file mode 100644
index 0000000..3ecd6a8
Binary files /dev/null and b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/calendar.png differ
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/card.png b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/card.png
new file mode 100644
index 0000000..2ce9548
Binary files /dev/null and b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/card.png differ
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/collection.png b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/collection.png
new file mode 100644
index 0000000..156fa64
Binary files /dev/null and b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/collection.png differ
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/file.png b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/file.png
new file mode 100644
index 0000000..3b98551
Binary files /dev/null and b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/file.png differ
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/parent.png b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/parent.png
new file mode 100644
index 0000000..156fa64
Binary files /dev/null and b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/parent.png differ
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/principal.png b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/principal.png
new file mode 100644
index 0000000..f8988f8
Binary files /dev/null and b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Browser/assets/icons/principal.png differ
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Client.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Client.php
new file mode 100644
index 0000000..8941d74
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Client.php
@@ -0,0 +1,641 @@
+$validSetting = $settings[$validSetting];
+ }
+ }
+
+ if (isset($settings['authType'])) {
+ $this->authType = $settings['authType'];
+ } else {
+ $this->authType = self::AUTH_BASIC | self::AUTH_DIGEST;
+ }
+
+ $this->propertyMap['{DAV:}resourcetype'] = 'SabreForRainLoop\\DAV\\Property\\ResourceType';
+
+ }
+
+ /**
+ * Add trusted root certificates to the webdav client.
+ *
+ * The parameter certificates should be a absolute path to a file
+ * which contains all trusted certificates
+ *
+ * @param string $certificates
+ */
+ public function addTrustedCertificates($certificates) {
+ $this->trustedCertificates = $certificates;
+ }
+
+ /**
+ * Enables/disables SSL peer verification
+ *
+ * @param boolean $value
+ */
+ public function setVerifyPeer($value) {
+ $this->verifyPeer = $value;
+ }
+
+ /**
+ * Does a PROPFIND request
+ *
+ * The list of requested properties must be specified as an array, in clark
+ * notation.
+ *
+ * The returned array will contain a list of filenames as keys, and
+ * properties as values.
+ *
+ * The properties array will contain the list of properties. Only properties
+ * that are actually returned from the server (without error) will be
+ * returned, anything else is discarded.
+ *
+ * Depth should be either 0 or 1. A depth of 1 will cause a request to be
+ * made to the server to also return all child resources.
+ *
+ * @param string $url
+ * @param array $properties
+ * @param int $depth
+ * @return array
+ */
+ public function propFind($url, array $properties, $depth = 0) {
+
+ $body = '' . "\n";
+ $body.= '' . "\n";
+ $body.= ' ' . "\n";
+
+ foreach($properties as $property) {
+
+ list(
+ $namespace,
+ $elementName
+ ) = XMLUtil::parseClarkNotation($property);
+
+ if ($namespace === 'DAV:') {
+ $body.=' ' . "\n";
+ } else {
+ $body.=" \n";
+ }
+
+ }
+
+ $body.= ' ' . "\n";
+ $body.= ' ';
+
+ $response = $this->request('PROPFIND', $url, $body, array(
+ 'Depth' => $depth,
+ 'Content-Type' => 'application/xml'
+ ));
+
+ $result = $this->parseMultiStatus($response['body']);
+
+ // If depth was 0, we only return the top item
+ if ($depth===0) {
+ reset($result);
+ $result = current($result);
+ return isset($result[200])?$result[200]:array();
+ }
+
+ $newResult = array();
+ foreach($result as $href => $statusList) {
+
+ $newResult[$href] = isset($statusList[200])?$statusList[200]:array();
+
+ }
+
+ return $newResult;
+
+ }
+
+ /**
+ * Updates a list of properties on the server
+ *
+ * The list of properties must have clark-notation properties for the keys,
+ * and the actual (string) value for the value. If the value is null, an
+ * attempt is made to delete the property.
+ *
+ * @todo Must be building the request using the DOM, and does not yet
+ * support complex properties.
+ * @param string $url
+ * @param array $properties
+ * @return void
+ */
+ public function propPatch($url, array $properties) {
+
+ $body = '' . "\n";
+ $body.= '' . "\n";
+
+ foreach($properties as $propName => $propValue) {
+
+ list(
+ $namespace,
+ $elementName
+ ) = XMLUtil::parseClarkNotation($propName);
+
+ if ($propValue === null) {
+
+ $body.="\n";
+
+ if ($namespace === 'DAV:') {
+ $body.=' ' . "\n";
+ } else {
+ $body.=" \n";
+ }
+
+ $body.=" \n";
+
+ } else {
+
+ $body.="\n";
+ if ($namespace === 'DAV:') {
+ $body.=' ';
+ } else {
+ $body.=" ";
+ }
+ // Shitty.. i know
+ $body.=htmlspecialchars($propValue, ENT_NOQUOTES, 'UTF-8');
+ if ($namespace === 'DAV:') {
+ $body.=' ' . "\n";
+ } else {
+ $body.="\n";
+ }
+ $body.=" \n";
+
+ }
+
+ }
+
+ $body.= ' ';
+
+ $this->request('PROPPATCH', $url, $body, array(
+ 'Content-Type' => 'application/xml'
+ ));
+
+ }
+
+ /**
+ * Performs an HTTP options request
+ *
+ * This method returns all the features from the 'DAV:' header as an array.
+ * If there was no DAV header, or no contents this method will return an
+ * empty array.
+ *
+ * @return array
+ */
+ public function options() {
+
+ $result = $this->request('OPTIONS');
+ if (!isset($result['headers']['dav'])) {
+ return array();
+ }
+
+ $features = explode(',', $result['headers']['dav']);
+ foreach($features as &$v) {
+ $v = trim($v);
+ }
+ return $features;
+
+ }
+
+ /**
+ * Performs an actual HTTP request, and returns the result.
+ *
+ * If the specified url is relative, it will be expanded based on the base
+ * url.
+ *
+ * The returned array contains 3 keys:
+ * * body - the response body
+ * * httpCode - a HTTP code (200, 404, etc)
+ * * headers - a list of response http headers. The header names have
+ * been lowercased.
+ *
+ * @param string $method
+ * @param string $url
+ * @param string $body
+ * @param array $headers
+ * @return array
+ */
+ public function request($method, $url = '', $body = null, $headers = array()) {
+
+ $url = $this->getAbsoluteUrl($url);
+
+ $curlSettings = array(
+ CURLOPT_RETURNTRANSFER => true,
+ // Return headers as part of the response
+ CURLOPT_HEADER => true,
+ CURLOPT_POSTFIELDS => $body,
+ CURLOPT_USERAGENT => 'RainLoop DAV Client', // TODO rainloop
+ // Automatically follow redirects
+ CURLOPT_FOLLOWLOCATION => true,
+ CURLOPT_MAXREDIRS => 5,
+ );
+
+ if($this->verifyPeer !== null) {
+ $curlSettings[CURLOPT_SSL_VERIFYPEER] = $this->verifyPeer;
+ // TODO rainloop
+ if (!$this->verifyPeer) {
+ $curlSettings[CURLOPT_SSL_VERIFYHOST] = 0;
+ } // ---
+ }
+
+ if($this->trustedCertificates) {
+ $curlSettings[CURLOPT_CAINFO] = $this->trustedCertificates;
+ }
+
+ switch ($method) {
+ case 'HEAD' :
+
+ // do not read body with HEAD requests (this is necessary because cURL does not ignore the body with HEAD
+ // requests when the Content-Length header is given - which in turn is perfectly valid according to HTTP
+ // specs...) cURL does unfortunately return an error in this case ("transfer closed transfer closed with
+ // ... bytes remaining to read") this can be circumvented by explicitly telling cURL to ignore the
+ // response body
+ $curlSettings[CURLOPT_NOBODY] = true;
+ $curlSettings[CURLOPT_CUSTOMREQUEST] = 'HEAD';
+ break;
+
+ default:
+ $curlSettings[CURLOPT_CUSTOMREQUEST] = $method;
+ break;
+
+ }
+
+ // Adding HTTP headers
+ $nHeaders = array();
+ foreach($headers as $key=>$value) {
+
+ $nHeaders[] = $key . ': ' . $value;
+
+ }
+ $curlSettings[CURLOPT_HTTPHEADER] = $nHeaders;
+
+ if ($this->proxy) {
+ $curlSettings[CURLOPT_PROXY] = $this->proxy;
+ }
+
+ if ($this->userName && $this->authType) {
+ $curlType = 0;
+ if ($this->authType & self::AUTH_BASIC) {
+ $curlType |= CURLAUTH_BASIC;
+ }
+ if ($this->authType & self::AUTH_DIGEST) {
+ $curlType |= CURLAUTH_DIGEST;
+ }
+ $curlSettings[CURLOPT_HTTPAUTH] = $curlType;
+ $curlSettings[CURLOPT_USERPWD] = $this->userName . ':' . $this->password;
+ }
+
+// var_dump($url);
+// var_dump($curlSettings);
+
+ list(
+ $response,
+ $curlInfo,
+ $curlErrNo,
+ $curlError
+ ) = $this->curlRequest($url, $curlSettings);
+
+// var_dump($response);
+
+ $headerBlob = substr($response, 0, $curlInfo['header_size']);
+ $response = substr($response, $curlInfo['header_size']);
+
+
+ // In the case of 100 Continue, or redirects we'll have multiple lists
+ // of headers for each separate HTTP response. We can easily split this
+ // because they are separated by \r\n\r\n
+ $headerBlob = explode("\r\n\r\n", trim($headerBlob, "\r\n"));
+
+ // We only care about the last set of headers
+ $headerBlob = $headerBlob[count($headerBlob)-1];
+
+ // Splitting headers
+ $headerBlob = explode("\r\n", $headerBlob);
+
+ $headers = array();
+ foreach($headerBlob as $header) {
+ $parts = explode(':', $header, 2);
+ if (count($parts)==2) {
+ $headers[strtolower(trim($parts[0]))] = trim($parts[1]);
+ }
+ }
+
+ $response = array(
+ 'body' => $response,
+ 'statusCode' => $curlInfo['http_code'],
+ 'headers' => $headers
+ );
+
+ if ($curlErrNo) {
+ throw new Exception('[CURL] Error while making request: ' . $curlError . ' (error code: ' . $curlErrNo . ')');
+ }
+
+ if ($response['statusCode']>=400) {
+ switch ($response['statusCode']) {
+ case 400 :
+ throw new Exception\BadRequest('Bad request');
+ case 401 :
+ throw new Exception\NotAuthenticated('Not authenticated');
+ case 402 :
+ throw new Exception\PaymentRequired('Payment required');
+ case 403 :
+ throw new Exception\Forbidden('Forbidden');
+ case 404:
+ throw new Exception\NotFound('Resource not found.');
+ case 405 :
+ throw new Exception\MethodNotAllowed('Method not allowed');
+ case 409 :
+ throw new Exception\Conflict('Conflict');
+ case 412 :
+ throw new Exception\PreconditionFailed('Precondition failed');
+ case 416 :
+ throw new Exception\RequestedRangeNotSatisfiable('Requested Range Not Satisfiable');
+ case 500 :
+ throw new Exception('Internal server error');
+ case 501 :
+ throw new Exception\NotImplemented('Not Implemented');
+ case 507 :
+ throw new Exception\InsufficientStorage('Insufficient storage');
+ default:
+ throw new Exception('HTTP error response. (errorcode ' . $response['statusCode'] . ')');
+ }
+ }
+
+ return $response;
+
+ }
+
+ /**
+ * Wrapper for all curl functions.
+ *
+ * The only reason this was split out in a separate method, is so it
+ * becomes easier to unittest.
+ *
+ * @param string $url
+ * @param array $settings
+ * @return array
+ */
+ // @codeCoverageIgnoreStart
+ protected function curlRequest($url, $settings) {
+
+ // TODO rainloop
+ $curl = curl_init($url);
+ $sSafeMode = strtolower(trim(@ini_get('safe_mode')));
+ $bSafeMode = 'on' === $sSafeMode || '1' === $sSafeMode;
+
+ if (!$bSafeMode && ini_get('open_basedir') === '')
+ {
+ curl_setopt_array($curl, $settings);
+ $data = curl_exec($curl);
+ }
+ else
+ {
+ $settings[CURLOPT_FOLLOWLOCATION] = false;
+ curl_setopt_array($curl, $settings);
+
+ $max_redirects = isset($settings[CURLOPT_MAXREDIRS]) ? $settings[CURLOPT_MAXREDIRS] : 5;
+ $mr = $max_redirects;
+ if ($mr > 0)
+ {
+ $newurl = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL);
+
+ $rcurl = curl_copy_handle($curl);
+ curl_setopt($rcurl, CURLOPT_HEADER, true);
+ curl_setopt($rcurl, CURLOPT_NOBODY, true);
+ curl_setopt($rcurl, CURLOPT_FORBID_REUSE, false);
+ curl_setopt($rcurl, CURLOPT_RETURNTRANSFER, true);
+ do
+ {
+ curl_setopt($rcurl, CURLOPT_URL, $newurl);
+ $header = curl_exec($rcurl);
+ if (curl_errno($rcurl))
+ {
+ $code = 0;
+ }
+ else
+ {
+ $code = curl_getinfo($rcurl, CURLINFO_HTTP_CODE);
+ if ($code == 301 || $code == 302)
+ {
+ $matches = array();
+ preg_match('/Location:(.*?)\n/', $header, $matches);
+ $newurl = trim(array_pop($matches));
+ }
+ else
+ {
+ $code = 0;
+ }
+ }
+ } while ($code && --$mr);
+
+ curl_close($rcurl);
+ if ($mr > 0)
+ {
+ curl_setopt($curl, CURLOPT_URL, $newurl);
+ }
+ }
+
+ if ($mr == 0 && $max_redirects > 0)
+ {
+ $data = false;
+ }
+ else
+ {
+ $data = curl_exec($curl);
+ }
+ }
+
+ return array(
+ $data,
+ curl_getinfo($curl),
+ curl_errno($curl),
+ curl_error($curl)
+ );
+
+ }
+ // @codeCoverageIgnoreEnd
+
+ /**
+ * Returns the full url based on the given url (which may be relative). All
+ * urls are expanded based on the base url as given by the server.
+ *
+ * @param string $url
+ * @return string
+ */
+ protected function getAbsoluteUrl($url) {
+
+ // If the url starts with http:// or https://, the url is already absolute.
+ if (preg_match('/^http(s?):\/\//', $url)) {
+ return $url;
+ }
+
+ // If the url starts with a slash, we must calculate the url based off
+ // the root of the base url.
+ if (strpos($url,'/') === 0) {
+ $parts = parse_url($this->baseUri);
+ return $parts['scheme'] . '://' . $parts['host'] . (isset($parts['port'])?':' . $parts['port']:'') . $url;
+ }
+
+ // Otherwise...
+ return $this->baseUri . $url;
+
+ }
+
+ /**
+ * Parses a WebDAV multistatus response body
+ *
+ * This method returns an array with the following structure
+ *
+ * array(
+ * 'url/to/resource' => array(
+ * '200' => array(
+ * '{DAV:}property1' => 'value1',
+ * '{DAV:}property2' => 'value2',
+ * ),
+ * '404' => array(
+ * '{DAV:}property1' => null,
+ * '{DAV:}property2' => null,
+ * ),
+ * )
+ * 'url/to/resource2' => array(
+ * .. etc ..
+ * )
+ * )
+ *
+ *
+ * @param string $body xml body
+ * @return array
+ */
+ public function parseMultiStatus($body) {
+
+ $body = XMLUtil::convertDAVNamespace($body);
+
+ $responseXML = simplexml_load_string($body, null, LIBXML_NOBLANKS | LIBXML_NOCDATA);
+ if ($responseXML===false) {
+ throw new \InvalidArgumentException('The passed data is not valid XML');
+ }
+
+ $responseXML->registerXPathNamespace('d', 'urn:DAV');
+
+ $propResult = array();
+
+ foreach($responseXML->xpath('d:response') as $response) {
+ $response->registerXPathNamespace('d', 'urn:DAV');
+ $href = $response->xpath('d:href');
+ $href = (string)$href[0];
+
+ $properties = array();
+
+ foreach($response->xpath('d:propstat') as $propStat) {
+
+ $propStat->registerXPathNamespace('d', 'urn:DAV');
+ $status = $propStat->xpath('d:status');
+ list($httpVersion, $statusCode, $message) = explode(' ', (string)$status[0],3);
+
+ // Only using the propertymap for results with status 200.
+ $propertyMap = $statusCode==='200' ? $this->propertyMap : array();
+
+ $properties[$statusCode] = XMLUtil::parseProperties(dom_import_simplexml($propStat), $propertyMap);
+
+ }
+
+ $propResult[$href] = $properties;
+
+ }
+
+ return $propResult;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Collection.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Collection.php
new file mode 100644
index 0000000..1e070e7
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Collection.php
@@ -0,0 +1,110 @@
+getChildren() as $child) {
+
+ if ($child->getName()==$name) return $child;
+
+ }
+ throw new Exception\NotFound('File not found: ' . $name);
+
+ }
+
+ /**
+ * Checks is a child-node exists.
+ *
+ * It is generally a good idea to try and override this. Usually it can be optimized.
+ *
+ * @param string $name
+ * @return bool
+ */
+ public function childExists($name) {
+
+ try {
+
+ $this->getChild($name);
+ return true;
+
+ } catch(Exception\NotFound $e) {
+
+ return false;
+
+ }
+
+ }
+
+ /**
+ * Creates a new file in the directory
+ *
+ * Data will either be supplied as a stream resource, or in certain cases
+ * as a string. Keep in mind that you may have to support either.
+ *
+ * After succesful creation of the file, you may choose to return the ETag
+ * of the new file here.
+ *
+ * The returned ETag must be surrounded by double-quotes (The quotes should
+ * be part of the actual string).
+ *
+ * If you cannot accurately determine the ETag, you should not return it.
+ * If you don't store the file exactly as-is (you're transforming it
+ * somehow) you should also not return an ETag.
+ *
+ * This means that if a subsequent GET to this new file does not exactly
+ * return the same contents of what was submitted here, you are strongly
+ * recommended to omit the ETag.
+ *
+ * @param string $name Name of the file
+ * @param resource|string $data Initial payload
+ * @return null|string
+ */
+ public function createFile($name, $data = null) {
+
+ throw new Exception\Forbidden('Permission denied to create file (filename ' . $name . ')');
+
+ }
+
+ /**
+ * Creates a new subdirectory
+ *
+ * @param string $name
+ * @throws Exception\Forbidden
+ * @return void
+ */
+ public function createDirectory($name) {
+
+ throw new Exception\Forbidden('Permission denied to create directory');
+
+ }
+
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception.php
new file mode 100644
index 0000000..7140bdf
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception.php
@@ -0,0 +1,64 @@
+lock) {
+ $error = $errorNode->ownerDocument->createElementNS('DAV:','d:no-conflicting-lock');
+ $errorNode->appendChild($error);
+ if (!is_object($this->lock)) var_dump($this->lock);
+ $error->appendChild($errorNode->ownerDocument->createElementNS('DAV:','d:href',$this->lock->uri));
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/FileNotFound.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/FileNotFound.php
new file mode 100644
index 0000000..24a0e64
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/FileNotFound.php
@@ -0,0 +1,19 @@
+ownerDocument->createElementNS('DAV:','d:valid-resourcetype');
+ $errorNode->appendChild($error);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/LockTokenMatchesRequestUri.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/LockTokenMatchesRequestUri.php
new file mode 100644
index 0000000..6fbd288
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/LockTokenMatchesRequestUri.php
@@ -0,0 +1,41 @@
+message = 'The locktoken supplied does not match any locks on this entity';
+
+ }
+
+ /**
+ * This method allows the exception to include additional information into the WebDAV error response
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $errorNode
+ * @return void
+ */
+ public function serialize(DAV\Server $server,\DOMElement $errorNode) {
+
+ $error = $errorNode->ownerDocument->createElementNS('DAV:','d:lock-token-matches-request-uri');
+ $errorNode->appendChild($error);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/Locked.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/Locked.php
new file mode 100644
index 0000000..ebcc46c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/Locked.php
@@ -0,0 +1,73 @@
+lock = $lock;
+
+ }
+
+ /**
+ * Returns the HTTP statuscode for this exception
+ *
+ * @return int
+ */
+ public function getHTTPCode() {
+
+ return 423;
+
+ }
+
+ /**
+ * This method allows the exception to include additional information into the WebDAV error response
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $errorNode
+ * @return void
+ */
+ public function serialize(DAV\Server $server,\DOMElement $errorNode) {
+
+ if ($this->lock) {
+ $error = $errorNode->ownerDocument->createElementNS('DAV:','d:lock-token-submitted');
+ $errorNode->appendChild($error);
+
+ $href = $errorNode->ownerDocument->createElementNS('DAV:','d:href');
+ $href->appendChild($errorNode->ownerDocument->createTextNode($this->lock->uri));
+ $error->appendChild(
+ $href
+ );
+ }
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/MethodNotAllowed.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/MethodNotAllowed.php
new file mode 100644
index 0000000..0c2b67e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/MethodNotAllowed.php
@@ -0,0 +1,45 @@
+getAllowedMethods($server->getRequestUri());
+
+ return array(
+ 'Allow' => strtoupper(implode(', ',$methods)),
+ );
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/NotAuthenticated.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/NotAuthenticated.php
new file mode 100644
index 0000000..99e2ad2
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/NotAuthenticated.php
@@ -0,0 +1,30 @@
+header = $header;
+
+ }
+
+ /**
+ * Returns the HTTP statuscode for this exception
+ *
+ * @return int
+ */
+ public function getHTTPCode() {
+
+ return 412;
+
+ }
+
+ /**
+ * This method allows the exception to include additional information into the WebDAV error response
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $errorNode
+ * @return void
+ */
+ public function serialize(DAV\Server $server,\DOMElement $errorNode) {
+
+ if ($this->header) {
+ $prop = $errorNode->ownerDocument->createElement('s:header');
+ $prop->nodeValue = $this->header;
+ $errorNode->appendChild($prop);
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/ReportNotSupported.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/ReportNotSupported.php
new file mode 100644
index 0000000..d7fa05f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/ReportNotSupported.php
@@ -0,0 +1,32 @@
+ownerDocument->createElementNS('DAV:','d:supported-report');
+ $errorNode->appendChild($error);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/RequestedRangeNotSatisfiable.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/RequestedRangeNotSatisfiable.php
new file mode 100644
index 0000000..2080388
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/RequestedRangeNotSatisfiable.php
@@ -0,0 +1,31 @@
+
+ * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
+ * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
+ */
+class ServiceUnavailable extends DAV\Exception {
+
+ /**
+ * Returns the HTTP statuscode for this exception
+ *
+ * @return int
+ */
+ public function getHTTPCode() {
+
+ return 503;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/UnsupportedMediaType.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/UnsupportedMediaType.php
new file mode 100644
index 0000000..05b245d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Exception/UnsupportedMediaType.php
@@ -0,0 +1,28 @@
+path . '/' . $name;
+ file_put_contents($newPath,$data);
+
+ }
+
+ /**
+ * Creates a new subdirectory
+ *
+ * @param string $name
+ * @return void
+ */
+ public function createDirectory($name) {
+
+ $newPath = $this->path . '/' . $name;
+ mkdir($newPath);
+
+ }
+
+ /**
+ * Returns a specific child node, referenced by its name
+ *
+ * This method must throw DAV\Exception\NotFound if the node does not
+ * exist.
+ *
+ * @param string $name
+ * @throws DAV\Exception\NotFound
+ * @return DAV\INode
+ */
+ public function getChild($name) {
+
+ $path = $this->path . '/' . $name;
+
+ if (!file_exists($path)) throw new DAV\Exception\NotFound('File with name ' . $path . ' could not be located');
+
+ if (is_dir($path)) {
+
+ return new Directory($path);
+
+ } else {
+
+ return new File($path);
+
+ }
+
+ }
+
+ /**
+ * Returns an array with all the child nodes
+ *
+ * @return DAV\INode[]
+ */
+ public function getChildren() {
+
+ $nodes = array();
+ foreach(scandir($this->path) as $node) if($node!='.' && $node!='..') $nodes[] = $this->getChild($node);
+ return $nodes;
+
+ }
+
+ /**
+ * Checks if a child exists.
+ *
+ * @param string $name
+ * @return bool
+ */
+ public function childExists($name) {
+
+ $path = $this->path . '/' . $name;
+ return file_exists($path);
+
+ }
+
+ /**
+ * Deletes all files in this directory, and then itself
+ *
+ * @return void
+ */
+ public function delete() {
+
+ foreach($this->getChildren() as $child) $child->delete();
+ rmdir($this->path);
+
+ }
+
+ /**
+ * Returns available diskspace information
+ *
+ * @return array
+ */
+ public function getQuotaInfo() {
+
+ return array(
+ disk_total_space($this->path)-disk_free_space($this->path),
+ disk_free_space($this->path)
+ );
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/FS/File.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/FS/File.php
new file mode 100644
index 0000000..36106de
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/FS/File.php
@@ -0,0 +1,91 @@
+path,$data);
+
+ }
+
+ /**
+ * Returns the data
+ *
+ * @return string
+ */
+ public function get() {
+
+ return fopen($this->path,'r');
+
+ }
+
+ /**
+ * Delete the current file
+ *
+ * @return void
+ */
+ public function delete() {
+
+ unlink($this->path);
+
+ }
+
+ /**
+ * Returns the size of the node, in bytes
+ *
+ * @return int
+ */
+ public function getSize() {
+
+ return filesize($this->path);
+
+ }
+
+ /**
+ * Returns the ETag for a file
+ *
+ * An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change.
+ * The ETag is an arbitrary string, but MUST be surrounded by double-quotes.
+ *
+ * Return null if the ETag can not effectively be determined
+ *
+ * @return mixed
+ */
+ public function getETag() {
+
+ return null;
+
+ }
+
+ /**
+ * Returns the mime-type for a file
+ *
+ * If null is returned, we'll assume application/octet-stream
+ *
+ * @return mixed
+ */
+ public function getContentType() {
+
+ return null;
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/FS/Node.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/FS/Node.php
new file mode 100644
index 0000000..0e2145b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/FS/Node.php
@@ -0,0 +1,82 @@
+path = $path;
+
+ }
+
+
+
+ /**
+ * Returns the name of the node
+ *
+ * @return string
+ */
+ public function getName() {
+
+ list(, $name) = DAV\URLUtil::splitPath($this->path);
+ return $name;
+
+ }
+
+ /**
+ * Renames the node
+ *
+ * @param string $name The new name
+ * @return void
+ */
+ public function setName($name) {
+
+ list($parentPath, ) = DAV\URLUtil::splitPath($this->path);
+ list(, $newName) = DAV\URLUtil::splitPath($name);
+
+ $newPath = $parentPath . '/' . $newName;
+ rename($this->path,$newPath);
+
+ $this->path = $newPath;
+
+ }
+
+
+
+ /**
+ * Returns the last modification time, as a unix timestamp
+ *
+ * @return int
+ */
+ public function getLastModified() {
+
+ return filemtime($this->path);
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/FSExt/Directory.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/FSExt/Directory.php
new file mode 100644
index 0000000..ca26db0
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/FSExt/Directory.php
@@ -0,0 +1,159 @@
+path . '/' . $name;
+ file_put_contents($newPath,$data);
+
+ return '"' . md5_file($newPath) . '"';
+
+ }
+
+ /**
+ * Creates a new subdirectory
+ *
+ * @param string $name
+ * @return void
+ */
+ public function createDirectory($name) {
+
+ // We're not allowing dots
+ if ($name=='.' || $name=='..') throw new DAV\Exception\Forbidden('Permission denied to . and ..');
+ $newPath = $this->path . '/' . $name;
+ mkdir($newPath);
+
+ }
+
+ /**
+ * Returns a specific child node, referenced by its name
+ *
+ * This method must throw SabreForRainLoop\DAV\Exception\NotFound if the node does not
+ * exist.
+ *
+ * @param string $name
+ * @throws DAV\Exception\NotFound
+ * @return DAV\INode
+ */
+ public function getChild($name) {
+
+ $path = $this->path . '/' . $name;
+
+ if (!file_exists($path)) throw new DAV\Exception\NotFound('File could not be located');
+ if ($name=='.' || $name=='..') throw new DAV\Exception\Forbidden('Permission denied to . and ..');
+
+ if (is_dir($path)) {
+
+ return new Directory($path);
+
+ } else {
+
+ return new File($path);
+
+ }
+
+ }
+
+ /**
+ * Checks if a child exists.
+ *
+ * @param string $name
+ * @return bool
+ */
+ public function childExists($name) {
+
+ if ($name=='.' || $name=='..')
+ throw new DAV\Exception\Forbidden('Permission denied to . and ..');
+
+ $path = $this->path . '/' . $name;
+ return file_exists($path);
+
+ }
+
+ /**
+ * Returns an array with all the child nodes
+ *
+ * @return DAV\INode[]
+ */
+ public function getChildren() {
+
+ $nodes = array();
+ foreach(scandir($this->path) as $node) if($node!='.' && $node!='..' && $node!='.sabredav') $nodes[] = $this->getChild($node);
+ return $nodes;
+
+ }
+
+ /**
+ * Deletes all files in this directory, and then itself
+ *
+ * @return bool
+ */
+ public function delete() {
+
+ // Deleting all children
+ foreach($this->getChildren() as $child) $child->delete();
+
+ // Removing resource info, if its still around
+ if (file_exists($this->path . '/.sabredav')) unlink($this->path . '/.sabredav');
+
+ // Removing the directory itself
+ rmdir($this->path);
+
+ return parent::delete();
+
+ }
+
+ /**
+ * Returns available diskspace information
+ *
+ * @return array
+ */
+ public function getQuotaInfo() {
+
+ return array(
+ disk_total_space($this->path)-disk_free_space($this->path),
+ disk_free_space($this->path)
+ );
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/FSExt/File.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/FSExt/File.php
new file mode 100644
index 0000000..425637c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/FSExt/File.php
@@ -0,0 +1,118 @@
+path,$data);
+ return '"' . md5_file($this->path) . '"';
+
+ }
+
+ /**
+ * Updates the data at a given offset
+ *
+ * The data argument is a readable stream resource.
+ * The offset argument is a 0-based offset where the data should be
+ * written.
+ *
+ * param resource|string $data
+ * @return void
+ */
+ public function putRange($data, $offset) {
+
+ $f = fopen($this->path, 'c');
+ fseek($f,$offset-1);
+ if (is_string($data)) {
+ fwrite($f, $data);
+ } else {
+ stream_copy_to_stream($data,$f);
+ }
+ fclose($f);
+ return '"' . md5_file($this->path) . '"';
+
+ }
+
+ /**
+ * Returns the data
+ *
+ * @return resource
+ */
+ public function get() {
+
+ return fopen($this->path,'r');
+
+ }
+
+ /**
+ * Delete the current file
+ *
+ * @return bool
+ */
+ public function delete() {
+
+ unlink($this->path);
+ return parent::delete();
+
+ }
+
+ /**
+ * Returns the ETag for a file
+ *
+ * An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change.
+ * The ETag is an arbitrary string, but MUST be surrounded by double-quotes.
+ *
+ * Return null if the ETag can not effectively be determined
+ *
+ * @return string|null
+ */
+ public function getETag() {
+
+ return '"' . md5_file($this->path). '"';
+
+ }
+
+ /**
+ * Returns the mime-type for a file
+ *
+ * If null is returned, we'll assume application/octet-stream
+ *
+ * @return string|null
+ */
+ public function getContentType() {
+
+ return null;
+
+ }
+
+ /**
+ * Returns the size of the file, in bytes
+ *
+ * @return int
+ */
+ public function getSize() {
+
+ return filesize($this->path);
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/FSExt/Node.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/FSExt/Node.php
new file mode 100644
index 0000000..17cd32c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/FSExt/Node.php
@@ -0,0 +1,214 @@
+getResourceData();
+
+ foreach($properties as $propertyName=>$propertyValue) {
+
+ // If it was null, we need to delete the property
+ if (is_null($propertyValue)) {
+ if (isset($resourceData['properties'][$propertyName])) {
+ unset($resourceData['properties'][$propertyName]);
+ }
+ } else {
+ $resourceData['properties'][$propertyName] = $propertyValue;
+ }
+
+ }
+
+ $this->putResourceData($resourceData);
+ return true;
+ }
+
+ /**
+ * Returns a list of properties for this nodes.;
+ *
+ * The properties list is a list of propertynames the client requested, encoded as xmlnamespace#tagName, for example: http://www.example.org/namespace#author
+ * If the array is empty, all properties should be returned
+ *
+ * @param array $properties
+ * @return array
+ */
+ function getProperties($properties) {
+
+ $resourceData = $this->getResourceData();
+
+ // if the array was empty, we need to return everything
+ if (!$properties) return $resourceData['properties'];
+
+ $props = array();
+ foreach($properties as $property) {
+ if (isset($resourceData['properties'][$property])) $props[$property] = $resourceData['properties'][$property];
+ }
+
+ return $props;
+
+ }
+
+ /**
+ * Returns the path to the resource file
+ *
+ * @return string
+ */
+ protected function getResourceInfoPath() {
+
+ list($parentDir) = DAV\URLUtil::splitPath($this->path);
+ return $parentDir . '/.sabredav';
+
+ }
+
+ /**
+ * Returns all the stored resource information
+ *
+ * @return array
+ */
+ protected function getResourceData() {
+
+ $path = $this->getResourceInfoPath();
+ if (!file_exists($path)) return array('properties' => array());
+
+ // opening up the file, and creating a shared lock
+ $handle = fopen($path,'r');
+ flock($handle,LOCK_SH);
+ $data = '';
+
+ // Reading data until the eof
+ while(!feof($handle)) {
+ $data.=fread($handle,8192);
+ }
+
+ // We're all good
+ fclose($handle);
+
+ // Unserializing and checking if the resource file contains data for this file
+ $data = unserialize($data);
+ if (!isset($data[$this->getName()])) {
+ return array('properties' => array());
+ }
+
+ $data = $data[$this->getName()];
+ if (!isset($data['properties'])) $data['properties'] = array();
+ return $data;
+
+ }
+
+ /**
+ * Updates the resource information
+ *
+ * @param array $newData
+ * @return void
+ */
+ protected function putResourceData(array $newData) {
+
+ $path = $this->getResourceInfoPath();
+
+ // opening up the file, and creating a shared lock
+ $handle = fopen($path,'a+');
+ flock($handle,LOCK_EX);
+ $data = '';
+
+ rewind($handle);
+
+ // Reading data until the eof
+ while(!feof($handle)) {
+ $data.=fread($handle,8192);
+ }
+
+ // Unserializing and checking if the resource file contains data for this file
+ $data = unserialize($data);
+ $data[$this->getName()] = $newData;
+ ftruncate($handle,0);
+ rewind($handle);
+
+ fwrite($handle,serialize($data));
+ fclose($handle);
+
+ }
+
+ /**
+ * Renames the node
+ *
+ * @param string $name The new name
+ * @return void
+ */
+ public function setName($name) {
+
+ list($parentPath, ) = DAV\URLUtil::splitPath($this->path);
+ list(, $newName) = DAV\URLUtil::splitPath($name);
+ $newPath = $parentPath . '/' . $newName;
+
+ // We're deleting the existing resourcedata, and recreating it
+ // for the new path.
+ $resourceData = $this->getResourceData();
+ $this->deleteResourceData();
+
+ rename($this->path,$newPath);
+ $this->path = $newPath;
+ $this->putResourceData($resourceData);
+
+
+ }
+
+ /**
+ * @return bool
+ */
+ public function deleteResourceData() {
+
+ // When we're deleting this node, we also need to delete any resource information
+ $path = $this->getResourceInfoPath();
+ if (!file_exists($path)) return true;
+
+ // opening up the file, and creating a shared lock
+ $handle = fopen($path,'a+');
+ flock($handle,LOCK_EX);
+ $data = '';
+
+ rewind($handle);
+
+ // Reading data until the eof
+ while(!feof($handle)) {
+ $data.=fread($handle,8192);
+ }
+
+ // Unserializing and checking if the resource file contains data for this file
+ $data = unserialize($data);
+ if (isset($data[$this->getName()])) unset($data[$this->getName()]);
+ ftruncate($handle,0);
+ rewind($handle);
+ fwrite($handle,serialize($data));
+ fclose($handle);
+
+ return true;
+ }
+
+ public function delete() {
+
+ return $this->deleteResourceData();
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/File.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/File.php
new file mode 100644
index 0000000..e21d240
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/File.php
@@ -0,0 +1,85 @@
+ array(
+ * '{DAV:}displayname' => null,
+ * ),
+ * 424 => array(
+ * '{DAV:}owner' => null,
+ * )
+ * )
+ *
+ * In this example it was forbidden to update {DAV:}displayname.
+ * (403 Forbidden), which in turn also caused {DAV:}owner to fail
+ * (424 Failed Dependency) because the request needs to be atomic.
+ *
+ * @param array $mutations
+ * @return bool|array
+ */
+ function updateProperties($mutations);
+
+ /**
+ * Returns a list of properties for this nodes.
+ *
+ * The properties list is a list of propertynames the client requested,
+ * encoded in clark-notation {xmlnamespace}tagname
+ *
+ * If the array is empty, it means 'all properties' were requested.
+ *
+ * Note that it's fine to liberally give properties back, instead of
+ * conforming to the list of requested properties.
+ * The Server class will filter out the extra.
+ *
+ * @param array $properties
+ * @return void
+ */
+ function getProperties($properties);
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/IQuota.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/IQuota.php
new file mode 100644
index 0000000..dd42fc5
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/IQuota.php
@@ -0,0 +1,27 @@
+dataDir = $dataDir;
+
+ }
+
+ protected function getFileNameForUri($uri) {
+
+ return $this->dataDir . '/sabredav_' . md5($uri) . '.locks';
+
+ }
+
+
+ /**
+ * Returns a list of SabreForRainLoop\DAV\Locks\LockInfo objects
+ *
+ * This method should return all the locks for a particular uri, including
+ * locks that might be set on a parent uri.
+ *
+ * If returnChildLocks is set to true, this method should also look for
+ * any locks in the subtree of the uri for locks.
+ *
+ * @param string $uri
+ * @param bool $returnChildLocks
+ * @return array
+ */
+ public function getLocks($uri, $returnChildLocks) {
+
+ $lockList = array();
+ $currentPath = '';
+
+ foreach(explode('/',$uri) as $uriPart) {
+
+ // weird algorithm that can probably be improved, but we're traversing the path top down
+ if ($currentPath) $currentPath.='/';
+ $currentPath.=$uriPart;
+
+ $uriLocks = $this->getData($currentPath);
+
+ foreach($uriLocks as $uriLock) {
+
+ // Unless we're on the leaf of the uri-tree we should ignore locks with depth 0
+ if($uri==$currentPath || $uriLock->depth!=0) {
+ $uriLock->uri = $currentPath;
+ $lockList[] = $uriLock;
+ }
+
+ }
+
+ }
+
+ // Checking if we can remove any of these locks
+ foreach($lockList as $k=>$lock) {
+ if (time() > $lock->timeout + $lock->created) unset($lockList[$k]);
+ }
+ return $lockList;
+
+ }
+
+ /**
+ * Locks a uri
+ *
+ * @param string $uri
+ * @param LockInfo $lockInfo
+ * @return bool
+ */
+ public function lock($uri, LockInfo $lockInfo) {
+
+ // We're making the lock timeout 30 minutes
+ $lockInfo->timeout = 1800;
+ $lockInfo->created = time();
+
+ $locks = $this->getLocks($uri,false);
+ foreach($locks as $k=>$lock) {
+ if ($lock->token == $lockInfo->token) unset($locks[$k]);
+ }
+ $locks[] = $lockInfo;
+ $this->putData($uri,$locks);
+ return true;
+
+ }
+
+ /**
+ * Removes a lock from a uri
+ *
+ * @param string $uri
+ * @param LockInfo $lockInfo
+ * @return bool
+ */
+ public function unlock($uri, LockInfo $lockInfo) {
+
+ $locks = $this->getLocks($uri,false);
+ foreach($locks as $k=>$lock) {
+
+ if ($lock->token == $lockInfo->token) {
+
+ unset($locks[$k]);
+ $this->putData($uri,$locks);
+ return true;
+
+ }
+ }
+ return false;
+
+ }
+
+ /**
+ * Returns the stored data for a uri
+ *
+ * @param string $uri
+ * @return array
+ */
+ protected function getData($uri) {
+
+ $path = $this->getFilenameForUri($uri);
+ if (!file_exists($path)) return array();
+
+ // opening up the file, and creating a shared lock
+ $handle = fopen($path,'r');
+ flock($handle,LOCK_SH);
+ $data = '';
+
+ // Reading data until the eof
+ while(!feof($handle)) {
+ $data.=fread($handle,8192);
+ }
+
+ // We're all good
+ fclose($handle);
+
+ // Unserializing and checking if the resource file contains data for this file
+ $data = unserialize($data);
+ if (!$data) return array();
+ return $data;
+
+ }
+
+ /**
+ * Updates the lock information
+ *
+ * @param string $uri
+ * @param array $newData
+ * @return void
+ */
+ protected function putData($uri,array $newData) {
+
+ $path = $this->getFileNameForUri($uri);
+
+ // opening up the file, and creating a shared lock
+ $handle = fopen($path,'a+');
+ flock($handle,LOCK_EX);
+ ftruncate($handle,0);
+ rewind($handle);
+
+ fwrite($handle,serialize($newData));
+ fclose($handle);
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Locks/Backend/File.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Locks/Backend/File.php
new file mode 100644
index 0000000..b405085
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Locks/Backend/File.php
@@ -0,0 +1,183 @@
+locksFile = $locksFile;
+
+ }
+
+ /**
+ * Returns a list of SabreForRainLoop\DAV\Locks\LockInfo objects
+ *
+ * This method should return all the locks for a particular uri, including
+ * locks that might be set on a parent uri.
+ *
+ * If returnChildLocks is set to true, this method should also look for
+ * any locks in the subtree of the uri for locks.
+ *
+ * @param string $uri
+ * @param bool $returnChildLocks
+ * @return array
+ */
+ public function getLocks($uri, $returnChildLocks) {
+
+ $newLocks = array();
+
+ $locks = $this->getData();
+
+ foreach($locks as $lock) {
+
+ if ($lock->uri === $uri ||
+ //deep locks on parents
+ ($lock->depth!=0 && strpos($uri, $lock->uri . '/')===0) ||
+
+ // locks on children
+ ($returnChildLocks && (strpos($lock->uri, $uri . '/')===0)) ) {
+
+ $newLocks[] = $lock;
+
+ }
+
+ }
+
+ // Checking if we can remove any of these locks
+ foreach($newLocks as $k=>$lock) {
+ if (time() > $lock->timeout + $lock->created) unset($newLocks[$k]);
+ }
+ return $newLocks;
+
+ }
+
+ /**
+ * Locks a uri
+ *
+ * @param string $uri
+ * @param LockInfo $lockInfo
+ * @return bool
+ */
+ public function lock($uri, LockInfo $lockInfo) {
+
+ // We're making the lock timeout 30 minutes
+ $lockInfo->timeout = 1800;
+ $lockInfo->created = time();
+ $lockInfo->uri = $uri;
+
+ $locks = $this->getData();
+
+ foreach($locks as $k=>$lock) {
+ if (
+ ($lock->token == $lockInfo->token) ||
+ (time() > $lock->timeout + $lock->created)
+ ) {
+ unset($locks[$k]);
+ }
+ }
+ $locks[] = $lockInfo;
+ $this->putData($locks);
+ return true;
+
+ }
+
+ /**
+ * Removes a lock from a uri
+ *
+ * @param string $uri
+ * @param LockInfo $lockInfo
+ * @return bool
+ */
+ public function unlock($uri, LockInfo $lockInfo) {
+
+ $locks = $this->getData();
+ foreach($locks as $k=>$lock) {
+
+ if ($lock->token == $lockInfo->token) {
+
+ unset($locks[$k]);
+ $this->putData($locks);
+ return true;
+
+ }
+ }
+ return false;
+
+ }
+
+ /**
+ * Loads the lockdata from the filesystem.
+ *
+ * @return array
+ */
+ protected function getData() {
+
+ if (!file_exists($this->locksFile)) return array();
+
+ // opening up the file, and creating a shared lock
+ $handle = fopen($this->locksFile,'r');
+ flock($handle,LOCK_SH);
+
+ // Reading data until the eof
+ $data = stream_get_contents($handle);
+
+ // We're all good
+ fclose($handle);
+
+ // Unserializing and checking if the resource file contains data for this file
+ $data = unserialize($data);
+ if (!$data) return array();
+ return $data;
+
+ }
+
+ /**
+ * Saves the lockdata
+ *
+ * @param array $newData
+ * @return void
+ */
+ protected function putData(array $newData) {
+
+ // opening up the file, and creating an exclusive lock
+ $handle = fopen($this->locksFile,'a+');
+ flock($handle,LOCK_EX);
+
+ // We can only truncate and rewind once the lock is acquired.
+ ftruncate($handle,0);
+ rewind($handle);
+
+ fwrite($handle,serialize($newData));
+ fclose($handle);
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Locks/Backend/PDO.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Locks/Backend/PDO.php
new file mode 100644
index 0000000..2718533
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Locks/Backend/PDO.php
@@ -0,0 +1,167 @@
+pdo = $pdo;
+ $this->tableName = $tableName;
+
+ }
+
+ /**
+ * Returns a list of SabreForRainLoop\DAV\Locks\LockInfo objects
+ *
+ * This method should return all the locks for a particular uri, including
+ * locks that might be set on a parent uri.
+ *
+ * If returnChildLocks is set to true, this method should also look for
+ * any locks in the subtree of the uri for locks.
+ *
+ * @param string $uri
+ * @param bool $returnChildLocks
+ * @return array
+ */
+ public function getLocks($uri, $returnChildLocks) {
+
+ // NOTE: the following 10 lines or so could be easily replaced by
+ // pure sql. MySQL's non-standard string concatenation prevents us
+ // from doing this though.
+ $query = 'SELECT owner, token, timeout, created, scope, depth, uri FROM '.$this->tableName.' WHERE ((created + timeout) > CAST(? AS UNSIGNED INTEGER)) AND ((uri = ?)';
+ $params = array(time(),$uri);
+
+ // We need to check locks for every part in the uri.
+ $uriParts = explode('/',$uri);
+
+ // We already covered the last part of the uri
+ array_pop($uriParts);
+
+ $currentPath='';
+
+ foreach($uriParts as $part) {
+
+ if ($currentPath) $currentPath.='/';
+ $currentPath.=$part;
+
+ $query.=' OR (depth!=0 AND uri = ?)';
+ $params[] = $currentPath;
+
+ }
+
+ if ($returnChildLocks) {
+
+ $query.=' OR (uri LIKE ?)';
+ $params[] = $uri . '/%';
+
+ }
+ $query.=')';
+
+ $stmt = $this->pdo->prepare($query);
+ $stmt->execute($params);
+ $result = $stmt->fetchAll();
+
+ $lockList = array();
+ foreach($result as $row) {
+
+ $lockInfo = new LockInfo();
+ $lockInfo->owner = $row['owner'];
+ $lockInfo->token = $row['token'];
+ $lockInfo->timeout = $row['timeout'];
+ $lockInfo->created = $row['created'];
+ $lockInfo->scope = $row['scope'];
+ $lockInfo->depth = $row['depth'];
+ $lockInfo->uri = $row['uri'];
+ $lockList[] = $lockInfo;
+
+ }
+
+ return $lockList;
+
+ }
+
+ /**
+ * Locks a uri
+ *
+ * @param string $uri
+ * @param LockInfo $lockInfo
+ * @return bool
+ */
+ public function lock($uri, LockInfo $lockInfo) {
+
+ // We're making the lock timeout 30 minutes
+ $lockInfo->timeout = 30*60;
+ $lockInfo->created = time();
+ $lockInfo->uri = $uri;
+
+ $locks = $this->getLocks($uri,false);
+ $exists = false;
+ foreach($locks as $lock) {
+ if ($lock->token == $lockInfo->token) $exists = true;
+ }
+
+ if ($exists) {
+ $stmt = $this->pdo->prepare('UPDATE '.$this->tableName.' SET owner = ?, timeout = ?, scope = ?, depth = ?, uri = ?, created = ? WHERE token = ?');
+ $stmt->execute(array($lockInfo->owner,$lockInfo->timeout,$lockInfo->scope,$lockInfo->depth,$uri,$lockInfo->created,$lockInfo->token));
+ } else {
+ $stmt = $this->pdo->prepare('INSERT INTO '.$this->tableName.' (owner,timeout,scope,depth,uri,created,token) VALUES (?,?,?,?,?,?,?)');
+ $stmt->execute(array($lockInfo->owner,$lockInfo->timeout,$lockInfo->scope,$lockInfo->depth,$uri,$lockInfo->created,$lockInfo->token));
+ }
+
+ return true;
+
+ }
+
+
+
+ /**
+ * Removes a lock from a uri
+ *
+ * @param string $uri
+ * @param LockInfo $lockInfo
+ * @return bool
+ */
+ public function unlock($uri, LockInfo $lockInfo) {
+
+ $stmt = $this->pdo->prepare('DELETE FROM '.$this->tableName.' WHERE uri = ? AND token = ?');
+ $stmt->execute(array($uri,$lockInfo->token));
+
+ return $stmt->rowCount()===1;
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Locks/LockInfo.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Locks/LockInfo.php
new file mode 100644
index 0000000..894ac57
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Locks/LockInfo.php
@@ -0,0 +1,81 @@
+addPlugin($lockPlugin);
+ *
+ * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
+ */
+class Plugin extends DAV\ServerPlugin {
+
+ /**
+ * locksBackend
+ *
+ * @var Backend\Backend\Interface
+ */
+ protected $locksBackend;
+
+ /**
+ * server
+ *
+ * @var SabreForRainLoop\DAV\Server
+ */
+ protected $server;
+
+ /**
+ * __construct
+ *
+ * @param Backend\BackendInterface $locksBackend
+ */
+ public function __construct(Backend\BackendInterface $locksBackend = null) {
+
+ $this->locksBackend = $locksBackend;
+
+ }
+
+ /**
+ * Initializes the plugin
+ *
+ * This method is automatically called by the Server class after addPlugin.
+ *
+ * @param DAV\Server $server
+ * @return void
+ */
+ public function initialize(DAV\Server $server) {
+
+ $this->server = $server;
+ $server->subscribeEvent('unknownMethod',array($this,'unknownMethod'));
+ $server->subscribeEvent('beforeMethod',array($this,'beforeMethod'),50);
+ $server->subscribeEvent('afterGetProperties',array($this,'afterGetProperties'));
+
+ }
+
+ /**
+ * Returns a plugin name.
+ *
+ * Using this name other plugins will be able to access other plugins
+ * using SabreForRainLoop\DAV\Server::getPlugin
+ *
+ * @return string
+ */
+ public function getPluginName() {
+
+ return 'locks';
+
+ }
+
+ /**
+ * This method is called by the Server if the user used an HTTP method
+ * the server didn't recognize.
+ *
+ * This plugin intercepts the LOCK and UNLOCK methods.
+ *
+ * @param string $method
+ * @param string $uri
+ * @return bool
+ */
+ public function unknownMethod($method, $uri) {
+
+ switch($method) {
+
+ case 'LOCK' : $this->httpLock($uri); return false;
+ case 'UNLOCK' : $this->httpUnlock($uri); return false;
+
+ }
+
+ }
+
+ /**
+ * This method is called after most properties have been found
+ * it allows us to add in any Lock-related properties
+ *
+ * @param string $path
+ * @param array $newProperties
+ * @return bool
+ */
+ public function afterGetProperties($path, &$newProperties) {
+
+ foreach($newProperties[404] as $propName=>$discard) {
+
+ switch($propName) {
+
+ case '{DAV:}supportedlock' :
+ $val = false;
+ if ($this->locksBackend) $val = true;
+ $newProperties[200][$propName] = new DAV\Property\SupportedLock($val);
+ unset($newProperties[404][$propName]);
+ break;
+
+ case '{DAV:}lockdiscovery' :
+ $newProperties[200][$propName] = new DAV\Property\LockDiscovery($this->getLocks($path));
+ unset($newProperties[404][$propName]);
+ break;
+
+ }
+
+
+ }
+ return true;
+
+ }
+
+
+ /**
+ * This method is called before the logic for any HTTP method is
+ * handled.
+ *
+ * This plugin uses that feature to intercept access to locked resources.
+ *
+ * @param string $method
+ * @param string $uri
+ * @return bool
+ */
+ public function beforeMethod($method, $uri) {
+
+ switch($method) {
+
+ case 'DELETE' :
+ $lastLock = null;
+ if (!$this->validateLock($uri,$lastLock, true))
+ throw new DAV\Exception\Locked($lastLock);
+ break;
+ case 'MKCOL' :
+ case 'PROPPATCH' :
+ case 'PUT' :
+ case 'PATCH' :
+ $lastLock = null;
+ if (!$this->validateLock($uri,$lastLock))
+ throw new DAV\Exception\Locked($lastLock);
+ break;
+ case 'MOVE' :
+ $lastLock = null;
+ if (!$this->validateLock(array(
+ $uri,
+ $this->server->calculateUri($this->server->httpRequest->getHeader('Destination')),
+ ),$lastLock, true))
+ throw new DAV\Exception\Locked($lastLock);
+ break;
+ case 'COPY' :
+ $lastLock = null;
+ if (!$this->validateLock(
+ $this->server->calculateUri($this->server->httpRequest->getHeader('Destination')),
+ $lastLock, true))
+ throw new DAV\Exception\Locked($lastLock);
+ break;
+ }
+
+ return true;
+
+ }
+
+ /**
+ * Use this method to tell the server this plugin defines additional
+ * HTTP methods.
+ *
+ * This method is passed a uri. It should only return HTTP methods that are
+ * available for the specified uri.
+ *
+ * @param string $uri
+ * @return array
+ */
+ public function getHTTPMethods($uri) {
+
+ if ($this->locksBackend)
+ return array('LOCK','UNLOCK');
+
+ return array();
+
+ }
+
+ /**
+ * Returns a list of features for the HTTP OPTIONS Dav: header.
+ *
+ * In this case this is only the number 2. The 2 in the Dav: header
+ * indicates the server supports locks.
+ *
+ * @return array
+ */
+ public function getFeatures() {
+
+ return array(2);
+
+ }
+
+ /**
+ * Returns all lock information on a particular uri
+ *
+ * This function should return an array with SabreForRainLoop\DAV\Locks\LockInfo objects. If there are no locks on a file, return an empty array.
+ *
+ * Additionally there is also the possibility of locks on parent nodes, so we'll need to traverse every part of the tree
+ * If the $returnChildLocks argument is set to true, we'll also traverse all the children of the object
+ * for any possible locks and return those as well.
+ *
+ * @param string $uri
+ * @param bool $returnChildLocks
+ * @return array
+ */
+ public function getLocks($uri, $returnChildLocks = false) {
+
+ $lockList = array();
+
+ if ($this->locksBackend)
+ $lockList = array_merge($lockList,$this->locksBackend->getLocks($uri, $returnChildLocks));
+
+ return $lockList;
+
+ }
+
+ /**
+ * Locks an uri
+ *
+ * The WebDAV lock request can be operated to either create a new lock on a file, or to refresh an existing lock
+ * If a new lock is created, a full XML body should be supplied, containing information about the lock such as the type
+ * of lock (shared or exclusive) and the owner of the lock
+ *
+ * If a lock is to be refreshed, no body should be supplied and there should be a valid If header containing the lock
+ *
+ * Additionally, a lock can be requested for a non-existent file. In these case we're obligated to create an empty file as per RFC4918:S7.3
+ *
+ * @param string $uri
+ * @return void
+ */
+ protected function httpLock($uri) {
+
+ $lastLock = null;
+ if (!$this->validateLock($uri,$lastLock)) {
+
+ // If the existing lock was an exclusive lock, we need to fail
+ if (!$lastLock || $lastLock->scope == LockInfo::EXCLUSIVE) {
+ //var_dump($lastLock);
+ throw new DAV\Exception\ConflictingLock($lastLock);
+ }
+
+ }
+
+ if ($body = $this->server->httpRequest->getBody(true)) {
+ // This is a new lock request
+ $lockInfo = $this->parseLockRequest($body);
+ $lockInfo->depth = $this->server->getHTTPDepth();
+ $lockInfo->uri = $uri;
+ if($lastLock && $lockInfo->scope != LockInfo::SHARED) throw new DAV\Exception\ConflictingLock($lastLock);
+
+ } elseif ($lastLock) {
+
+ // This must have been a lock refresh
+ $lockInfo = $lastLock;
+
+ // The resource could have been locked through another uri.
+ if ($uri!=$lockInfo->uri) $uri = $lockInfo->uri;
+
+ } else {
+
+ // There was neither a lock refresh nor a new lock request
+ throw new DAV\Exception\BadRequest('An xml body is required for lock requests');
+
+ }
+
+ if ($timeout = $this->getTimeoutHeader()) $lockInfo->timeout = $timeout;
+
+ $newFile = false;
+
+ // If we got this far.. we should go check if this node actually exists. If this is not the case, we need to create it first
+ try {
+ $this->server->tree->getNodeForPath($uri);
+
+ // We need to call the beforeWriteContent event for RFC3744
+ // Edit: looks like this is not used, and causing problems now.
+ //
+ // See Issue 222
+ // $this->server->broadcastEvent('beforeWriteContent',array($uri));
+
+ } catch (DAV\Exception\NotFound $e) {
+
+ // It didn't, lets create it
+ $this->server->createFile($uri,fopen('php://memory','r'));
+ $newFile = true;
+
+ }
+
+ $this->lockNode($uri,$lockInfo);
+
+ $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
+ $this->server->httpResponse->setHeader('Lock-Token','token . '>');
+ $this->server->httpResponse->sendStatus($newFile?201:200);
+ $this->server->httpResponse->sendBody($this->generateLockResponse($lockInfo));
+
+ }
+
+ /**
+ * Unlocks a uri
+ *
+ * This WebDAV method allows you to remove a lock from a node. The client should provide a valid locktoken through the Lock-token http header
+ * The server should return 204 (No content) on success
+ *
+ * @param string $uri
+ * @return void
+ */
+ protected function httpUnlock($uri) {
+
+ $lockToken = $this->server->httpRequest->getHeader('Lock-Token');
+
+ // If the locktoken header is not supplied, we need to throw a bad request exception
+ if (!$lockToken) throw new DAV\Exception\BadRequest('No lock token was supplied');
+
+ $locks = $this->getLocks($uri);
+
+ // Windows sometimes forgets to include < and > in the Lock-Token
+ // header
+ if ($lockToken[0]!=='<') $lockToken = '<' . $lockToken . '>';
+
+ foreach($locks as $lock) {
+
+ if ('token . '>' == $lockToken) {
+
+ $this->unlockNode($uri,$lock);
+ $this->server->httpResponse->setHeader('Content-Length','0');
+ $this->server->httpResponse->sendStatus(204);
+ return;
+
+ }
+
+ }
+
+ // If we got here, it means the locktoken was invalid
+ throw new DAV\Exception\LockTokenMatchesRequestUri();
+
+ }
+
+ /**
+ * Locks a uri
+ *
+ * All the locking information is supplied in the lockInfo object. The object has a suggested timeout, but this can be safely ignored
+ * It is important that if the existing timeout is ignored, the property is overwritten, as this needs to be sent back to the client
+ *
+ * @param string $uri
+ * @param LockInfo $lockInfo
+ * @return bool
+ */
+ public function lockNode($uri,LockInfo $lockInfo) {
+
+ if (!$this->server->broadcastEvent('beforeLock',array($uri,$lockInfo))) return;
+
+ if ($this->locksBackend) return $this->locksBackend->lock($uri,$lockInfo);
+ throw new DAV\Exception\MethodNotAllowed('Locking support is not enabled for this resource. No Locking backend was found so if you didn\'t expect this error, please check your configuration.');
+
+ }
+
+ /**
+ * Unlocks a uri
+ *
+ * This method removes a lock from a uri. It is assumed all the supplied information is correct and verified
+ *
+ * @param string $uri
+ * @param LockInfo $lockInfo
+ * @return bool
+ */
+ public function unlockNode($uri, LockInfo $lockInfo) {
+
+ if (!$this->server->broadcastEvent('beforeUnlock',array($uri,$lockInfo))) return;
+ if ($this->locksBackend) return $this->locksBackend->unlock($uri,$lockInfo);
+
+ }
+
+
+ /**
+ * Returns the contents of the HTTP Timeout header.
+ *
+ * The method formats the header into an integer.
+ *
+ * @return int
+ */
+ public function getTimeoutHeader() {
+
+ $header = $this->server->httpRequest->getHeader('Timeout');
+
+ if ($header) {
+
+ if (stripos($header,'second-')===0) $header = (int)(substr($header,7));
+ else if (strtolower($header)=='infinite') $header = LockInfo::TIMEOUT_INFINITE;
+ else throw new DAV\Exception\BadRequest('Invalid HTTP timeout header');
+
+ } else {
+
+ $header = 0;
+
+ }
+
+ return $header;
+
+ }
+
+ /**
+ * Generates the response for successful LOCK requests
+ *
+ * @param LockInfo $lockInfo
+ * @return string
+ */
+ protected function generateLockResponse(LockInfo $lockInfo) {
+
+ $dom = new \DOMDocument('1.0','utf-8');
+ $dom->formatOutput = true;
+
+ $prop = $dom->createElementNS('DAV:','d:prop');
+ $dom->appendChild($prop);
+
+ $lockDiscovery = $dom->createElementNS('DAV:','d:lockdiscovery');
+ $prop->appendChild($lockDiscovery);
+
+ $lockObj = new DAV\Property\LockDiscovery(array($lockInfo),true);
+ $lockObj->serialize($this->server,$lockDiscovery);
+
+ return $dom->saveXML();
+
+ }
+
+ /**
+ * validateLock should be called when a write operation is about to happen
+ * It will check if the requested url is locked, and see if the correct lock tokens are passed
+ *
+ * @param mixed $urls List of relevant urls. Can be an array, a string or nothing at all for the current request uri
+ * @param mixed $lastLock This variable will be populated with the last checked lock object (SabreForRainLoop\DAV\Locks\LockInfo)
+ * @param bool $checkChildLocks If set to true, this function will also look for any locks set on child resources of the supplied urls. This is needed for for example deletion of entire trees.
+ * @return bool
+ */
+ protected function validateLock($urls = null,&$lastLock = null, $checkChildLocks = false) {
+
+ if (is_null($urls)) {
+ $urls = array($this->server->getRequestUri());
+ } elseif (is_string($urls)) {
+ $urls = array($urls);
+ } elseif (!is_array($urls)) {
+ throw new DAV\Exception('The urls parameter should either be null, a string or an array');
+ }
+
+ $conditions = $this->getIfConditions();
+
+ // We're going to loop through the urls and make sure all lock conditions are satisfied
+ foreach($urls as $url) {
+
+ $locks = $this->getLocks($url, $checkChildLocks);
+
+ // If there were no conditions, but there were locks, we fail
+ if (!$conditions && $locks) {
+ reset($locks);
+ $lastLock = current($locks);
+ return false;
+ }
+
+ // If there were no locks or conditions, we go to the next url
+ if (!$locks && !$conditions) continue;
+
+ foreach($conditions as $condition) {
+
+ if (!$condition['uri']) {
+ $conditionUri = $this->server->getRequestUri();
+ } else {
+ $conditionUri = $this->server->calculateUri($condition['uri']);
+ }
+
+ // If the condition has a url, and it isn't part of the affected url at all, check the next condition
+ if ($conditionUri && strpos($url,$conditionUri)!==0) continue;
+
+ // The tokens array contians arrays with 2 elements. 0=true/false for normal/not condition, 1=locktoken
+ // At least 1 condition has to be satisfied
+ foreach($condition['tokens'] as $conditionToken) {
+
+ $etagValid = true;
+ $lockValid = true;
+
+ // key 2 can contain an etag
+ if ($conditionToken[2]) {
+
+ $uri = $conditionUri?$conditionUri:$this->server->getRequestUri();
+ $node = $this->server->tree->getNodeForPath($uri);
+ $etagValid = $node->getETag()==$conditionToken[2];
+
+ }
+
+ // key 1 can contain a lock token
+ if ($conditionToken[1]) {
+
+ $lockValid = false;
+ // Match all the locks
+ foreach($locks as $lockIndex=>$lock) {
+
+ $lockToken = 'opaquelocktoken:' . $lock->token;
+
+ // Checking NOT
+ if (!$conditionToken[0] && $lockToken != $conditionToken[1]) {
+
+ // Condition valid, onto the next
+ $lockValid = true;
+ break;
+ }
+ if ($conditionToken[0] && $lockToken == $conditionToken[1]) {
+
+ $lastLock = $lock;
+ // Condition valid and lock matched
+ unset($locks[$lockIndex]);
+ $lockValid = true;
+ break;
+
+ }
+
+ }
+
+ }
+
+ // If, after checking both etags and locks they are stil valid,
+ // we can continue with the next condition.
+ if ($etagValid && $lockValid) continue 2;
+ }
+ // No conditions matched, so we fail
+ throw new DAV\Exception\PreconditionFailed('The tokens provided in the if header did not match','If');
+ }
+
+ // Conditions were met, we'll also need to check if all the locks are gone
+ if (count($locks)) {
+
+ reset($locks);
+
+ // There's still locks, we fail
+ $lastLock = current($locks);
+ return false;
+
+ }
+
+
+ }
+
+ // We got here, this means every condition was satisfied
+ return true;
+
+ }
+
+ /**
+ * This method is created to extract information from the WebDAV HTTP 'If:' header
+ *
+ * The If header can be quite complex, and has a bunch of features. We're using a regex to extract all relevant information
+ * The function will return an array, containing structs with the following keys
+ *
+ * * uri - the uri the condition applies to. If this is returned as an
+ * empty string, this implies it's referring to the request url.
+ * * tokens - The lock token. another 2 dimensional array containing 2 elements (0 = true/false.. If this is a negative condition its set to false, 1 = the actual token)
+ * * etag - an etag, if supplied
+ *
+ * @return array
+ */
+ public function getIfConditions() {
+
+ $header = $this->server->httpRequest->getHeader('If');
+ if (!$header) return array();
+
+ $matches = array();
+
+ $regex = '/(?:\<(?P.*?)\>\s)?\((?PNot\s)?(?:\<(?P[^\>]*)\>)?(?:\s?)(?:\[(?P[^\]]*)\])?\)/im';
+ preg_match_all($regex,$header,$matches,PREG_SET_ORDER);
+
+ $conditions = array();
+
+ foreach($matches as $match) {
+
+ $condition = array(
+ 'uri' => $match['uri'],
+ 'tokens' => array(
+ array($match['not']?0:1,$match['token'],isset($match['etag'])?$match['etag']:'')
+ ),
+ );
+
+ if (!$condition['uri'] && count($conditions)) $conditions[count($conditions)-1]['tokens'][] = array(
+ $match['not']?0:1,
+ $match['token'],
+ isset($match['etag'])?$match['etag']:''
+ );
+ else {
+ $conditions[] = $condition;
+ }
+
+ }
+
+ return $conditions;
+
+ }
+
+ /**
+ * Parses a webdav lock xml body, and returns a new SabreForRainLoop\DAV\Locks\LockInfo object
+ *
+ * @param string $body
+ * @return DAV\Locks\LockInfo
+ */
+ protected function parseLockRequest($body) {
+
+ $xml = simplexml_load_string(
+ DAV\XMLUtil::convertDAVNamespace($body),
+ null,
+ LIBXML_NOWARNING);
+ $xml->registerXPathNamespace('d','urn:DAV');
+ $lockInfo = new LockInfo();
+
+ $children = $xml->children("urn:DAV");
+ $lockInfo->owner = (string)$children->owner;
+
+ $lockInfo->token = DAV\UUIDUtil::getUUID();
+ $lockInfo->scope = count($xml->xpath('d:lockscope/d:exclusive'))>0 ? LockInfo::EXCLUSIVE : LockInfo::SHARED;
+
+ return $lockInfo;
+
+ }
+
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Mount/Plugin.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Mount/Plugin.php
new file mode 100644
index 0000000..4959f01
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Mount/Plugin.php
@@ -0,0 +1,83 @@
+server = $server;
+ $this->server->subscribeEvent('beforeMethod',array($this,'beforeMethod'), 90);
+
+ }
+
+ /**
+ * 'beforeMethod' event handles. This event handles intercepts GET requests ending
+ * with ?mount
+ *
+ * @param string $method
+ * @param string $uri
+ * @return bool
+ */
+ public function beforeMethod($method, $uri) {
+
+ if ($method!='GET') return;
+ if ($this->server->httpRequest->getQueryString()!='mount') return;
+
+ $currentUri = $this->server->httpRequest->getAbsoluteUri();
+
+ // Stripping off everything after the ?
+ list($currentUri) = explode('?',$currentUri);
+
+ $this->davMount($currentUri);
+
+ // Returning false to break the event chain
+ return false;
+
+ }
+
+ /**
+ * Generates the davmount response
+ *
+ * @param string $uri absolute uri
+ * @return void
+ */
+ public function davMount($uri) {
+
+ $this->server->httpResponse->sendStatus(200);
+ $this->server->httpResponse->setHeader('Content-Type','application/davmount+xml');
+ ob_start();
+ echo '', "\n";
+ echo "\n";
+ echo " ", htmlspecialchars($uri, ENT_NOQUOTES, 'UTF-8'), " \n";
+ echo " ";
+ $this->server->httpResponse->sendBody(ob_get_clean());
+
+ }
+
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Node.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Node.php
new file mode 100644
index 0000000..52e460e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Node.php
@@ -0,0 +1,55 @@
+rootNode = $rootNode;
+
+ }
+
+ /**
+ * Returns the INode object for the requested path
+ *
+ * @param string $path
+ * @return INode
+ */
+ public function getNodeForPath($path) {
+
+ $path = trim($path,'/');
+ if (isset($this->cache[$path])) return $this->cache[$path];
+
+ // Is it the root node?
+ if (!strlen($path)) {
+ return $this->rootNode;
+ }
+
+ // Attempting to fetch its parent
+ list($parentName, $baseName) = URLUtil::splitPath($path);
+
+ // If there was no parent, we must simply ask it from the root node.
+ if ($parentName==="") {
+ $node = $this->rootNode->getChild($baseName);
+ } else {
+ // Otherwise, we recursively grab the parent and ask him/her.
+ $parent = $this->getNodeForPath($parentName);
+
+ if (!($parent instanceof ICollection))
+ throw new Exception\NotFound('Could not find node at path: ' . $path);
+
+ $node = $parent->getChild($baseName);
+
+ }
+
+ $this->cache[$path] = $node;
+ return $node;
+
+ }
+
+ /**
+ * This function allows you to check if a node exists.
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function nodeExists($path) {
+
+ try {
+
+ // The root always exists
+ if ($path==='') return true;
+
+ list($parent, $base) = URLUtil::splitPath($path);
+
+ $parentNode = $this->getNodeForPath($parent);
+ if (!$parentNode instanceof ICollection) return false;
+ return $parentNode->childExists($base);
+
+ } catch (Exception\NotFound $e) {
+
+ return false;
+
+ }
+
+ }
+
+ /**
+ * Returns a list of childnodes for a given path.
+ *
+ * @param string $path
+ * @return array
+ */
+ public function getChildren($path) {
+
+ $node = $this->getNodeForPath($path);
+ $children = $node->getChildren();
+ foreach($children as $child) {
+
+ $this->cache[trim($path,'/') . '/' . $child->getName()] = $child;
+
+ }
+ return $children;
+
+ }
+
+ /**
+ * This method is called with every tree update
+ *
+ * Examples of tree updates are:
+ * * node deletions
+ * * node creations
+ * * copy
+ * * move
+ * * renaming nodes
+ *
+ * If Tree classes implement a form of caching, this will allow
+ * them to make sure caches will be expired.
+ *
+ * If a path is passed, it is assumed that the entire subtree is dirty
+ *
+ * @param string $path
+ * @return void
+ */
+ public function markDirty($path) {
+
+ // We don't care enough about sub-paths
+ // flushing the entire cache
+ $path = trim($path,'/');
+ foreach($this->cache as $nodePath=>$node) {
+ if ($nodePath == $path || strpos($nodePath,$path.'/')===0)
+ unset($this->cache[$nodePath]);
+
+ }
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/PartialUpdate/IFile.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/PartialUpdate/IFile.php
new file mode 100644
index 0000000..a3eee51
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/PartialUpdate/IFile.php
@@ -0,0 +1,40 @@
+addPlugin($patchPlugin);
+ *
+ * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
+ * @author Jean-Tiare LE BIGOT (http://www.jtlebi.fr/)
+ * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
+ */
+class Plugin extends DAV\ServerPlugin {
+
+ /**
+ * Reference to server
+ *
+ * @var SabreForRainLoop\DAV\Server
+ */
+ protected $server;
+
+ /**
+ * Initializes the plugin
+ *
+ * This method is automatically called by the Server class after addPlugin.
+ *
+ * @param DAV\Server $server
+ * @return void
+ */
+ public function initialize(DAV\Server $server) {
+
+ $this->server = $server;
+ $server->subscribeEvent('unknownMethod',array($this,'unknownMethod'));
+
+ }
+
+ /**
+ * Returns a plugin name.
+ *
+ * Using this name other plugins will be able to access other plugins
+ * using DAV\Server::getPlugin
+ *
+ * @return string
+ */
+ public function getPluginName() {
+
+ return 'partialupdate';
+
+ }
+
+ /**
+ * This method is called by the Server if the user used an HTTP method
+ * the server didn't recognize.
+ *
+ * This plugin intercepts the PATCH methods.
+ *
+ * @param string $method
+ * @param string $uri
+ * @return bool|null
+ */
+ public function unknownMethod($method, $uri) {
+
+ switch($method) {
+
+ case 'PATCH':
+ return $this->httpPatch($uri);
+
+ }
+
+ }
+
+ /**
+ * Use this method to tell the server this plugin defines additional
+ * HTTP methods.
+ *
+ * This method is passed a uri. It should only return HTTP methods that are
+ * available for the specified uri.
+ *
+ * We claim to support PATCH method (partial update) if and only if
+ * - the node exist
+ * - the node implements our partial update interface
+ *
+ * @param string $uri
+ * @return array
+ */
+ public function getHTTPMethods($uri) {
+
+ $tree = $this->server->tree;
+
+ if ($tree->nodeExists($uri) &&
+ $tree->getNodeForPath($uri) instanceof IFile) {
+ return array('PATCH');
+ }
+
+ return array();
+
+ }
+
+ /**
+ * Returns a list of features for the HTTP OPTIONS Dav: header.
+ *
+ * @return array
+ */
+ public function getFeatures() {
+
+ return array('sabredav-partialupdate');
+
+ }
+
+ /**
+ * Patch an uri
+ *
+ * The WebDAV patch request can be used to modify only a part of an
+ * existing resource. If the resource does not exist yet and the first
+ * offset is not 0, the request fails
+ *
+ * @param string $uri
+ * @return void
+ */
+ protected function httpPatch($uri) {
+
+ // Get the node. Will throw a 404 if not found
+ $node = $this->server->tree->getNodeForPath($uri);
+ if (!($node instanceof IFile)) {
+ throw new DAV\Exception\MethodNotAllowed('The target resource does not support the PATCH method.');
+ }
+
+ $range = $this->getHTTPUpdateRange();
+
+ if (!$range) {
+ throw new DAV\Exception\BadRequest('No valid "X-Update-Range" found in the headers');
+ }
+
+ $contentType = strtolower(
+ $this->server->httpRequest->getHeader('Content-Type')
+ );
+
+ if ($contentType != 'application/x-sabredav-partialupdate') {
+ throw new DAV\Exception\UnsupportedMediaType('Unknown Content-Type header "' . $contentType . '"');
+ }
+
+ $len = $this->server->httpRequest->getHeader('Content-Length');
+
+ // Load the begin and end data
+ $start = ($range[0])?$range[0]:0;
+ $end = ($range[1])?$range[1]:$len-1;
+
+ // Check consistency
+ if($end < $start)
+ throw new DAV\Exception\RequestedRangeNotSatisfiable('The end offset (' . $range[1] . ') is lower than the start offset (' . $range[0] . ')');
+ if($end - $start + 1 != $len)
+ throw new DAV\Exception\RequestedRangeNotSatisfiable('Actual data length (' . $len . ') is not consistent with begin (' . $range[0] . ') and end (' . $range[1] . ') offsets');
+
+ // Checking If-None-Match and related headers.
+ if (!$this->server->checkPreconditions()) return;
+
+ if (!$this->server->broadcastEvent('beforeWriteContent',array($uri, $node, null)))
+ return;
+
+ $body = $this->server->httpRequest->getBody();
+ $etag = $node->putRange($body, $start-1);
+
+ $this->server->broadcastEvent('afterWriteContent',array($uri, $node));
+
+ $this->server->httpResponse->setHeader('Content-Length','0');
+ if ($etag) $this->server->httpResponse->setHeader('ETag',$etag);
+ $this->server->httpResponse->sendStatus(204);
+
+ return false;
+
+ }
+
+ /**
+ * Returns the HTTP custom range update header
+ *
+ * This method returns null if there is no well-formed HTTP range request
+ * header or array($start, $end).
+ *
+ * The first number is the offset of the first byte in the range.
+ * The second number is the offset of the last byte in the range.
+ *
+ * If the second offset is null, it should be treated as the offset of the last byte of the entity
+ * If the first offset is null, the second offset should be used to retrieve the last x bytes of the entity
+ *
+ * @return array|null
+ */
+ public function getHTTPUpdateRange() {
+
+ $range = $this->server->httpRequest->getHeader('X-Update-Range');
+ if (is_null($range)) return null;
+
+ // Matching "Range: bytes=1234-5678: both numbers are optional
+
+ if (!preg_match('/^bytes=([0-9]*)-([0-9]*)$/i',$range,$matches)) return null;
+
+ if ($matches[1]==='' && $matches[2]==='') return null;
+
+ return array(
+ $matches[1]!==''?$matches[1]:null,
+ $matches[2]!==''?$matches[2]:null,
+ );
+
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property.php
new file mode 100644
index 0000000..36d4ea6
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property.php
@@ -0,0 +1,31 @@
+time = $time;
+ } elseif (is_int($time) || ctype_digit($time)) {
+ $this->time = new \DateTime('@' . $time);
+ } else {
+ $this->time = new \DateTime($time);
+ }
+
+ // Setting timezone to UTC
+ $this->time->setTimezone(new \DateTimeZone('UTC'));
+
+ }
+
+ /**
+ * serialize
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $prop
+ * @return void
+ */
+ public function serialize(DAV\Server $server, \DOMElement $prop) {
+
+ $doc = $prop->ownerDocument;
+ //$prop->setAttribute('xmlns:b','urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/');
+ //$prop->setAttribute('b:dt','dateTime.rfc1123');
+ $prop->nodeValue = HTTP\Util::toHTTPDate($this->time);
+
+ }
+
+ /**
+ * getTime
+ *
+ * @return \DateTime
+ */
+ public function getTime() {
+
+ return $this->time;
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/Href.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/Href.php
new file mode 100644
index 0000000..71dcc24
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/Href.php
@@ -0,0 +1,99 @@
+href = $href;
+ $this->autoPrefix = $autoPrefix;
+
+ }
+
+ /**
+ * Returns the uri
+ *
+ * @return string
+ */
+ public function getHref() {
+
+ return $this->href;
+
+ }
+
+ /**
+ * Serializes this property.
+ *
+ * It will additionally prepend the href property with the server's base uri.
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $dom
+ * @return void
+ */
+ public function serialize(DAV\Server $server, \DOMElement $dom) {
+
+ $prefix = $server->xmlNamespaces['DAV:'];
+ $elem = $dom->ownerDocument->createElement($prefix . ':href');
+
+ if ($this->autoPrefix) {
+ $value = $server->getBaseUri() . DAV\URLUtil::encodePath($this->href);
+ } else {
+ $value = $this->href;
+ }
+ $elem->appendChild($dom->ownerDocument->createTextNode($value));
+
+ $dom->appendChild($elem);
+
+ }
+
+ /**
+ * Unserializes this property from a DOM Element
+ *
+ * This method returns an instance of this class.
+ * It will only decode {DAV:}href values. For non-compatible elements null will be returned.
+ *
+ * @param \DOMElement $dom
+ * @return DAV\Property\Href
+ */
+ static function unserialize(\DOMElement $dom) {
+
+ if ($dom->firstChild && DAV\XMLUtil::toClarkNotation($dom->firstChild)==='{DAV:}href') {
+ return new self($dom->firstChild->textContent,false);
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/HrefList.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/HrefList.php
new file mode 100644
index 0000000..05ba266
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/HrefList.php
@@ -0,0 +1,105 @@
+hrefs = $hrefs;
+ $this->autoPrefix = $autoPrefix;
+
+ }
+
+ /**
+ * Returns the uris
+ *
+ * @return array
+ */
+ public function getHrefs() {
+
+ return $this->hrefs;
+
+ }
+
+ /**
+ * Serializes this property.
+ *
+ * It will additionally prepend the href property with the server's base uri.
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $dom
+ * @return void
+ */
+ public function serialize(DAV\Server $server,\DOMElement $dom) {
+
+ $prefix = $server->xmlNamespaces['DAV:'];
+
+ foreach($this->hrefs as $href) {
+
+ $elem = $dom->ownerDocument->createElement($prefix . ':href');
+ if ($this->autoPrefix) {
+ $value = $server->getBaseUri() . DAV\URLUtil::encodePath($href);
+ } else {
+ $value = $href;
+ }
+ $elem->appendChild($dom->ownerDocument->createTextNode($value));
+
+ $dom->appendChild($elem);
+ }
+
+ }
+
+ /**
+ * Unserializes this property from a DOM Element
+ *
+ * This method returns an instance of this class.
+ * It will only decode {DAV:}href values.
+ *
+ * @param \DOMElement $dom
+ * @return DAV\Property\HrefList
+ */
+ static function unserialize(\DOMElement $dom) {
+
+ $hrefs = array();
+ foreach($dom->childNodes as $child) {
+ if (DAV\XMLUtil::toClarkNotation($child)==='{DAV:}href') {
+ $hrefs[] = $child->textContent;
+ }
+ }
+ return new self($hrefs, false);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/IHref.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/IHref.php
new file mode 100644
index 0000000..d2b4d4d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/IHref.php
@@ -0,0 +1,25 @@
+locks = $locks;
+ $this->revealLockToken = $revealLockToken;
+
+ }
+
+ /**
+ * serialize
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $prop
+ * @return void
+ */
+ public function serialize(DAV\Server $server, \DOMElement $prop) {
+
+ $doc = $prop->ownerDocument;
+
+ foreach($this->locks as $lock) {
+
+ $activeLock = $doc->createElementNS('DAV:','d:activelock');
+ $prop->appendChild($activeLock);
+
+ $lockScope = $doc->createElementNS('DAV:','d:lockscope');
+ $activeLock->appendChild($lockScope);
+
+ $lockScope->appendChild($doc->createElementNS('DAV:','d:' . ($lock->scope==DAV\Locks\LockInfo::EXCLUSIVE?'exclusive':'shared')));
+
+ $lockType = $doc->createElementNS('DAV:','d:locktype');
+ $activeLock->appendChild($lockType);
+
+ $lockType->appendChild($doc->createElementNS('DAV:','d:write'));
+
+ /* {DAV:}lockroot */
+ if (!self::$hideLockRoot) {
+ $lockRoot = $doc->createElementNS('DAV:','d:lockroot');
+ $activeLock->appendChild($lockRoot);
+ $href = $doc->createElementNS('DAV:','d:href');
+ $href->appendChild($doc->createTextNode($server->getBaseUri() . $lock->uri));
+ $lockRoot->appendChild($href);
+ }
+
+ $activeLock->appendChild($doc->createElementNS('DAV:','d:depth',($lock->depth == DAV\Server::DEPTH_INFINITY?'infinity':$lock->depth)));
+ $activeLock->appendChild($doc->createElementNS('DAV:','d:timeout','Second-' . $lock->timeout));
+
+ if ($this->revealLockToken) {
+ $lockToken = $doc->createElementNS('DAV:','d:locktoken');
+ $activeLock->appendChild($lockToken);
+ $lockToken->appendChild($doc->createElementNS('DAV:','d:href','opaquelocktoken:' . $lock->token));
+ }
+
+ $activeLock->appendChild($doc->createElementNS('DAV:','d:owner',$lock->owner));
+
+ }
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/ResourceType.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/ResourceType.php
new file mode 100644
index 0000000..7d12e31
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/ResourceType.php
@@ -0,0 +1,127 @@
+resourceType = array();
+ elseif ($resourceType === DAV\Server::NODE_DIRECTORY)
+ $this->resourceType = array('{DAV:}collection');
+ elseif (is_array($resourceType))
+ $this->resourceType = $resourceType;
+ else
+ $this->resourceType = array($resourceType);
+
+ }
+
+ /**
+ * serialize
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $prop
+ * @return void
+ */
+ public function serialize(DAV\Server $server, \DOMElement $prop) {
+
+ $propName = null;
+ $rt = $this->resourceType;
+
+ foreach($rt as $resourceType) {
+ if (preg_match('/^{([^}]*)}(.*)$/',$resourceType,$propName)) {
+
+ if (isset($server->xmlNamespaces[$propName[1]])) {
+ $prop->appendChild($prop->ownerDocument->createElement($server->xmlNamespaces[$propName[1]] . ':' . $propName[2]));
+ } else {
+ $prop->appendChild($prop->ownerDocument->createElementNS($propName[1],'custom:' . $propName[2]));
+ }
+
+ }
+ }
+
+ }
+
+ /**
+ * Returns the values in clark-notation
+ *
+ * For example array('{DAV:}collection')
+ *
+ * @return array
+ */
+ public function getValue() {
+
+ return $this->resourceType;
+
+ }
+
+ /**
+ * Checks if the principal contains a certain value
+ *
+ * @param string $type
+ * @return bool
+ */
+ public function is($type) {
+
+ return in_array($type, $this->resourceType);
+
+ }
+
+ /**
+ * Adds a resourcetype value to this property
+ *
+ * @param string $type
+ * @return void
+ */
+ public function add($type) {
+
+ $this->resourceType[] = $type;
+ $this->resourceType = array_unique($this->resourceType);
+
+ }
+
+ /**
+ * Unserializes a DOM element into a ResourceType property.
+ *
+ * @param \DOMElement $dom
+ * @return DAV\Property\ResourceType
+ */
+ static public function unserialize(\DOMElement $dom) {
+
+ $value = array();
+ foreach($dom->childNodes as $child) {
+
+ $value[] = DAV\XMLUtil::toClarkNotation($child);
+
+ }
+
+ return new self($value);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/Response.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/Response.php
new file mode 100644
index 0000000..151e795
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/Response.php
@@ -0,0 +1,157 @@
+href = $href;
+ $this->responseProperties = $responseProperties;
+
+ }
+
+ /**
+ * Returns the url
+ *
+ * @return string
+ */
+ public function getHref() {
+
+ return $this->href;
+
+ }
+
+ /**
+ * Returns the property list
+ *
+ * @return array
+ */
+ public function getResponseProperties() {
+
+ return $this->responseProperties;
+
+ }
+
+ /**
+ * serialize
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $dom
+ * @return void
+ */
+ public function serialize(DAV\Server $server, \DOMElement $dom) {
+
+ $document = $dom->ownerDocument;
+ $properties = $this->responseProperties;
+
+ $xresponse = $document->createElement('d:response');
+ $dom->appendChild($xresponse);
+
+ $uri = DAV\URLUtil::encodePath($this->href);
+
+ // Adding the baseurl to the beginning of the url
+ $uri = $server->getBaseUri() . $uri;
+
+ $xresponse->appendChild($document->createElement('d:href',$uri));
+
+ // The properties variable is an array containing properties, grouped by
+ // HTTP status
+ foreach($properties as $httpStatus=>$propertyGroup) {
+
+ // The 'href' is also in this array, and it's special cased.
+ // We will ignore it
+ if ($httpStatus=='href') continue;
+
+ // If there are no properties in this group, we can also just carry on
+ if (!count($propertyGroup)) continue;
+
+ $xpropstat = $document->createElement('d:propstat');
+ $xresponse->appendChild($xpropstat);
+
+ $xprop = $document->createElement('d:prop');
+ $xpropstat->appendChild($xprop);
+
+ $nsList = $server->xmlNamespaces;
+
+ foreach($propertyGroup as $propertyName=>$propertyValue) {
+
+ $propName = null;
+ preg_match('/^{([^}]*)}(.*)$/',$propertyName,$propName);
+
+ // special case for empty namespaces
+ if ($propName[1]=='') {
+
+ $currentProperty = $document->createElement($propName[2]);
+ $xprop->appendChild($currentProperty);
+ $currentProperty->setAttribute('xmlns','');
+
+ } else {
+
+ if (!isset($nsList[$propName[1]])) {
+ $nsList[$propName[1]] = 'x' . count($nsList);
+ }
+
+ // If the namespace was defined in the top-level xml namespaces, it means
+ // there was already a namespace declaration, and we don't have to worry about it.
+ if (isset($server->xmlNamespaces[$propName[1]])) {
+ $currentProperty = $document->createElement($nsList[$propName[1]] . ':' . $propName[2]);
+ } else {
+ $currentProperty = $document->createElementNS($propName[1],$nsList[$propName[1]].':' . $propName[2]);
+ }
+ $xprop->appendChild($currentProperty);
+
+ }
+
+ if (is_scalar($propertyValue)) {
+ $text = $document->createTextNode($propertyValue);
+ $currentProperty->appendChild($text);
+ } elseif ($propertyValue instanceof DAV\PropertyInterface) {
+ $propertyValue->serialize($server,$currentProperty);
+ } elseif (!is_null($propertyValue)) {
+ throw new DAV\Exception('Unknown property value type: ' . gettype($propertyValue) . ' for property: ' . $propertyName);
+ }
+
+ }
+
+ $xpropstat->appendChild($document->createElement('d:status',$server->httpResponse->getStatusMessage($httpStatus)));
+
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/ResponseList.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/ResponseList.php
new file mode 100644
index 0000000..62c4308
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/ResponseList.php
@@ -0,0 +1,59 @@
+responses = $responses;
+
+ }
+
+ /**
+ * serialize
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $dom
+ * @return void
+ */
+ public function serialize(DAV\Server $server,\DOMElement $dom) {
+
+ foreach($this->responses as $response) {
+ $response->serialize($server, $dom);
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/SupportedLock.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/SupportedLock.php
new file mode 100644
index 0000000..5ddde64
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/SupportedLock.php
@@ -0,0 +1,78 @@
+supportsLocks = $supportsLocks;
+
+ }
+
+ /**
+ * serialize
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $prop
+ * @return void
+ */
+ public function serialize(DAV\Server $server,\DOMElement $prop) {
+
+ $doc = $prop->ownerDocument;
+
+ if (!$this->supportsLocks) return null;
+
+ $lockEntry1 = $doc->createElement('d:lockentry');
+ $lockEntry2 = $doc->createElement('d:lockentry');
+
+ $prop->appendChild($lockEntry1);
+ $prop->appendChild($lockEntry2);
+
+ $lockScope1 = $doc->createElement('d:lockscope');
+ $lockScope2 = $doc->createElement('d:lockscope');
+ $lockType1 = $doc->createElement('d:locktype');
+ $lockType2 = $doc->createElement('d:locktype');
+
+ $lockEntry1->appendChild($lockScope1);
+ $lockEntry1->appendChild($lockType1);
+ $lockEntry2->appendChild($lockScope2);
+ $lockEntry2->appendChild($lockType2);
+
+ $lockScope1->appendChild($doc->createElement('d:exclusive'));
+ $lockScope2->appendChild($doc->createElement('d:shared'));
+
+ $lockType1->appendChild($doc->createElement('d:write'));
+ $lockType2->appendChild($doc->createElement('d:write'));
+
+ //$frag->appendXML(' ');
+ //$frag->appendXML(' ');
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/SupportedReportSet.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/SupportedReportSet.php
new file mode 100644
index 0000000..d0273e4
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Property/SupportedReportSet.php
@@ -0,0 +1,111 @@
+addReport($reports);
+
+ }
+
+ /**
+ * Adds a report to this property
+ *
+ * The report must be a string in clark-notation.
+ * Multiple reports can be specified as an array.
+ *
+ * @param mixed $report
+ * @return void
+ */
+ public function addReport($report) {
+
+ if (!is_array($report)) $report = array($report);
+
+ foreach($report as $r) {
+
+ if (!preg_match('/^{([^}]*)}(.*)$/',$r))
+ throw new DAV\Exception('Reportname must be in clark-notation');
+
+ $this->reports[] = $r;
+
+ }
+
+ }
+
+ /**
+ * Returns the list of supported reports
+ *
+ * @return array
+ */
+ public function getValue() {
+
+ return $this->reports;
+
+ }
+
+ /**
+ * Serializes the node
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $prop
+ * @return void
+ */
+ public function serialize(DAV\Server $server, \DOMElement $prop) {
+
+ foreach($this->reports as $reportName) {
+
+ $supportedReport = $prop->ownerDocument->createElement('d:supported-report');
+ $prop->appendChild($supportedReport);
+
+ $report = $prop->ownerDocument->createElement('d:report');
+ $supportedReport->appendChild($report);
+
+ preg_match('/^{([^}]*)}(.*)$/',$reportName,$matches);
+
+ list(, $namespace, $element) = $matches;
+
+ $prefix = isset($server->xmlNamespaces[$namespace])?$server->xmlNamespaces[$namespace]:null;
+
+ if ($prefix) {
+ $report->appendChild($prop->ownerDocument->createElement($prefix . ':' . $element));
+ } else {
+ $report->appendChild($prop->ownerDocument->createElementNS($namespace, 'x:' . $element));
+ }
+
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/PropertyInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/PropertyInterface.php
new file mode 100644
index 0000000..fe0c016
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/PropertyInterface.php
@@ -0,0 +1,21 @@
+ 'd',
+ 'http://sabredav.org/ns' => 's',
+ );
+
+ /**
+ * The propertymap can be used to map properties from
+ * requests to property classes.
+ *
+ * @var array
+ */
+ public $propertyMap = array(
+ '{DAV:}resourcetype' => 'SabreForRainLoop\\DAV\\Property\\ResourceType',
+ );
+
+ public $protectedProperties = array(
+ // RFC4918
+ '{DAV:}getcontentlength',
+ '{DAV:}getetag',
+ '{DAV:}getlastmodified',
+ '{DAV:}lockdiscovery',
+ '{DAV:}supportedlock',
+
+ // RFC4331
+ '{DAV:}quota-available-bytes',
+ '{DAV:}quota-used-bytes',
+
+ // RFC3744
+ '{DAV:}supported-privilege-set',
+ '{DAV:}current-user-privilege-set',
+ '{DAV:}acl',
+ '{DAV:}acl-restrictions',
+ '{DAV:}inherited-acl-set',
+
+ );
+
+ /**
+ * This is a flag that allow or not showing file, line and code
+ * of the exception in the returned XML
+ *
+ * @var bool
+ */
+ public $debugExceptions = false;
+
+ /**
+ * This property allows you to automatically add the 'resourcetype' value
+ * based on a node's classname or interface.
+ *
+ * The preset ensures that {DAV:}collection is automaticlly added for nodes
+ * implementing SabreForRainLoop\DAV\ICollection.
+ *
+ * @var array
+ */
+ public $resourceTypeMapping = array(
+ 'SabreForRainLoop\\DAV\\ICollection' => '{DAV:}collection',
+ );
+
+ /**
+ * If this setting is turned off, SabreDAV's version number will be hidden
+ * from various places.
+ *
+ * Some people feel this is a good security measure.
+ *
+ * @var bool
+ */
+ static public $exposeVersion = true;
+
+ /**
+ * Sets up the server
+ *
+ * If a SabreForRainLoop\DAV\Tree object is passed as an argument, it will
+ * use it as the directory tree. If a SabreForRainLoop\DAV\INode is passed, it
+ * will create a SabreForRainLoop\DAV\ObjectTree and use the node as the root.
+ *
+ * If nothing is passed, a SabreForRainLoop\DAV\SimpleCollection is created in
+ * a SabreForRainLoop\DAV\ObjectTree.
+ *
+ * If an array is passed, we automatically create a root node, and use
+ * the nodes in the array as top-level children.
+ *
+ * @param Tree|INode|array|null $treeOrNode The tree object
+ */
+ public function __construct($treeOrNode = null) {
+
+ if ($treeOrNode instanceof Tree) {
+ $this->tree = $treeOrNode;
+ } elseif ($treeOrNode instanceof INode) {
+ $this->tree = new ObjectTree($treeOrNode);
+ } elseif (is_array($treeOrNode)) {
+
+ // If it's an array, a list of nodes was passed, and we need to
+ // create the root node.
+ foreach($treeOrNode as $node) {
+ if (!($node instanceof INode)) {
+ throw new Exception('Invalid argument passed to constructor. If you\'re passing an array, all the values must implement SabreForRainLoop\\DAV\\INode');
+ }
+ }
+
+ $root = new SimpleCollection('root', $treeOrNode);
+ $this->tree = new ObjectTree($root);
+
+ } elseif (is_null($treeOrNode)) {
+ $root = new SimpleCollection('root');
+ $this->tree = new ObjectTree($root);
+ } else {
+ throw new Exception('Invalid argument passed to constructor. Argument must either be an instance of SabreForRainLoop\\DAV\\Tree, SabreForRainLoop\\DAV\\INode, an array or null');
+ }
+ $this->httpResponse = new HTTP\Response();
+ $this->httpRequest = new HTTP\Request();
+
+ }
+
+ /**
+ * Starts the DAV Server
+ *
+ * @return void
+ */
+ public function exec() {
+
+ try {
+
+ // If nginx (pre-1.2) is used as a proxy server, and SabreDAV as an
+ // origin, we must make sure we send back HTTP/1.0 if this was
+ // requested.
+ // This is mainly because nginx doesn't support Chunked Transfer
+ // Encoding, and this forces the webserver SabreDAV is running on,
+ // to buffer entire responses to calculate Content-Length.
+ $this->httpResponse->defaultHttpVersion = $this->httpRequest->getHTTPVersion();
+
+ $this->invokeMethod($this->httpRequest->getMethod(), $this->getRequestUri());
+
+ } catch (Exception $e) {
+
+ try {
+ $this->broadcastEvent('exception', array($e));
+ } catch (Exception $ignore) {
+ }
+ $DOM = new \DOMDocument('1.0','utf-8');
+ $DOM->formatOutput = true;
+
+ $error = $DOM->createElementNS('DAV:','d:error');
+ $error->setAttribute('xmlns:s',self::NS_SABREDAV);
+ $DOM->appendChild($error);
+
+ $h = function($v) {
+
+ return htmlspecialchars($v, ENT_NOQUOTES, 'UTF-8');
+
+ };
+
+ $error->appendChild($DOM->createElement('s:exception',$h(get_class($e))));
+ $error->appendChild($DOM->createElement('s:message',$h($e->getMessage())));
+ if ($this->debugExceptions) {
+ $error->appendChild($DOM->createElement('s:file',$h($e->getFile())));
+ $error->appendChild($DOM->createElement('s:line',$h($e->getLine())));
+ $error->appendChild($DOM->createElement('s:code',$h($e->getCode())));
+ $error->appendChild($DOM->createElement('s:stacktrace',$h($e->getTraceAsString())));
+
+ }
+ if (self::$exposeVersion) {
+ $error->appendChild($DOM->createElement('s:sabredav-version',$h(Version::VERSION)));
+ }
+
+ if($e instanceof Exception) {
+
+ $httpCode = $e->getHTTPCode();
+ $e->serialize($this,$error);
+ $headers = $e->getHTTPHeaders($this);
+
+ } else {
+
+ $httpCode = 500;
+ $headers = array();
+
+ }
+ $headers['Content-Type'] = 'application/xml; charset=utf-8';
+
+ $this->httpResponse->sendStatus($httpCode);
+ $this->httpResponse->setHeaders($headers);
+ $this->httpResponse->sendBody($DOM->saveXML());
+
+ }
+
+ }
+
+ /**
+ * Sets the base server uri
+ *
+ * @param string $uri
+ * @return void
+ */
+ public function setBaseUri($uri) {
+
+ // If the baseUri does not end with a slash, we must add it
+ if ($uri[strlen($uri)-1]!=='/')
+ $uri.='/';
+
+ $this->baseUri = $uri;
+
+ }
+
+ /**
+ * Returns the base responding uri
+ *
+ * @return string
+ */
+ public function getBaseUri() {
+
+ if (is_null($this->baseUri)) $this->baseUri = $this->guessBaseUri();
+ return $this->baseUri;
+
+ }
+
+ /**
+ * This method attempts to detect the base uri.
+ * Only the PATH_INFO variable is considered.
+ *
+ * If this variable is not set, the root (/) is assumed.
+ *
+ * @return string
+ */
+ public function guessBaseUri() {
+
+ $pathInfo = $this->httpRequest->getRawServerValue('PATH_INFO');
+ $uri = $this->httpRequest->getRawServerValue('REQUEST_URI');
+
+ // If PATH_INFO is found, we can assume it's accurate.
+ if (!empty($pathInfo)) {
+
+ // We need to make sure we ignore the QUERY_STRING part
+ if ($pos = strpos($uri,'?'))
+ $uri = substr($uri,0,$pos);
+
+ // PATH_INFO is only set for urls, such as: /example.php/path
+ // in that case PATH_INFO contains '/path'.
+ // Note that REQUEST_URI is percent encoded, while PATH_INFO is
+ // not, Therefore they are only comparable if we first decode
+ // REQUEST_INFO as well.
+ $decodedUri = URLUtil::decodePath($uri);
+
+ // A simple sanity check:
+ if(substr($decodedUri,strlen($decodedUri)-strlen($pathInfo))===$pathInfo) {
+ $baseUri = substr($decodedUri,0,strlen($decodedUri)-strlen($pathInfo));
+ return rtrim($baseUri,'/') . '/';
+ }
+
+ throw new Exception('The REQUEST_URI ('. $uri . ') did not end with the contents of PATH_INFO (' . $pathInfo . '). This server might be misconfigured.');
+
+ }
+
+ // The last fallback is that we're just going to assume the server root.
+ return '/';
+
+ }
+
+ /**
+ * Adds a plugin to the server
+ *
+ * For more information, console the documentation of SabreForRainLoop\DAV\ServerPlugin
+ *
+ * @param ServerPlugin $plugin
+ * @return void
+ */
+ public function addPlugin(ServerPlugin $plugin) {
+
+ $this->plugins[$plugin->getPluginName()] = $plugin;
+ $plugin->initialize($this);
+
+ }
+
+ /**
+ * Returns an initialized plugin by it's name.
+ *
+ * This function returns null if the plugin was not found.
+ *
+ * @param string $name
+ * @return ServerPlugin
+ */
+ public function getPlugin($name) {
+
+ if (isset($this->plugins[$name]))
+ return $this->plugins[$name];
+
+ // This is a fallback and deprecated.
+ foreach($this->plugins as $plugin) {
+ if (get_class($plugin)===$name) return $plugin;
+ }
+
+ return null;
+
+ }
+
+ /**
+ * Returns all plugins
+ *
+ * @return array
+ */
+ public function getPlugins() {
+
+ return $this->plugins;
+
+ }
+
+
+ /**
+ * Subscribe to an event.
+ *
+ * When the event is triggered, we'll call all the specified callbacks.
+ * It is possible to control the order of the callbacks through the
+ * priority argument.
+ *
+ * This is for example used to make sure that the authentication plugin
+ * is triggered before anything else. If it's not needed to change this
+ * number, it is recommended to ommit.
+ *
+ * @param string $event
+ * @param callback $callback
+ * @param int $priority
+ * @return void
+ */
+ public function subscribeEvent($event, $callback, $priority = 100) {
+
+ if (!isset($this->eventSubscriptions[$event])) {
+ $this->eventSubscriptions[$event] = array();
+ }
+ while(isset($this->eventSubscriptions[$event][$priority])) $priority++;
+ $this->eventSubscriptions[$event][$priority] = $callback;
+ ksort($this->eventSubscriptions[$event]);
+
+ }
+
+ /**
+ * Broadcasts an event
+ *
+ * This method will call all subscribers. If one of the subscribers returns false, the process stops.
+ *
+ * The arguments parameter will be sent to all subscribers
+ *
+ * @param string $eventName
+ * @param array $arguments
+ * @return bool
+ */
+ public function broadcastEvent($eventName,$arguments = array()) {
+
+ if (isset($this->eventSubscriptions[$eventName])) {
+
+ foreach($this->eventSubscriptions[$eventName] as $subscriber) {
+
+ $result = call_user_func_array($subscriber,$arguments);
+ if ($result===false) return false;
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+ /**
+ * Handles a http request, and execute a method based on its name
+ *
+ * @param string $method
+ * @param string $uri
+ * @return void
+ */
+ public function invokeMethod($method, $uri) {
+
+ $method = strtoupper($method);
+
+ if (!$this->broadcastEvent('beforeMethod',array($method, $uri))) return;
+
+ // Make sure this is a HTTP method we support
+ $internalMethods = array(
+ 'OPTIONS',
+ 'GET',
+ 'HEAD',
+ 'DELETE',
+ 'PROPFIND',
+ 'MKCOL',
+ 'PUT',
+ 'PROPPATCH',
+ 'COPY',
+ 'MOVE',
+ 'REPORT'
+ );
+
+ if (in_array($method,$internalMethods)) {
+
+ call_user_func(array($this,'http' . $method), $uri);
+
+ } else {
+
+ if ($this->broadcastEvent('unknownMethod',array($method, $uri))) {
+ // Unsupported method
+ throw new Exception\NotImplemented('There was no handler found for this "' . $method . '" method');
+ }
+
+ }
+
+ }
+
+ // {{{ HTTP Method implementations
+
+ /**
+ * HTTP OPTIONS
+ *
+ * @param string $uri
+ * @return void
+ */
+ protected function httpOptions($uri) {
+
+ $methods = $this->getAllowedMethods($uri);
+
+ $this->httpResponse->setHeader('Allow',strtoupper(implode(', ',$methods)));
+ $features = array('1','3', 'extended-mkcol');
+
+ foreach($this->plugins as $plugin) $features = array_merge($features,$plugin->getFeatures());
+
+ $this->httpResponse->setHeader('DAV',implode(', ',$features));
+ $this->httpResponse->setHeader('MS-Author-Via','DAV');
+ $this->httpResponse->setHeader('Accept-Ranges','bytes');
+ if (self::$exposeVersion) {
+ $this->httpResponse->setHeader('X-Sabre-Version',Version::VERSION);
+ }
+ $this->httpResponse->setHeader('Content-Length',0);
+ $this->httpResponse->sendStatus(200);
+
+ }
+
+ /**
+ * HTTP GET
+ *
+ * This method simply fetches the contents of a uri, like normal
+ *
+ * @param string $uri
+ * @return bool
+ */
+ protected function httpGet($uri) {
+
+ $node = $this->tree->getNodeForPath($uri,0);
+
+ if (!$this->checkPreconditions(true)) return false;
+ if (!$node instanceof IFile) throw new Exception\NotImplemented('GET is only implemented on File objects');
+
+ $body = $node->get();
+
+ // Converting string into stream, if needed.
+ if (is_string($body)) {
+ $stream = fopen('php://temp','r+');
+ fwrite($stream,$body);
+ rewind($stream);
+ $body = $stream;
+ }
+
+ /*
+ * TODO: getetag, getlastmodified, getsize should also be used using
+ * this method
+ */
+ $httpHeaders = $this->getHTTPHeaders($uri);
+
+ /* ContentType needs to get a default, because many webservers will otherwise
+ * default to text/html, and we don't want this for security reasons.
+ */
+ if (!isset($httpHeaders['Content-Type'])) {
+ $httpHeaders['Content-Type'] = 'application/octet-stream';
+ }
+
+
+ if (isset($httpHeaders['Content-Length'])) {
+
+ $nodeSize = $httpHeaders['Content-Length'];
+
+ // Need to unset Content-Length, because we'll handle that during figuring out the range
+ unset($httpHeaders['Content-Length']);
+
+ } else {
+ $nodeSize = null;
+ }
+
+ $this->httpResponse->setHeaders($httpHeaders);
+
+ $range = $this->getHTTPRange();
+ $ifRange = $this->httpRequest->getHeader('If-Range');
+ $ignoreRangeHeader = false;
+
+ // If ifRange is set, and range is specified, we first need to check
+ // the precondition.
+ if ($nodeSize && $range && $ifRange) {
+
+ // if IfRange is parsable as a date we'll treat it as a DateTime
+ // otherwise, we must treat it as an etag.
+ try {
+ $ifRangeDate = new \DateTime($ifRange);
+
+ // It's a date. We must check if the entity is modified since
+ // the specified date.
+ if (!isset($httpHeaders['Last-Modified'])) $ignoreRangeHeader = true;
+ else {
+ $modified = new \DateTime($httpHeaders['Last-Modified']);
+ if($modified > $ifRangeDate) $ignoreRangeHeader = true;
+ }
+
+ } catch (\Exception $e) {
+
+ // It's an entity. We can do a simple comparison.
+ if (!isset($httpHeaders['ETag'])) $ignoreRangeHeader = true;
+ elseif ($httpHeaders['ETag']!==$ifRange) $ignoreRangeHeader = true;
+ }
+ }
+
+ // We're only going to support HTTP ranges if the backend provided a filesize
+ if (!$ignoreRangeHeader && $nodeSize && $range) {
+
+ // Determining the exact byte offsets
+ if (!is_null($range[0])) {
+
+ $start = $range[0];
+ $end = $range[1]?$range[1]:$nodeSize-1;
+ if($start >= $nodeSize)
+ throw new Exception\RequestedRangeNotSatisfiable('The start offset (' . $range[0] . ') exceeded the size of the entity (' . $nodeSize . ')');
+
+ if($end < $start) throw new Exception\RequestedRangeNotSatisfiable('The end offset (' . $range[1] . ') is lower than the start offset (' . $range[0] . ')');
+ if($end >= $nodeSize) $end = $nodeSize-1;
+
+ } else {
+
+ $start = $nodeSize-$range[1];
+ $end = $nodeSize-1;
+
+ if ($start<0) $start = 0;
+
+ }
+
+ // New read/write stream
+ $newStream = fopen('php://temp','r+');
+
+ // stream_copy_to_stream() has a bug/feature: the `whence` argument
+ // is interpreted as SEEK_SET (count from absolute offset 0), while
+ // for a stream it should be SEEK_CUR (count from current offset).
+ // If a stream is nonseekable, the function fails. So we *emulate*
+ // the correct behaviour with fseek():
+ if ($start > 0) {
+ if (($curOffs = ftell($body)) === false) $curOffs = 0;
+ fseek($body, $start - $curOffs, SEEK_CUR);
+ }
+ stream_copy_to_stream($body, $newStream, $end-$start+1);
+ rewind($newStream);
+
+ $this->httpResponse->setHeader('Content-Length', $end-$start+1);
+ $this->httpResponse->setHeader('Content-Range','bytes ' . $start . '-' . $end . '/' . $nodeSize);
+ $this->httpResponse->sendStatus(206);
+ $this->httpResponse->sendBody($newStream);
+
+
+ } else {
+
+ if ($nodeSize) $this->httpResponse->setHeader('Content-Length',$nodeSize);
+ $this->httpResponse->sendStatus(200);
+ $this->httpResponse->sendBody($body);
+
+ }
+
+ }
+
+ /**
+ * HTTP HEAD
+ *
+ * This method is normally used to take a peak at a url, and only get the HTTP response headers, without the body
+ * This is used by clients to determine if a remote file was changed, so they can use a local cached version, instead of downloading it again
+ *
+ * @param string $uri
+ * @return void
+ */
+ protected function httpHead($uri) {
+
+ $node = $this->tree->getNodeForPath($uri);
+ /* This information is only collection for File objects.
+ * Ideally we want to throw 405 Method Not Allowed for every
+ * non-file, but MS Office does not like this
+ */
+ if ($node instanceof IFile) {
+ $headers = $this->getHTTPHeaders($this->getRequestUri());
+ if (!isset($headers['Content-Type'])) {
+ $headers['Content-Type'] = 'application/octet-stream';
+ }
+ $this->httpResponse->setHeaders($headers);
+ }
+ $this->httpResponse->sendStatus(200);
+
+ }
+
+ /**
+ * HTTP Delete
+ *
+ * The HTTP delete method, deletes a given uri
+ *
+ * @param string $uri
+ * @return void
+ */
+ protected function httpDelete($uri) {
+
+ if (!$this->broadcastEvent('beforeUnbind',array($uri))) return;
+ $this->tree->delete($uri);
+ $this->broadcastEvent('afterUnbind',array($uri));
+
+ $this->httpResponse->sendStatus(204);
+ $this->httpResponse->setHeader('Content-Length','0');
+
+ }
+
+
+ /**
+ * WebDAV PROPFIND
+ *
+ * This WebDAV method requests information about an uri resource, or a list of resources
+ * If a client wants to receive the properties for a single resource it will add an HTTP Depth: header with a 0 value
+ * If the value is 1, it means that it also expects a list of sub-resources (e.g.: files in a directory)
+ *
+ * The request body contains an XML data structure that has a list of properties the client understands
+ * The response body is also an xml document, containing information about every uri resource and the requested properties
+ *
+ * It has to return a HTTP 207 Multi-status status code
+ *
+ * @param string $uri
+ * @return void
+ */
+ protected function httpPropfind($uri) {
+
+ $requestedProperties = $this->parsePropFindRequest($this->httpRequest->getBody(true));
+
+ $depth = $this->getHTTPDepth(1);
+ // The only two options for the depth of a propfind is 0 or 1
+ if ($depth!=0) $depth = 1;
+
+ $newProperties = $this->getPropertiesForPath($uri,$requestedProperties,$depth);
+
+ // This is a multi-status response
+ $this->httpResponse->sendStatus(207);
+ $this->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
+ $this->httpResponse->setHeader('Vary','Brief,Prefer');
+
+ // Normally this header is only needed for OPTIONS responses, however..
+ // iCal seems to also depend on these being set for PROPFIND. Since
+ // this is not harmful, we'll add it.
+ $features = array('1','3', 'extended-mkcol');
+ foreach($this->plugins as $plugin) $features = array_merge($features,$plugin->getFeatures());
+ $this->httpResponse->setHeader('DAV',implode(', ',$features));
+
+ $prefer = $this->getHTTPPrefer();
+ $minimal = $prefer['return-minimal'];
+
+ $data = $this->generateMultiStatus($newProperties, $minimal);
+ $this->httpResponse->sendBody($data);
+
+ }
+
+ /**
+ * WebDAV PROPPATCH
+ *
+ * This method is called to update properties on a Node. The request is an XML body with all the mutations.
+ * In this XML body it is specified which properties should be set/updated and/or deleted
+ *
+ * @param string $uri
+ * @return void
+ */
+ protected function httpPropPatch($uri) {
+
+ $newProperties = $this->parsePropPatchRequest($this->httpRequest->getBody(true));
+
+ $result = $this->updateProperties($uri, $newProperties);
+
+ $prefer = $this->getHTTPPrefer();
+ $this->httpResponse->setHeader('Vary','Brief,Prefer');
+
+ if ($prefer['return-minimal']) {
+
+ // If return-minimal is specified, we only have to check if the
+ // request was succesful, and don't need to return the
+ // multi-status.
+ $ok = true;
+ foreach($result as $code=>$prop) {
+ if ((int)$code > 299) {
+ $ok = false;
+ }
+ }
+
+ if ($ok) {
+
+ $this->httpResponse->sendStatus(204);
+ return;
+
+ }
+
+ }
+
+ $this->httpResponse->sendStatus(207);
+ $this->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
+
+ $this->httpResponse->sendBody(
+ $this->generateMultiStatus(array($result))
+ );
+
+ }
+
+ /**
+ * HTTP PUT method
+ *
+ * This HTTP method updates a file, or creates a new one.
+ *
+ * If a new resource was created, a 201 Created status code should be returned. If an existing resource is updated, it's a 204 No Content
+ *
+ * @param string $uri
+ * @return bool
+ */
+ protected function httpPut($uri) {
+
+ $body = $this->httpRequest->getBody();
+
+ // Intercepting Content-Range
+ if ($this->httpRequest->getHeader('Content-Range')) {
+ /**
+ Content-Range is dangerous for PUT requests: PUT per definition
+ stores a full resource. draft-ietf-httpbis-p2-semantics-15 says
+ in section 7.6:
+ An origin server SHOULD reject any PUT request that contains a
+ Content-Range header field, since it might be misinterpreted as
+ partial content (or might be partial content that is being mistakenly
+ PUT as a full representation). Partial content updates are possible
+ by targeting a separately identified resource with state that
+ overlaps a portion of the larger resource, or by using a different
+ method that has been specifically defined for partial updates (for
+ example, the PATCH method defined in [RFC5789]).
+ This clarifies RFC2616 section 9.6:
+ The recipient of the entity MUST NOT ignore any Content-*
+ (e.g. Content-Range) headers that it does not understand or implement
+ and MUST return a 501 (Not Implemented) response in such cases.
+ OTOH is a PUT request with a Content-Range currently the only way to
+ continue an aborted upload request and is supported by curl, mod_dav,
+ Tomcat and others. Since some clients do use this feature which results
+ in unexpected behaviour (cf PEAR::HTTP_WebDAV_Client 1.0.1), we reject
+ all PUT requests with a Content-Range for now.
+ */
+
+ throw new Exception\NotImplemented('PUT with Content-Range is not allowed.');
+ }
+
+ // Intercepting the Finder problem
+ if (($expected = $this->httpRequest->getHeader('X-Expected-Entity-Length')) && $expected > 0) {
+
+ /**
+ Many webservers will not cooperate well with Finder PUT requests,
+ because it uses 'Chunked' transfer encoding for the request body.
+
+ The symptom of this problem is that Finder sends files to the
+ server, but they arrive as 0-length files in PHP.
+
+ If we don't do anything, the user might think they are uploading
+ files successfully, but they end up empty on the server. Instead,
+ we throw back an error if we detect this.
+
+ The reason Finder uses Chunked, is because it thinks the files
+ might change as it's being uploaded, and therefore the
+ Content-Length can vary.
+
+ Instead it sends the X-Expected-Entity-Length header with the size
+ of the file at the very start of the request. If this header is set,
+ but we don't get a request body we will fail the request to
+ protect the end-user.
+ */
+
+ // Only reading first byte
+ $firstByte = fread($body,1);
+ if (strlen($firstByte)!==1) {
+ throw new Exception\Forbidden('This server is not compatible with OS/X finder. Consider using a different WebDAV client or webserver.');
+ }
+
+ // The body needs to stay intact, so we copy everything to a
+ // temporary stream.
+
+ $newBody = fopen('php://temp','r+');
+ fwrite($newBody,$firstByte);
+ stream_copy_to_stream($body, $newBody);
+ rewind($newBody);
+
+ $body = $newBody;
+
+ }
+
+ if ($this->tree->nodeExists($uri)) {
+
+ $node = $this->tree->getNodeForPath($uri);
+
+ // Checking If-None-Match and related headers.
+ if (!$this->checkPreconditions()) return;
+
+ // If the node is a collection, we'll deny it
+ if (!($node instanceof IFile)) throw new Exception\Conflict('PUT is not allowed on non-files.');
+ if (!$this->broadcastEvent('beforeWriteContent',array($uri, $node, &$body))) return false;
+
+ $etag = $node->put($body);
+
+ $this->broadcastEvent('afterWriteContent',array($uri, $node));
+
+ $this->httpResponse->setHeader('Content-Length','0');
+ if ($etag) $this->httpResponse->setHeader('ETag',$etag);
+ $this->httpResponse->sendStatus(204);
+
+ } else {
+
+ $etag = null;
+ // If we got here, the resource didn't exist yet.
+ if (!$this->createFile($this->getRequestUri(),$body,$etag)) {
+ // For one reason or another the file was not created.
+ return;
+ }
+
+ $this->httpResponse->setHeader('Content-Length','0');
+ if ($etag) $this->httpResponse->setHeader('ETag', $etag);
+ $this->httpResponse->sendStatus(201);
+
+ }
+
+ }
+
+
+ /**
+ * WebDAV MKCOL
+ *
+ * The MKCOL method is used to create a new collection (directory) on the server
+ *
+ * @param string $uri
+ * @return void
+ */
+ protected function httpMkcol($uri) {
+
+ $requestBody = $this->httpRequest->getBody(true);
+
+ if ($requestBody) {
+
+ $contentType = $this->httpRequest->getHeader('Content-Type');
+ if (strpos($contentType,'application/xml')!==0 && strpos($contentType,'text/xml')!==0) {
+
+ // We must throw 415 for unsupported mkcol bodies
+ throw new Exception\UnsupportedMediaType('The request body for the MKCOL request must have an xml Content-Type');
+
+ }
+
+ $dom = XMLUtil::loadDOMDocument($requestBody);
+ if (XMLUtil::toClarkNotation($dom->firstChild)!=='{DAV:}mkcol') {
+
+ // We must throw 415 for unsupported mkcol bodies
+ throw new Exception\UnsupportedMediaType('The request body for the MKCOL request must be a {DAV:}mkcol request construct.');
+
+ }
+
+ $properties = array();
+ foreach($dom->firstChild->childNodes as $childNode) {
+
+ if (XMLUtil::toClarkNotation($childNode)!=='{DAV:}set') continue;
+ $properties = array_merge($properties, XMLUtil::parseProperties($childNode, $this->propertyMap));
+
+ }
+ if (!isset($properties['{DAV:}resourcetype']))
+ throw new Exception\BadRequest('The mkcol request must include a {DAV:}resourcetype property');
+
+ $resourceType = $properties['{DAV:}resourcetype']->getValue();
+ unset($properties['{DAV:}resourcetype']);
+
+ } else {
+
+ $properties = array();
+ $resourceType = array('{DAV:}collection');
+
+ }
+
+ $result = $this->createCollection($uri, $resourceType, $properties);
+
+ if (is_array($result)) {
+ $this->httpResponse->sendStatus(207);
+ $this->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
+
+ $this->httpResponse->sendBody(
+ $this->generateMultiStatus(array($result))
+ );
+
+ } else {
+ $this->httpResponse->setHeader('Content-Length','0');
+ $this->httpResponse->sendStatus(201);
+ }
+
+ }
+
+ /**
+ * WebDAV HTTP MOVE method
+ *
+ * This method moves one uri to a different uri. A lot of the actual request processing is done in getCopyMoveInfo
+ *
+ * @param string $uri
+ * @return bool
+ */
+ protected function httpMove($uri) {
+
+ $moveInfo = $this->getCopyAndMoveInfo();
+
+ // If the destination is part of the source tree, we must fail
+ if ($moveInfo['destination']==$uri)
+ throw new Exception\Forbidden('Source and destination uri are identical.');
+
+ if ($moveInfo['destinationExists']) {
+
+ if (!$this->broadcastEvent('beforeUnbind',array($moveInfo['destination']))) return false;
+ $this->tree->delete($moveInfo['destination']);
+ $this->broadcastEvent('afterUnbind',array($moveInfo['destination']));
+
+ }
+
+ if (!$this->broadcastEvent('beforeUnbind',array($uri))) return false;
+ if (!$this->broadcastEvent('beforeBind',array($moveInfo['destination']))) return false;
+ $this->tree->move($uri,$moveInfo['destination']);
+ $this->broadcastEvent('afterUnbind',array($uri));
+ $this->broadcastEvent('afterBind',array($moveInfo['destination']));
+
+ // If a resource was overwritten we should send a 204, otherwise a 201
+ $this->httpResponse->setHeader('Content-Length','0');
+ $this->httpResponse->sendStatus($moveInfo['destinationExists']?204:201);
+
+ }
+
+ /**
+ * WebDAV HTTP COPY method
+ *
+ * This method copies one uri to a different uri, and works much like the MOVE request
+ * A lot of the actual request processing is done in getCopyMoveInfo
+ *
+ * @param string $uri
+ * @return bool
+ */
+ protected function httpCopy($uri) {
+
+ $copyInfo = $this->getCopyAndMoveInfo();
+ // If the destination is part of the source tree, we must fail
+ if ($copyInfo['destination']==$uri)
+ throw new Exception\Forbidden('Source and destination uri are identical.');
+
+ if ($copyInfo['destinationExists']) {
+ if (!$this->broadcastEvent('beforeUnbind',array($copyInfo['destination']))) return false;
+ $this->tree->delete($copyInfo['destination']);
+
+ }
+ if (!$this->broadcastEvent('beforeBind',array($copyInfo['destination']))) return false;
+ $this->tree->copy($uri,$copyInfo['destination']);
+ $this->broadcastEvent('afterBind',array($copyInfo['destination']));
+
+ // If a resource was overwritten we should send a 204, otherwise a 201
+ $this->httpResponse->setHeader('Content-Length','0');
+ $this->httpResponse->sendStatus($copyInfo['destinationExists']?204:201);
+
+ }
+
+
+
+ /**
+ * HTTP REPORT method implementation
+ *
+ * Although the REPORT method is not part of the standard WebDAV spec (it's from rfc3253)
+ * It's used in a lot of extensions, so it made sense to implement it into the core.
+ *
+ * @param string $uri
+ * @return void
+ */
+ protected function httpReport($uri) {
+
+ $body = $this->httpRequest->getBody(true);
+ $dom = XMLUtil::loadDOMDocument($body);
+
+ $reportName = XMLUtil::toClarkNotation($dom->firstChild);
+
+ if ($this->broadcastEvent('report',array($reportName,$dom, $uri))) {
+
+ // If broadcastEvent returned true, it means the report was not supported
+ throw new Exception\ReportNotSupported();
+
+ }
+
+ }
+
+ // }}}
+ // {{{ HTTP/WebDAV protocol helpers
+
+ /**
+ * Returns an array with all the supported HTTP methods for a specific uri.
+ *
+ * @param string $uri
+ * @return array
+ */
+ public function getAllowedMethods($uri) {
+
+ $methods = array(
+ 'OPTIONS',
+ 'GET',
+ 'HEAD',
+ 'DELETE',
+ 'PROPFIND',
+ 'PUT',
+ 'PROPPATCH',
+ 'COPY',
+ 'MOVE',
+ 'REPORT'
+ );
+
+ // The MKCOL is only allowed on an unmapped uri
+ try {
+ $this->tree->getNodeForPath($uri);
+ } catch (Exception\NotFound $e) {
+ $methods[] = 'MKCOL';
+ }
+
+ // We're also checking if any of the plugins register any new methods
+ foreach($this->plugins as $plugin) $methods = array_merge($methods, $plugin->getHTTPMethods($uri));
+ array_unique($methods);
+
+ return $methods;
+
+ }
+
+ /**
+ * Gets the uri for the request, keeping the base uri into consideration
+ *
+ * @return string
+ */
+ public function getRequestUri() {
+
+ return $this->calculateUri($this->httpRequest->getUri());
+
+ }
+
+ /**
+ * Calculates the uri for a request, making sure that the base uri is stripped out
+ *
+ * @param string $uri
+ * @throws Exception\Forbidden A permission denied exception is thrown whenever there was an attempt to supply a uri outside of the base uri
+ * @return string
+ */
+ public function calculateUri($uri) {
+
+ if ($uri[0]!='/' && strpos($uri,'://')) {
+
+ $uri = parse_url($uri,PHP_URL_PATH);
+
+ }
+
+ $uri = str_replace('//','/',$uri);
+
+ if (strpos($uri,$this->getBaseUri())===0) {
+
+ return trim(URLUtil::decodePath(substr($uri,strlen($this->getBaseUri()))),'/');
+
+ // A special case, if the baseUri was accessed without a trailing
+ // slash, we'll accept it as well.
+ } elseif ($uri.'/' === $this->getBaseUri()) {
+
+ return '';
+
+ } else {
+
+ throw new Exception\Forbidden('Requested uri (' . $uri . ') is out of base uri (' . $this->getBaseUri() . ')');
+
+ }
+
+ }
+
+ /**
+ * Returns the HTTP depth header
+ *
+ * This method returns the contents of the HTTP depth request header. If the depth header was 'infinity' it will return the SabreForRainLoop\DAV\Server::DEPTH_INFINITY object
+ * It is possible to supply a default depth value, which is used when the depth header has invalid content, or is completely non-existent
+ *
+ * @param mixed $default
+ * @return int
+ */
+ public function getHTTPDepth($default = self::DEPTH_INFINITY) {
+
+ // If its not set, we'll grab the default
+ $depth = $this->httpRequest->getHeader('Depth');
+
+ if (is_null($depth)) return $default;
+
+ if ($depth == 'infinity') return self::DEPTH_INFINITY;
+
+
+ // If its an unknown value. we'll grab the default
+ if (!ctype_digit($depth)) return $default;
+
+ return (int)$depth;
+
+ }
+
+ /**
+ * Returns the HTTP range header
+ *
+ * This method returns null if there is no well-formed HTTP range request
+ * header or array($start, $end).
+ *
+ * The first number is the offset of the first byte in the range.
+ * The second number is the offset of the last byte in the range.
+ *
+ * If the second offset is null, it should be treated as the offset of the last byte of the entity
+ * If the first offset is null, the second offset should be used to retrieve the last x bytes of the entity
+ *
+ * @return array|null
+ */
+ public function getHTTPRange() {
+
+ $range = $this->httpRequest->getHeader('range');
+ if (is_null($range)) return null;
+
+ // Matching "Range: bytes=1234-5678: both numbers are optional
+
+ if (!preg_match('/^bytes=([0-9]*)-([0-9]*)$/i',$range,$matches)) return null;
+
+ if ($matches[1]==='' && $matches[2]==='') return null;
+
+ return array(
+ $matches[1]!==''?$matches[1]:null,
+ $matches[2]!==''?$matches[2]:null,
+ );
+
+ }
+
+ /**
+ * Returns the HTTP Prefer header information.
+ *
+ * The prefer header is defined in:
+ * http://tools.ietf.org/html/draft-snell-http-prefer-14
+ *
+ * This method will return an array with options.
+ *
+ * Currently, the following options may be returned:
+ * array(
+ * 'return-asynch' => true,
+ * 'return-minimal' => true,
+ * 'return-representation' => true,
+ * 'wait' => 30,
+ * 'strict' => true,
+ * 'lenient' => true,
+ * )
+ *
+ * This method also supports the Brief header, and will also return
+ * 'return-minimal' if the brief header was set to 't'.
+ *
+ * For the boolean options, false will be returned if the headers are not
+ * specified. For the integer options it will be 'null'.
+ *
+ * @return array
+ */
+ public function getHTTPPrefer() {
+
+ $result = array(
+ 'return-asynch' => false,
+ 'return-minimal' => false,
+ 'return-representation' => false,
+ 'wait' => null,
+ 'strict' => false,
+ 'lenient' => false,
+ );
+
+ if ($prefer = $this->httpRequest->getHeader('Prefer')) {
+
+ $parameters = array_map('trim',
+ explode(',', $prefer)
+ );
+
+ foreach($parameters as $parameter) {
+
+ // Right now our regex only supports the tokens actually
+ // specified in the draft. We may need to expand this if new
+ // tokens get registered.
+ if(!preg_match('/^(?P[a-z0-9-]+)(?:=(?P[0-9]+))?$/', $parameter, $matches)) {
+ continue;
+ }
+
+ switch($matches['token']) {
+
+ case 'return-asynch' :
+ case 'return-minimal' :
+ case 'return-representation' :
+ case 'strict' :
+ case 'lenient' :
+ $result[$matches['token']] = true;
+ break;
+ case 'wait' :
+ $result[$matches['token']] = $matches['value'];
+ break;
+
+ }
+
+ }
+
+ }
+
+ if ($this->httpRequest->getHeader('Brief')=='t') {
+ $result['return-minimal'] = true;
+ }
+
+ return $result;
+
+ }
+
+
+ /**
+ * Returns information about Copy and Move requests
+ *
+ * This function is created to help getting information about the source and the destination for the
+ * WebDAV MOVE and COPY HTTP request. It also validates a lot of information and throws proper exceptions
+ *
+ * The returned value is an array with the following keys:
+ * * destination - Destination path
+ * * destinationExists - Whether or not the destination is an existing url (and should therefore be overwritten)
+ *
+ * @return array
+ */
+ public function getCopyAndMoveInfo() {
+
+ // Collecting the relevant HTTP headers
+ if (!$this->httpRequest->getHeader('Destination')) throw new Exception\BadRequest('The destination header was not supplied');
+ $destination = $this->calculateUri($this->httpRequest->getHeader('Destination'));
+ $overwrite = $this->httpRequest->getHeader('Overwrite');
+ if (!$overwrite) $overwrite = 'T';
+ if (strtoupper($overwrite)=='T') $overwrite = true;
+ elseif (strtoupper($overwrite)=='F') $overwrite = false;
+ // We need to throw a bad request exception, if the header was invalid
+ else throw new Exception\BadRequest('The HTTP Overwrite header should be either T or F');
+
+ list($destinationDir) = URLUtil::splitPath($destination);
+
+ try {
+ $destinationParent = $this->tree->getNodeForPath($destinationDir);
+ if (!($destinationParent instanceof ICollection)) throw new Exception\UnsupportedMediaType('The destination node is not a collection');
+ } catch (Exception\NotFound $e) {
+
+ // If the destination parent node is not found, we throw a 409
+ throw new Exception\Conflict('The destination node is not found');
+ }
+
+ try {
+
+ $destinationNode = $this->tree->getNodeForPath($destination);
+
+ // If this succeeded, it means the destination already exists
+ // we'll need to throw precondition failed in case overwrite is false
+ if (!$overwrite) throw new Exception\PreconditionFailed('The destination node already exists, and the overwrite header is set to false','Overwrite');
+
+ } catch (Exception\NotFound $e) {
+
+ // Destination didn't exist, we're all good
+ $destinationNode = false;
+
+
+
+ }
+
+ // These are the three relevant properties we need to return
+ return array(
+ 'destination' => $destination,
+ 'destinationExists' => $destinationNode==true,
+ 'destinationNode' => $destinationNode,
+ );
+
+ }
+
+ /**
+ * Returns a list of properties for a path
+ *
+ * This is a simplified version getPropertiesForPath.
+ * if you aren't interested in status codes, but you just
+ * want to have a flat list of properties. Use this method.
+ *
+ * @param string $path
+ * @param array $propertyNames
+ */
+ public function getProperties($path, $propertyNames) {
+
+ $result = $this->getPropertiesForPath($path,$propertyNames,0);
+ return $result[0][200];
+
+ }
+
+ /**
+ * A kid-friendly way to fetch properties for a node's children.
+ *
+ * The returned array will be indexed by the path of the of child node.
+ * Only properties that are actually found will be returned.
+ *
+ * The parent node will not be returned.
+ *
+ * @param string $path
+ * @param array $propertyNames
+ * @return array
+ */
+ public function getPropertiesForChildren($path, $propertyNames) {
+
+ $result = array();
+ foreach($this->getPropertiesForPath($path,$propertyNames,1) as $k=>$row) {
+
+ // Skipping the parent path
+ if ($k === 0) continue;
+
+ $result[$row['href']] = $row[200];
+
+ }
+ return $result;
+
+ }
+
+ /**
+ * Returns a list of HTTP headers for a particular resource
+ *
+ * The generated http headers are based on properties provided by the
+ * resource. The method basically provides a simple mapping between
+ * DAV property and HTTP header.
+ *
+ * The headers are intended to be used for HEAD and GET requests.
+ *
+ * @param string $path
+ * @return array
+ */
+ public function getHTTPHeaders($path) {
+
+ $propertyMap = array(
+ '{DAV:}getcontenttype' => 'Content-Type',
+ '{DAV:}getcontentlength' => 'Content-Length',
+ '{DAV:}getlastmodified' => 'Last-Modified',
+ '{DAV:}getetag' => 'ETag',
+ );
+
+ $properties = $this->getProperties($path,array_keys($propertyMap));
+
+ $headers = array();
+ foreach($propertyMap as $property=>$header) {
+ if (!isset($properties[$property])) continue;
+
+ if (is_scalar($properties[$property])) {
+ $headers[$header] = $properties[$property];
+
+ // GetLastModified gets special cased
+ } elseif ($properties[$property] instanceof Property\GetLastModified) {
+ $headers[$header] = HTTP\Util::toHTTPDate($properties[$property]->getTime());
+ }
+
+ }
+
+ return $headers;
+
+ }
+
+ /**
+ * Returns a list of properties for a given path
+ *
+ * The path that should be supplied should have the baseUrl stripped out
+ * The list of properties should be supplied in Clark notation. If the list is empty
+ * 'allprops' is assumed.
+ *
+ * If a depth of 1 is requested child elements will also be returned.
+ *
+ * @param string $path
+ * @param array $propertyNames
+ * @param int $depth
+ * @return array
+ */
+ public function getPropertiesForPath($path, $propertyNames = array(), $depth = 0) {
+
+ if ($depth!=0) $depth = 1;
+
+ $path = rtrim($path,'/');
+
+ // This event allows people to intercept these requests early on in the
+ // process.
+ //
+ // We're not doing anything with the result, but this can be helpful to
+ // pre-fetch certain expensive live properties.
+ $this->broadCastEvent('beforeGetPropertiesForPath', array($path, $propertyNames, $depth));
+
+ $returnPropertyList = array();
+
+ $parentNode = $this->tree->getNodeForPath($path);
+ $nodes = array(
+ $path => $parentNode
+ );
+ if ($depth==1 && $parentNode instanceof ICollection) {
+ foreach($this->tree->getChildren($path) as $childNode)
+ $nodes[$path . '/' . $childNode->getName()] = $childNode;
+ }
+
+ // If the propertyNames array is empty, it means all properties are requested.
+ // We shouldn't actually return everything we know though, and only return a
+ // sensible list.
+ $allProperties = count($propertyNames)==0;
+
+ foreach($nodes as $myPath=>$node) {
+
+ $currentPropertyNames = $propertyNames;
+
+ $newProperties = array(
+ '200' => array(),
+ '404' => array(),
+ );
+
+ if ($allProperties) {
+ // Default list of propertyNames, when all properties were requested.
+ $currentPropertyNames = array(
+ '{DAV:}getlastmodified',
+ '{DAV:}getcontentlength',
+ '{DAV:}resourcetype',
+ '{DAV:}quota-used-bytes',
+ '{DAV:}quota-available-bytes',
+ '{DAV:}getetag',
+ '{DAV:}getcontenttype',
+ );
+ }
+
+ // If the resourceType was not part of the list, we manually add it
+ // and mark it for removal. We need to know the resourcetype in order
+ // to make certain decisions about the entry.
+ // WebDAV dictates we should add a / and the end of href's for collections
+ $removeRT = false;
+ if (!in_array('{DAV:}resourcetype',$currentPropertyNames)) {
+ $currentPropertyNames[] = '{DAV:}resourcetype';
+ $removeRT = true;
+ }
+
+ $result = $this->broadcastEvent('beforeGetProperties',array($myPath, $node, &$currentPropertyNames, &$newProperties));
+ // If this method explicitly returned false, we must ignore this
+ // node as it is inaccessible.
+ if ($result===false) continue;
+
+ if (count($currentPropertyNames) > 0) {
+
+ if ($node instanceof IProperties) {
+ $nodeProperties = $node->getProperties($currentPropertyNames);
+
+ // The getProperties method may give us too much,
+ // properties, in case the implementor was lazy.
+ //
+ // So as we loop through this list, we will only take the
+ // properties that were actually requested and discard the
+ // rest.
+ foreach($currentPropertyNames as $k=>$currentPropertyName) {
+ if (isset($nodeProperties[$currentPropertyName])) {
+ unset($currentPropertyNames[$k]);
+ $newProperties[200][$currentPropertyName] = $nodeProperties[$currentPropertyName];
+ }
+ }
+
+ }
+
+ }
+
+ foreach($currentPropertyNames as $prop) {
+
+ if (isset($newProperties[200][$prop])) continue;
+
+ switch($prop) {
+ case '{DAV:}getlastmodified' : if ($node->getLastModified()) $newProperties[200][$prop] = new Property\GetLastModified($node->getLastModified()); break;
+ case '{DAV:}getcontentlength' :
+ if ($node instanceof IFile) {
+ $size = $node->getSize();
+ if (!is_null($size)) {
+ $newProperties[200][$prop] = (int)$node->getSize();
+ }
+ }
+ break;
+ case '{DAV:}quota-used-bytes' :
+ if ($node instanceof IQuota) {
+ $quotaInfo = $node->getQuotaInfo();
+ $newProperties[200][$prop] = $quotaInfo[0];
+ }
+ break;
+ case '{DAV:}quota-available-bytes' :
+ if ($node instanceof IQuota) {
+ $quotaInfo = $node->getQuotaInfo();
+ $newProperties[200][$prop] = $quotaInfo[1];
+ }
+ break;
+ case '{DAV:}getetag' : if ($node instanceof IFile && $etag = $node->getETag()) $newProperties[200][$prop] = $etag; break;
+ case '{DAV:}getcontenttype' : if ($node instanceof IFile && $ct = $node->getContentType()) $newProperties[200][$prop] = $ct; break;
+ case '{DAV:}supported-report-set' :
+ $reports = array();
+ foreach($this->plugins as $plugin) {
+ $reports = array_merge($reports, $plugin->getSupportedReportSet($myPath));
+ }
+ $newProperties[200][$prop] = new Property\SupportedReportSet($reports);
+ break;
+ case '{DAV:}resourcetype' :
+ $newProperties[200]['{DAV:}resourcetype'] = new Property\ResourceType();
+ foreach($this->resourceTypeMapping as $className => $resourceType) {
+ if ($node instanceof $className) $newProperties[200]['{DAV:}resourcetype']->add($resourceType);
+ }
+ break;
+
+ }
+
+ // If we were unable to find the property, we will list it as 404.
+ if (!$allProperties && !isset($newProperties[200][$prop])) $newProperties[404][$prop] = null;
+
+ }
+
+ $this->broadcastEvent('afterGetProperties',array(trim($myPath,'/'),&$newProperties, $node));
+
+ $newProperties['href'] = trim($myPath,'/');
+
+ // Its is a WebDAV recommendation to add a trailing slash to collectionnames.
+ // Apple's iCal also requires a trailing slash for principals (rfc 3744), though this is non-standard.
+ if ($myPath!='' && isset($newProperties[200]['{DAV:}resourcetype'])) {
+ $rt = $newProperties[200]['{DAV:}resourcetype'];
+ if ($rt->is('{DAV:}collection') || $rt->is('{DAV:}principal')) {
+ $newProperties['href'] .='/';
+ }
+ }
+
+ // If the resourcetype property was manually added to the requested property list,
+ // we will remove it again.
+ if ($removeRT) unset($newProperties[200]['{DAV:}resourcetype']);
+
+ $returnPropertyList[] = $newProperties;
+
+ }
+
+ return $returnPropertyList;
+
+ }
+
+ /**
+ * This method is invoked by sub-systems creating a new file.
+ *
+ * Currently this is done by HTTP PUT and HTTP LOCK (in the Locks_Plugin).
+ * It was important to get this done through a centralized function,
+ * allowing plugins to intercept this using the beforeCreateFile event.
+ *
+ * This method will return true if the file was actually created
+ *
+ * @param string $uri
+ * @param resource $data
+ * @param string $etag
+ * @return bool
+ */
+ public function createFile($uri,$data, &$etag = null) {
+
+ list($dir,$name) = URLUtil::splitPath($uri);
+
+ if (!$this->broadcastEvent('beforeBind',array($uri))) return false;
+
+ $parent = $this->tree->getNodeForPath($dir);
+ if (!$parent instanceof ICollection) {
+ throw new Exception\Conflict('Files can only be created as children of collections');
+ }
+
+ if (!$this->broadcastEvent('beforeCreateFile',array($uri, &$data, $parent))) return false;
+
+ $etag = $parent->createFile($name,$data);
+ $this->tree->markDirty($dir . '/' . $name);
+
+ $this->broadcastEvent('afterBind',array($uri));
+ $this->broadcastEvent('afterCreateFile',array($uri, $parent));
+
+ return true;
+ }
+
+ /**
+ * This method is invoked by sub-systems creating a new directory.
+ *
+ * @param string $uri
+ * @return void
+ */
+ public function createDirectory($uri) {
+
+ $this->createCollection($uri,array('{DAV:}collection'),array());
+
+ }
+
+ /**
+ * Use this method to create a new collection
+ *
+ * The {DAV:}resourcetype is specified using the resourceType array.
+ * At the very least it must contain {DAV:}collection.
+ *
+ * The properties array can contain a list of additional properties.
+ *
+ * @param string $uri The new uri
+ * @param array $resourceType The resourceType(s)
+ * @param array $properties A list of properties
+ * @return array|null
+ */
+ public function createCollection($uri, array $resourceType, array $properties) {
+
+ list($parentUri,$newName) = URLUtil::splitPath($uri);
+
+ // Making sure {DAV:}collection was specified as resourceType
+ if (!in_array('{DAV:}collection', $resourceType)) {
+ throw new Exception\InvalidResourceType('The resourceType for this collection must at least include {DAV:}collection');
+ }
+
+
+ // Making sure the parent exists
+ try {
+
+ $parent = $this->tree->getNodeForPath($parentUri);
+
+ } catch (Exception\NotFound $e) {
+
+ throw new Exception\Conflict('Parent node does not exist');
+
+ }
+
+ // Making sure the parent is a collection
+ if (!$parent instanceof ICollection) {
+ throw new Exception\Conflict('Parent node is not a collection');
+ }
+
+
+
+ // Making sure the child does not already exist
+ try {
+ $parent->getChild($newName);
+
+ // If we got here.. it means there's already a node on that url, and we need to throw a 405
+ throw new Exception\MethodNotAllowed('The resource you tried to create already exists');
+
+ } catch (Exception\NotFound $e) {
+ // This is correct
+ }
+
+
+ if (!$this->broadcastEvent('beforeBind',array($uri))) return;
+
+ // There are 2 modes of operation. The standard collection
+ // creates the directory, and then updates properties
+ // the extended collection can create it directly.
+ if ($parent instanceof IExtendedCollection) {
+
+ $parent->createExtendedCollection($newName, $resourceType, $properties);
+
+ } else {
+
+ // No special resourcetypes are supported
+ if (count($resourceType)>1) {
+ throw new Exception\InvalidResourceType('The {DAV:}resourcetype you specified is not supported here.');
+ }
+
+ $parent->createDirectory($newName);
+ $rollBack = false;
+ $exception = null;
+ $errorResult = null;
+
+ if (count($properties)>0) {
+
+ try {
+
+ $errorResult = $this->updateProperties($uri, $properties);
+ if (!isset($errorResult[200])) {
+ $rollBack = true;
+ }
+
+ } catch (Exception $e) {
+
+ $rollBack = true;
+ $exception = $e;
+
+ }
+
+ }
+
+ if ($rollBack) {
+ if (!$this->broadcastEvent('beforeUnbind',array($uri))) return;
+ $this->tree->delete($uri);
+
+ // Re-throwing exception
+ if ($exception) throw $exception;
+
+ return $errorResult;
+ }
+
+ }
+ $this->tree->markDirty($parentUri);
+ $this->broadcastEvent('afterBind',array($uri));
+
+ }
+
+ /**
+ * This method updates a resource's properties
+ *
+ * The properties array must be a list of properties. Array-keys are
+ * property names in clarknotation, array-values are it's values.
+ * If a property must be deleted, the value should be null.
+ *
+ * Note that this request should either completely succeed, or
+ * completely fail.
+ *
+ * The response is an array with statuscodes for keys, which in turn
+ * contain arrays with propertynames. This response can be used
+ * to generate a multistatus body.
+ *
+ * @param string $uri
+ * @param array $properties
+ * @return array
+ */
+ public function updateProperties($uri, array $properties) {
+
+ // we'll start by grabbing the node, this will throw the appropriate
+ // exceptions if it doesn't.
+ $node = $this->tree->getNodeForPath($uri);
+
+ $result = array(
+ 200 => array(),
+ 403 => array(),
+ 424 => array(),
+ );
+ $remainingProperties = $properties;
+ $hasError = false;
+
+ // Running through all properties to make sure none of them are protected
+ if (!$hasError) foreach($properties as $propertyName => $value) {
+ if(in_array($propertyName, $this->protectedProperties)) {
+ $result[403][$propertyName] = null;
+ unset($remainingProperties[$propertyName]);
+ $hasError = true;
+ }
+ }
+
+ if (!$hasError) {
+ // Allowing plugins to take care of property updating
+ $hasError = !$this->broadcastEvent('updateProperties',array(
+ &$remainingProperties,
+ &$result,
+ $node
+ ));
+ }
+
+ // If the node is not an instance of SabreForRainLoop\DAV\IProperties, every
+ // property is 403 Forbidden
+ if (!$hasError && count($remainingProperties) && !($node instanceof IProperties)) {
+ $hasError = true;
+ foreach($properties as $propertyName=> $value) {
+ $result[403][$propertyName] = null;
+ }
+ $remainingProperties = array();
+ }
+
+ // Only if there were no errors we may attempt to update the resource
+ if (!$hasError) {
+
+ if (count($remainingProperties)>0) {
+
+ $updateResult = $node->updateProperties($remainingProperties);
+
+ if ($updateResult===true) {
+ // success
+ foreach($remainingProperties as $propertyName=>$value) {
+ $result[200][$propertyName] = null;
+ }
+
+ } elseif ($updateResult===false) {
+ // The node failed to update the properties for an
+ // unknown reason
+ foreach($remainingProperties as $propertyName=>$value) {
+ $result[403][$propertyName] = null;
+ }
+
+ } elseif (is_array($updateResult)) {
+
+ // The node has detailed update information
+ // We need to merge the results with the earlier results.
+ foreach($updateResult as $status => $props) {
+ if (is_array($props)) {
+ if (!isset($result[$status]))
+ $result[$status] = array();
+
+ $result[$status] = array_merge($result[$status], $updateResult[$status]);
+ }
+ }
+
+ } else {
+ throw new Exception('Invalid result from updateProperties');
+ }
+ $remainingProperties = array();
+ }
+
+ }
+
+ foreach($remainingProperties as $propertyName=>$value) {
+ // if there are remaining properties, it must mean
+ // there's a dependency failure
+ $result[424][$propertyName] = null;
+ }
+
+ // Removing empty array values
+ foreach($result as $status=>$props) {
+
+ if (count($props)===0) unset($result[$status]);
+
+ }
+ $result['href'] = $uri;
+ return $result;
+
+ }
+
+ /**
+ * This method checks the main HTTP preconditions.
+ *
+ * Currently these are:
+ * * If-Match
+ * * If-None-Match
+ * * If-Modified-Since
+ * * If-Unmodified-Since
+ *
+ * The method will return true if all preconditions are met
+ * The method will return false, or throw an exception if preconditions
+ * failed. If false is returned the operation should be aborted, and
+ * the appropriate HTTP response headers are already set.
+ *
+ * Normally this method will throw 412 Precondition Failed for failures
+ * related to If-None-Match, If-Match and If-Unmodified Since. It will
+ * set the status to 304 Not Modified for If-Modified_since.
+ *
+ * If the $handleAsGET argument is set to true, it will also return 304
+ * Not Modified for failure of the If-None-Match precondition. This is the
+ * desired behaviour for HTTP GET and HTTP HEAD requests.
+ *
+ * @param bool $handleAsGET
+ * @return bool
+ */
+ public function checkPreconditions($handleAsGET = false) {
+
+ $uri = $this->getRequestUri();
+ $node = null;
+ $lastMod = null;
+ $etag = null;
+
+ if ($ifMatch = $this->httpRequest->getHeader('If-Match')) {
+
+ // If-Match contains an entity tag. Only if the entity-tag
+ // matches we are allowed to make the request succeed.
+ // If the entity-tag is '*' we are only allowed to make the
+ // request succeed if a resource exists at that url.
+ try {
+ $node = $this->tree->getNodeForPath($uri);
+ } catch (Exception\NotFound $e) {
+ throw new Exception\PreconditionFailed('An If-Match header was specified and the resource did not exist','If-Match');
+ }
+
+ // Only need to check entity tags if they are not *
+ if ($ifMatch!=='*') {
+
+ // There can be multiple etags
+ $ifMatch = explode(',',$ifMatch);
+ $haveMatch = false;
+ foreach($ifMatch as $ifMatchItem) {
+
+ // Stripping any extra spaces
+ $ifMatchItem = trim($ifMatchItem,' ');
+
+ $etag = $node->getETag();
+ if ($etag===$ifMatchItem) {
+ $haveMatch = true;
+ } else {
+ // Evolution has a bug where it sometimes prepends the "
+ // with a \. This is our workaround.
+ if (str_replace('\\"','"', $ifMatchItem) === $etag) {
+ $haveMatch = true;
+ }
+ }
+
+ }
+ if (!$haveMatch) {
+ throw new Exception\PreconditionFailed('An If-Match header was specified, but none of the specified the ETags matched.','If-Match');
+ }
+ }
+ }
+
+ if ($ifNoneMatch = $this->httpRequest->getHeader('If-None-Match')) {
+
+ // The If-None-Match header contains an etag.
+ // Only if the ETag does not match the current ETag, the request will succeed
+ // The header can also contain *, in which case the request
+ // will only succeed if the entity does not exist at all.
+ $nodeExists = true;
+ if (!$node) {
+ try {
+ $node = $this->tree->getNodeForPath($uri);
+ } catch (Exception\NotFound $e) {
+ $nodeExists = false;
+ }
+ }
+ if ($nodeExists) {
+ $haveMatch = false;
+ if ($ifNoneMatch==='*') $haveMatch = true;
+ else {
+
+ // There might be multiple etags
+ $ifNoneMatch = explode(',', $ifNoneMatch);
+ $etag = $node->getETag();
+
+ foreach($ifNoneMatch as $ifNoneMatchItem) {
+
+ // Stripping any extra spaces
+ $ifNoneMatchItem = trim($ifNoneMatchItem,' ');
+
+ if ($etag===$ifNoneMatchItem) $haveMatch = true;
+
+ }
+
+ }
+
+ if ($haveMatch) {
+ if ($handleAsGET) {
+ $this->httpResponse->sendStatus(304);
+ return false;
+ } else {
+ throw new Exception\PreconditionFailed('An If-None-Match header was specified, but the ETag matched (or * was specified).','If-None-Match');
+ }
+ }
+ }
+
+ }
+
+ if (!$ifNoneMatch && ($ifModifiedSince = $this->httpRequest->getHeader('If-Modified-Since'))) {
+
+ // The If-Modified-Since header contains a date. We
+ // will only return the entity if it has been changed since
+ // that date. If it hasn't been changed, we return a 304
+ // header
+ // Note that this header only has to be checked if there was no If-None-Match header
+ // as per the HTTP spec.
+ $date = HTTP\Util::parseHTTPDate($ifModifiedSince);
+
+ if ($date) {
+ if (is_null($node)) {
+ $node = $this->tree->getNodeForPath($uri);
+ }
+ $lastMod = $node->getLastModified();
+ if ($lastMod) {
+ $lastMod = new \DateTime('@' . $lastMod);
+ if ($lastMod <= $date) {
+ $this->httpResponse->sendStatus(304);
+ $this->httpResponse->setHeader('Last-Modified', HTTP\Util::toHTTPDate($lastMod));
+ return false;
+ }
+ }
+ }
+ }
+
+ if ($ifUnmodifiedSince = $this->httpRequest->getHeader('If-Unmodified-Since')) {
+
+ // The If-Unmodified-Since will allow allow the request if the
+ // entity has not changed since the specified date.
+ $date = HTTP\Util::parseHTTPDate($ifUnmodifiedSince);
+
+ // We must only check the date if it's valid
+ if ($date) {
+ if (is_null($node)) {
+ $node = $this->tree->getNodeForPath($uri);
+ }
+ $lastMod = $node->getLastModified();
+ if ($lastMod) {
+ $lastMod = new \DateTime('@' . $lastMod);
+ if ($lastMod > $date) {
+ throw new Exception\PreconditionFailed('An If-Unmodified-Since header was specified, but the entity has been changed since the specified date.','If-Unmodified-Since');
+ }
+ }
+ }
+
+ }
+ return true;
+
+ }
+
+ // }}}
+ // {{{ XML Readers & Writers
+
+
+ /**
+ * Generates a WebDAV propfind response body based on a list of nodes.
+ *
+ * If 'strip404s' is set to true, all 404 responses will be removed.
+ *
+ * @param array $fileProperties The list with nodes
+ * @param bool strip404s
+ * @return string
+ */
+ public function generateMultiStatus(array $fileProperties, $strip404s = false) {
+
+ $dom = new \DOMDocument('1.0','utf-8');
+ //$dom->formatOutput = true;
+ $multiStatus = $dom->createElement('d:multistatus');
+ $dom->appendChild($multiStatus);
+
+ // Adding in default namespaces
+ foreach($this->xmlNamespaces as $namespace=>$prefix) {
+
+ $multiStatus->setAttribute('xmlns:' . $prefix,$namespace);
+
+ }
+
+ foreach($fileProperties as $entry) {
+
+ $href = $entry['href'];
+ unset($entry['href']);
+
+ if ($strip404s && isset($entry[404])) {
+ unset($entry[404]);
+ }
+
+ $response = new Property\Response($href,$entry);
+ $response->serialize($this,$multiStatus);
+
+ }
+
+ return $dom->saveXML();
+
+ }
+
+ /**
+ * This method parses a PropPatch request
+ *
+ * PropPatch changes the properties for a resource. This method
+ * returns a list of properties.
+ *
+ * The keys in the returned array contain the property name (e.g.: {DAV:}displayname,
+ * and the value contains the property value. If a property is to be removed the value
+ * will be null.
+ *
+ * @param string $body xml body
+ * @return array list of properties in need of updating or deletion
+ */
+ public function parsePropPatchRequest($body) {
+
+ //We'll need to change the DAV namespace declaration to something else in order to make it parsable
+ $dom = XMLUtil::loadDOMDocument($body);
+
+ $newProperties = array();
+
+ foreach($dom->firstChild->childNodes as $child) {
+
+ if ($child->nodeType !== XML_ELEMENT_NODE) continue;
+
+ $operation = XMLUtil::toClarkNotation($child);
+
+ if ($operation!=='{DAV:}set' && $operation!=='{DAV:}remove') continue;
+
+ $innerProperties = XMLUtil::parseProperties($child, $this->propertyMap);
+
+ foreach($innerProperties as $propertyName=>$propertyValue) {
+
+ if ($operation==='{DAV:}remove') {
+ $propertyValue = null;
+ }
+
+ $newProperties[$propertyName] = $propertyValue;
+
+ }
+
+ }
+
+ return $newProperties;
+
+ }
+
+ /**
+ * This method parses the PROPFIND request and returns its information
+ *
+ * This will either be a list of properties, or an empty array; in which case
+ * an {DAV:}allprop was requested.
+ *
+ * @param string $body
+ * @return array
+ */
+ public function parsePropFindRequest($body) {
+
+ // If the propfind body was empty, it means IE is requesting 'all' properties
+ if (!$body) return array();
+
+ $dom = XMLUtil::loadDOMDocument($body);
+ $elem = $dom->getElementsByTagNameNS('urn:DAV','propfind')->item(0);
+ return array_keys(XMLUtil::parseProperties($elem));
+
+ }
+
+ // }}}
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/ServerPlugin.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/ServerPlugin.php
new file mode 100644
index 0000000..83cde57
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/ServerPlugin.php
@@ -0,0 +1,90 @@
+name = $name;
+ foreach($children as $child) {
+
+ if (!($child instanceof INode)) throw new Exception('Only instances of SabreForRainLoop\DAV\INode are allowed to be passed in the children argument');
+ $this->addChild($child);
+
+ }
+
+ }
+
+ /**
+ * Adds a new childnode to this collection
+ *
+ * @param INode $child
+ * @return void
+ */
+ public function addChild(INode $child) {
+
+ $this->children[$child->getName()] = $child;
+
+ }
+
+ /**
+ * Returns the name of the collection
+ *
+ * @return string
+ */
+ public function getName() {
+
+ return $this->name;
+
+ }
+
+ /**
+ * Returns a child object, by its name.
+ *
+ * This method makes use of the getChildren method to grab all the child nodes, and compares the name.
+ * Generally its wise to override this, as this can usually be optimized
+ *
+ * This method must throw SabreForRainLoop\DAV\Exception\NotFound if the node does not
+ * exist.
+ *
+ * @param string $name
+ * @throws Exception\NotFound
+ * @return INode
+ */
+ public function getChild($name) {
+
+ if (isset($this->children[$name])) return $this->children[$name];
+ throw new Exception\NotFound('File not found: ' . $name . ' in \'' . $this->getName() . '\'');
+
+ }
+
+ /**
+ * Returns a list of children for this collection
+ *
+ * @return array
+ */
+ public function getChildren() {
+
+ return array_values($this->children);
+
+ }
+
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/SimpleFile.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/SimpleFile.php
new file mode 100644
index 0000000..d1b2d7e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/SimpleFile.php
@@ -0,0 +1,121 @@
+name = $name;
+ $this->contents = $contents;
+ $this->mimeType = $mimeType;
+
+ }
+
+ /**
+ * Returns the node name for this file.
+ *
+ * This name is used to construct the url.
+ *
+ * @return string
+ */
+ public function getName() {
+
+ return $this->name;
+
+ }
+
+ /**
+ * Returns the data
+ *
+ * This method may either return a string or a readable stream resource
+ *
+ * @return mixed
+ */
+ public function get() {
+
+ return $this->contents;
+
+ }
+
+ /**
+ * Returns the size of the file, in bytes.
+ *
+ * @return int
+ */
+ public function getSize() {
+
+ return strlen($this->contents);
+
+ }
+
+ /**
+ * Returns the ETag for a file
+ *
+ * An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change.
+ * The ETag is an arbitrary string, but MUST be surrounded by double-quotes.
+ *
+ * Return null if the ETag can not effectively be determined
+ * @return string
+ */
+ public function getETag() {
+
+ return '"' . md5($this->contents) . '"';
+
+ }
+
+ /**
+ * Returns the mime-type for a file
+ *
+ * If null is returned, we'll assume application/octet-stream
+ * @return string
+ */
+ public function getContentType() {
+
+ return $this->mimeType;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/StringUtil.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/StringUtil.php
new file mode 100644
index 0000000..4c9dcee
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/StringUtil.php
@@ -0,0 +1,91 @@
+dataDir = $dataDir;
+
+ }
+
+ /**
+ * Initialize the plugin
+ *
+ * This is called automatically be the Server class after this plugin is
+ * added with SabreForRainLoop\DAV\Server::addPlugin()
+ *
+ * @param Server $server
+ * @return void
+ */
+ public function initialize(Server $server) {
+
+ $this->server = $server;
+ $server->subscribeEvent('beforeMethod',array($this,'beforeMethod'));
+ $server->subscribeEvent('beforeCreateFile',array($this,'beforeCreateFile'));
+
+ }
+
+ /**
+ * This method is called before any HTTP method handler
+ *
+ * This method intercepts any GET, DELETE, PUT and PROPFIND calls to
+ * filenames that are known to match the 'temporary file' regex.
+ *
+ * @param string $method
+ * @param string $uri
+ * @return bool
+ */
+ public function beforeMethod($method, $uri) {
+
+ if (!$tempLocation = $this->isTempFile($uri))
+ return true;
+
+ switch($method) {
+ case 'GET' :
+ return $this->httpGet($tempLocation);
+ case 'PUT' :
+ return $this->httpPut($tempLocation);
+ case 'PROPFIND' :
+ return $this->httpPropfind($tempLocation, $uri);
+ case 'DELETE' :
+ return $this->httpDelete($tempLocation);
+ }
+ return true;
+
+ }
+
+ /**
+ * This method is invoked if some subsystem creates a new file.
+ *
+ * This is used to deal with HTTP LOCK requests which create a new
+ * file.
+ *
+ * @param string $uri
+ * @param resource $data
+ * @return bool
+ */
+ public function beforeCreateFile($uri,$data) {
+
+ if ($tempPath = $this->isTempFile($uri)) {
+
+ $hR = $this->server->httpResponse;
+ $hR->setHeader('X-Sabre-Temp','true');
+ file_put_contents($tempPath,$data);
+ return false;
+ }
+ return true;
+
+ }
+
+ /**
+ * This method will check if the url matches the temporary file pattern
+ * if it does, it will return an path based on $this->dataDir for the
+ * temporary file storage.
+ *
+ * @param string $path
+ * @return boolean|string
+ */
+ protected function isTempFile($path) {
+
+ // We're only interested in the basename.
+ list(, $tempPath) = URLUtil::splitPath($path);
+
+ foreach($this->temporaryFilePatterns as $tempFile) {
+
+ if (preg_match($tempFile,$tempPath)) {
+ return $this->getDataDir() . '/sabredav_' . md5($path) . '.tempfile';
+ }
+
+ }
+
+ return false;
+
+ }
+
+
+ /**
+ * This method handles the GET method for temporary files.
+ * If the file doesn't exist, it will return false which will kick in
+ * the regular system for the GET method.
+ *
+ * @param string $tempLocation
+ * @return bool
+ */
+ public function httpGet($tempLocation) {
+
+ if (!file_exists($tempLocation)) return true;
+
+ $hR = $this->server->httpResponse;
+ $hR->setHeader('Content-Type','application/octet-stream');
+ $hR->setHeader('Content-Length',filesize($tempLocation));
+ $hR->setHeader('X-Sabre-Temp','true');
+ $hR->sendStatus(200);
+ $hR->sendBody(fopen($tempLocation,'r'));
+ return false;
+
+ }
+
+ /**
+ * This method handles the PUT method.
+ *
+ * @param string $tempLocation
+ * @return bool
+ */
+ public function httpPut($tempLocation) {
+
+ $hR = $this->server->httpResponse;
+ $hR->setHeader('X-Sabre-Temp','true');
+
+ $newFile = !file_exists($tempLocation);
+
+ if (!$newFile && ($this->server->httpRequest->getHeader('If-None-Match'))) {
+ throw new Exception\PreconditionFailed('The resource already exists, and an If-None-Match header was supplied');
+ }
+
+ file_put_contents($tempLocation,$this->server->httpRequest->getBody());
+ $hR->sendStatus($newFile?201:200);
+ return false;
+
+ }
+
+ /**
+ * This method handles the DELETE method.
+ *
+ * If the file didn't exist, it will return false, which will make the
+ * standard HTTP DELETE handler kick in.
+ *
+ * @param string $tempLocation
+ * @return bool
+ */
+ public function httpDelete($tempLocation) {
+
+ if (!file_exists($tempLocation)) return true;
+
+ unlink($tempLocation);
+ $hR = $this->server->httpResponse;
+ $hR->setHeader('X-Sabre-Temp','true');
+ $hR->sendStatus(204);
+ return false;
+
+ }
+
+ /**
+ * This method handles the PROPFIND method.
+ *
+ * It's a very lazy method, it won't bother checking the request body
+ * for which properties were requested, and just sends back a default
+ * set of properties.
+ *
+ * @param string $tempLocation
+ * @param string $uri
+ * @return bool
+ */
+ public function httpPropfind($tempLocation, $uri) {
+
+ if (!file_exists($tempLocation)) return true;
+
+ $hR = $this->server->httpResponse;
+ $hR->setHeader('X-Sabre-Temp','true');
+ $hR->sendStatus(207);
+ $hR->setHeader('Content-Type','application/xml; charset=utf-8');
+
+ $this->server->parsePropFindRequest($this->server->httpRequest->getBody(true));
+
+ $properties = array(
+ 'href' => $uri,
+ 200 => array(
+ '{DAV:}getlastmodified' => new Property\GetLastModified(filemtime($tempLocation)),
+ '{DAV:}getcontentlength' => filesize($tempLocation),
+ '{DAV:}resourcetype' => new Property\ResourceType(null),
+ '{'.Server::NS_SABREDAV.'}tempFile' => true,
+
+ ),
+ );
+
+ $data = $this->server->generateMultiStatus(array($properties));
+ $hR->sendBody($data);
+ return false;
+
+ }
+
+
+ /**
+ * This method returns the directory where the temporary files should be stored.
+ *
+ * @return string
+ */
+ protected function getDataDir()
+ {
+ return $this->dataDir;
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Tree.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Tree.php
new file mode 100644
index 0000000..49fa99d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Tree.php
@@ -0,0 +1,193 @@
+getNodeForPath($path);
+ return true;
+
+ } catch (Exception\NotFound $e) {
+
+ return false;
+
+ }
+
+ }
+
+ /**
+ * Copies a file from path to another
+ *
+ * @param string $sourcePath The source location
+ * @param string $destinationPath The full destination path
+ * @return void
+ */
+ public function copy($sourcePath, $destinationPath) {
+
+ $sourceNode = $this->getNodeForPath($sourcePath);
+
+ // grab the dirname and basename components
+ list($destinationDir, $destinationName) = URLUtil::splitPath($destinationPath);
+
+ $destinationParent = $this->getNodeForPath($destinationDir);
+ $this->copyNode($sourceNode,$destinationParent,$destinationName);
+
+ $this->markDirty($destinationDir);
+
+ }
+
+ /**
+ * Moves a file from one location to another
+ *
+ * @param string $sourcePath The path to the file which should be moved
+ * @param string $destinationPath The full destination path, so not just the destination parent node
+ * @return int
+ */
+ public function move($sourcePath, $destinationPath) {
+
+ list($sourceDir, $sourceName) = URLUtil::splitPath($sourcePath);
+ list($destinationDir, $destinationName) = URLUtil::splitPath($destinationPath);
+
+ if ($sourceDir===$destinationDir) {
+ $renameable = $this->getNodeForPath($sourcePath);
+ $renameable->setName($destinationName);
+ } else {
+ $this->copy($sourcePath,$destinationPath);
+ $this->getNodeForPath($sourcePath)->delete();
+ }
+ $this->markDirty($sourceDir);
+ $this->markDirty($destinationDir);
+
+ }
+
+ /**
+ * Deletes a node from the tree
+ *
+ * @param string $path
+ * @return void
+ */
+ public function delete($path) {
+
+ $node = $this->getNodeForPath($path);
+ $node->delete();
+
+ list($parent) = URLUtil::splitPath($path);
+ $this->markDirty($parent);
+
+ }
+
+ /**
+ * Returns a list of childnodes for a given path.
+ *
+ * @param string $path
+ * @return array
+ */
+ public function getChildren($path) {
+
+ $node = $this->getNodeForPath($path);
+ return $node->getChildren();
+
+ }
+
+ /**
+ * This method is called with every tree update
+ *
+ * Examples of tree updates are:
+ * * node deletions
+ * * node creations
+ * * copy
+ * * move
+ * * renaming nodes
+ *
+ * If Tree classes implement a form of caching, this will allow
+ * them to make sure caches will be expired.
+ *
+ * If a path is passed, it is assumed that the entire subtree is dirty
+ *
+ * @param string $path
+ * @return void
+ */
+ public function markDirty($path) {
+
+
+ }
+
+ /**
+ * copyNode
+ *
+ * @param INode $source
+ * @param ICollection $destinationParent
+ * @param string $destinationName
+ * @return void
+ */
+ protected function copyNode(INode $source,ICollection $destinationParent,$destinationName = null) {
+
+ if (!$destinationName) $destinationName = $source->getName();
+
+ if ($source instanceof IFile) {
+
+ $data = $source->get();
+
+ // If the body was a string, we need to convert it to a stream
+ if (is_string($data)) {
+ $stream = fopen('php://temp','r+');
+ fwrite($stream,$data);
+ rewind($stream);
+ $data = $stream;
+ }
+ $destinationParent->createFile($destinationName,$data);
+ $destination = $destinationParent->getChild($destinationName);
+
+ } elseif ($source instanceof ICollection) {
+
+ $destinationParent->createDirectory($destinationName);
+
+ $destination = $destinationParent->getChild($destinationName);
+ foreach($source->getChildren() as $child) {
+
+ $this->copyNode($child,$destination);
+
+ }
+
+ }
+ if ($source instanceof IProperties && $destination instanceof IProperties) {
+
+ $props = $source->getProperties(array());
+ $destination->updateProperties($props);
+
+ }
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Tree/Filesystem.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Tree/Filesystem.php
new file mode 100644
index 0000000..7546c05
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/Tree/Filesystem.php
@@ -0,0 +1,133 @@
+basePath = $basePath;
+
+ }
+
+ /**
+ * Returns a new node for the given path
+ *
+ * @param string $path
+ * @return DAV\FS\Node
+ */
+ public function getNodeForPath($path) {
+
+ $realPath = $this->getRealPath($path);
+ if (!file_exists($realPath)) {
+ throw new DAV\Exception\NotFound('File at location ' . $realPath . ' not found');
+ }
+ if (is_dir($realPath)) {
+ return new DAV\FS\Directory($realPath);
+ } else {
+ return new DAV\FS\File($realPath);
+ }
+
+ }
+
+ /**
+ * Returns the real filesystem path for a webdav url.
+ *
+ * @param string $publicPath
+ * @return string
+ */
+ protected function getRealPath($publicPath) {
+
+ return rtrim($this->basePath,'/') . '/' . trim($publicPath,'/');
+
+ }
+
+ /**
+ * Copies a file or directory.
+ *
+ * This method must work recursively and delete the destination
+ * if it exists
+ *
+ * @param string $source
+ * @param string $destination
+ * @return void
+ */
+ public function copy($source,$destination) {
+
+ $source = $this->getRealPath($source);
+ $destination = $this->getRealPath($destination);
+ $this->realCopy($source,$destination);
+
+ }
+
+ /**
+ * Used by self::copy
+ *
+ * @param string $source
+ * @param string $destination
+ * @return void
+ */
+ protected function realCopy($source,$destination) {
+
+ if (is_file($source)) {
+ copy($source,$destination);
+ } else {
+ mkdir($destination);
+ foreach(scandir($source) as $subnode) {
+
+ if ($subnode=='.' || $subnode=='..') continue;
+ $this->realCopy($source.'/'.$subnode,$destination.'/'.$subnode);
+
+ }
+ }
+
+ }
+
+ /**
+ * Moves a file or directory recursively.
+ *
+ * If the destination exists, delete it first.
+ *
+ * @param string $source
+ * @param string $destination
+ * @return void
+ */
+ public function move($source,$destination) {
+
+ $source = $this->getRealPath($source);
+ $destination = $this->getRealPath($destination);
+ rename($source,$destination);
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/URLUtil.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/URLUtil.php
new file mode 100644
index 0000000..65f4d9b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAV/URLUtil.php
@@ -0,0 +1,121 @@
+
+ * will be returned as:
+ * {http://www.example.org}myelem
+ *
+ * This format is used throughout the SabreDAV sourcecode.
+ * Elements encoded with the urn:DAV namespace will
+ * be returned as if they were in the DAV: namespace. This is to avoid
+ * compatibility problems.
+ *
+ * This function will return null if a nodetype other than an Element is passed.
+ *
+ * @param \DOMNode $dom
+ * @return string
+ */
+ static function toClarkNotation(\DOMNode $dom) {
+
+ if ($dom->nodeType !== XML_ELEMENT_NODE) return null;
+
+ // Mapping back to the real namespace, in case it was dav
+ if ($dom->namespaceURI=='urn:DAV') $ns = 'DAV:'; else $ns = $dom->namespaceURI;
+
+ // Mapping to clark notation
+ return '{' . $ns . '}' . $dom->localName;
+
+ }
+
+ /**
+ * Parses a clark-notation string, and returns the namespace and element
+ * name components.
+ *
+ * If the string was invalid, it will throw an InvalidArgumentException.
+ *
+ * @param string $str
+ * @throws InvalidArgumentException
+ * @return array
+ */
+ static function parseClarkNotation($str) {
+
+ if (!preg_match('/^{([^}]*)}(.*)$/',$str,$matches)) {
+ throw new \InvalidArgumentException('\'' . $str . '\' is not a valid clark-notation formatted string');
+ }
+
+ return array(
+ $matches[1],
+ $matches[2]
+ );
+
+ }
+
+ /**
+ * This method takes an XML document (as string) and converts all instances of the
+ * DAV: namespace to urn:DAV
+ *
+ * This is unfortunately needed, because the DAV: namespace violates the xml namespaces
+ * spec, and causes the DOM to throw errors
+ *
+ * @param string $xmlDocument
+ * @return array|string|null
+ */
+ static function convertDAVNamespace($xmlDocument) {
+
+ // This is used to map the DAV: namespace to urn:DAV. This is needed, because the DAV:
+ // namespace is actually a violation of the XML namespaces specification, and will cause errors
+ return preg_replace("/xmlns(:[A-Za-z0-9_]*)?=(\"|\')DAV:(\\2)/","xmlns\\1=\\2urn:DAV\\2",$xmlDocument);
+
+ }
+
+ /**
+ * This method provides a generic way to load a DOMDocument for WebDAV use.
+ *
+ * This method throws a SabreForRainLoop\DAV\Exception\BadRequest exception for any xml errors.
+ * It does not preserve whitespace, and it converts the DAV: namespace to urn:DAV.
+ *
+ * @param string $xml
+ * @throws SabreForRainLoop\DAV\Exception\BadRequest
+ * @return DOMDocument
+ */
+ static function loadDOMDocument($xml) {
+
+ if (empty($xml))
+ throw new Exception\BadRequest('Empty XML document sent');
+
+ // The BitKinex client sends xml documents as UTF-16. PHP 5.3.1 (and presumably lower)
+ // does not support this, so we must intercept this and convert to UTF-8.
+ if (substr($xml,0,12) === "\x3c\x00\x3f\x00\x78\x00\x6d\x00\x6c\x00\x20\x00") {
+
+ // Note: the preceeding byte sequence is "]*)encoding="UTF-16"([^>]*)>|u','',$xml);
+
+ }
+
+ // Retaining old error setting
+ $oldErrorSetting = libxml_use_internal_errors(true);
+
+ // Clearing any previous errors
+ libxml_clear_errors();
+
+ $dom = new \DOMDocument();
+
+ // We don't generally care about any whitespace
+ $dom->preserveWhiteSpace = false;
+
+ $dom->loadXML(self::convertDAVNamespace($xml),LIBXML_NOWARNING | LIBXML_NOERROR);
+
+ if ($error = libxml_get_last_error()) {
+ libxml_clear_errors();
+ throw new Exception\BadRequest('The request body had an invalid XML body. (message: ' . $error->message . ', errorcode: ' . $error->code . ', line: ' . $error->line . ')');
+ }
+
+ // Restoring old mechanism for error handling
+ if ($oldErrorSetting===false) libxml_use_internal_errors(false);
+
+ return $dom;
+
+ }
+
+ /**
+ * Parses all WebDAV properties out of a DOM Element
+ *
+ * Generally WebDAV properties are enclosed in {DAV:}prop elements. This
+ * method helps by going through all these and pulling out the actual
+ * propertynames, making them array keys and making the property values,
+ * well.. the array values.
+ *
+ * If no value was given (self-closing element) null will be used as the
+ * value. This is used in for example PROPFIND requests.
+ *
+ * Complex values are supported through the propertyMap argument. The
+ * propertyMap should have the clark-notation properties as it's keys, and
+ * classnames as values.
+ *
+ * When any of these properties are found, the unserialize() method will be
+ * (statically) called. The result of this method is used as the value.
+ *
+ * @param \DOMElement $parentNode
+ * @param array $propertyMap
+ * @return array
+ */
+ static function parseProperties(\DOMElement $parentNode, array $propertyMap = array()) {
+
+ $propList = array();
+ foreach($parentNode->childNodes as $propNode) {
+
+ if (self::toClarkNotation($propNode)!=='{DAV:}prop') continue;
+
+ foreach($propNode->childNodes as $propNodeData) {
+
+ /* If there are no elements in here, we actually get 1 text node, this special case is dedicated to netdrive */
+ if ($propNodeData->nodeType != XML_ELEMENT_NODE) continue;
+
+ $propertyName = self::toClarkNotation($propNodeData);
+ if (isset($propertyMap[$propertyName])) {
+ $propList[$propertyName] = call_user_func(array($propertyMap[$propertyName],'unserialize'),$propNodeData);
+ } else {
+ $propList[$propertyName] = $propNodeData->textContent;
+ }
+ }
+
+
+ }
+ return $propList;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/AbstractPrincipalCollection.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/AbstractPrincipalCollection.php
new file mode 100644
index 0000000..342796f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/AbstractPrincipalCollection.php
@@ -0,0 +1,155 @@
+principalPrefix = $principalPrefix;
+ $this->principalBackend = $principalBackend;
+
+ }
+
+ /**
+ * This method returns a node for a principal.
+ *
+ * The passed array contains principal information, and is guaranteed to
+ * at least contain a uri item. Other properties may or may not be
+ * supplied by the authentication backend.
+ *
+ * @param array $principalInfo
+ * @return IPrincipal
+ */
+ abstract function getChildForPrincipal(array $principalInfo);
+
+ /**
+ * Returns the name of this collection.
+ *
+ * @return string
+ */
+ public function getName() {
+
+ list(,$name) = DAV\URLUtil::splitPath($this->principalPrefix);
+ return $name;
+
+ }
+
+ /**
+ * Return the list of users
+ *
+ * @return array
+ */
+ public function getChildren() {
+
+ if ($this->disableListing)
+ throw new DAV\Exception\MethodNotAllowed('Listing members of this collection is disabled');
+
+ $children = array();
+ foreach($this->principalBackend->getPrincipalsByPrefix($this->principalPrefix) as $principalInfo) {
+
+ $children[] = $this->getChildForPrincipal($principalInfo);
+
+
+ }
+ return $children;
+
+ }
+
+ /**
+ * Returns a child object, by its name.
+ *
+ * @param string $name
+ * @throws DAV\Exception\NotFound
+ * @return IPrincipal
+ */
+ public function getChild($name) {
+
+ $principalInfo = $this->principalBackend->getPrincipalByPath($this->principalPrefix . '/' . $name);
+ if (!$principalInfo) throw new DAV\Exception\NotFound('Principal with name ' . $name . ' not found');
+ return $this->getChildForPrincipal($principalInfo);
+
+ }
+
+ /**
+ * This method is used to search for principals matching a set of
+ * properties.
+ *
+ * This search is specifically used by RFC3744's principal-property-search
+ * REPORT. You should at least allow searching on
+ * http://sabredav.org/ns}email-address.
+ *
+ * The actual search should be a unicode-non-case-sensitive search. The
+ * keys in searchProperties are the WebDAV property names, while the values
+ * are the property values to search on.
+ *
+ * If multiple properties are being searched on, the search should be
+ * AND'ed.
+ *
+ * This method should simply return a list of 'child names', which may be
+ * used to call $this->getChild in the future.
+ *
+ * @param array $searchProperties
+ * @return array
+ */
+ public function searchPrincipals(array $searchProperties) {
+
+ $result = $this->principalBackend->searchPrincipals($this->principalPrefix, $searchProperties);
+ $r = array();
+
+ foreach($result as $row) {
+ list(, $r[]) = DAV\URLUtil::splitPath($row);
+ }
+
+ return $r;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Exception/AceConflict.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Exception/AceConflict.php
new file mode 100644
index 0000000..cc91a95
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Exception/AceConflict.php
@@ -0,0 +1,35 @@
+ownerDocument;
+
+ $np = $doc->createElementNS('DAV:','d:no-ace-conflict');
+ $errorNode->appendChild($np);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Exception/NeedPrivileges.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Exception/NeedPrivileges.php
new file mode 100644
index 0000000..9b4db9b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Exception/NeedPrivileges.php
@@ -0,0 +1,83 @@
+uri = $uri;
+ $this->privileges = $privileges;
+
+ parent::__construct('User did not have the required privileges (' . implode(',', $privileges) . ') for path "' . $uri . '"');
+
+ }
+
+ /**
+ * Adds in extra information in the xml response.
+ *
+ * This method adds the {DAV:}need-privileges element as defined in rfc3744
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $errorNode
+ * @return void
+ */
+ public function serialize(DAV\Server $server,\DOMElement $errorNode) {
+
+ $doc = $errorNode->ownerDocument;
+
+ $np = $doc->createElementNS('DAV:','d:need-privileges');
+ $errorNode->appendChild($np);
+
+ foreach($this->privileges as $privilege) {
+
+ $resource = $doc->createElementNS('DAV:','d:resource');
+ $np->appendChild($resource);
+
+ $resource->appendChild($doc->createElementNS('DAV:','d:href',$server->getBaseUri() . $this->uri));
+
+ $priv = $doc->createElementNS('DAV:','d:privilege');
+ $resource->appendChild($priv);
+
+ preg_match('/^{([^}]*)}(.*)$/',$privilege,$privilegeParts);
+ $priv->appendChild($doc->createElementNS($privilegeParts[1],'d:' . $privilegeParts[2]));
+
+
+ }
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Exception/NoAbstract.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Exception/NoAbstract.php
new file mode 100644
index 0000000..0f82106
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Exception/NoAbstract.php
@@ -0,0 +1,35 @@
+ownerDocument;
+
+ $np = $doc->createElementNS('DAV:','d:no-abstract');
+ $errorNode->appendChild($np);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Exception/NotRecognizedPrincipal.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Exception/NotRecognizedPrincipal.php
new file mode 100644
index 0000000..9e95cc5
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Exception/NotRecognizedPrincipal.php
@@ -0,0 +1,35 @@
+ownerDocument;
+
+ $np = $doc->createElementNS('DAV:','d:recognized-principal');
+ $errorNode->appendChild($np);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Exception/NotSupportedPrivilege.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Exception/NotSupportedPrivilege.php
new file mode 100644
index 0000000..461ebe3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Exception/NotSupportedPrivilege.php
@@ -0,0 +1,35 @@
+ownerDocument;
+
+ $np = $doc->createElementNS('DAV:','d:not-supported-privilege');
+ $errorNode->appendChild($np);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/IACL.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/IACL.php
new file mode 100644
index 0000000..31971d5
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/IACL.php
@@ -0,0 +1,74 @@
+getChild in the future.
+ *
+ * @param array $searchProperties
+ * @return array
+ */
+ function searchPrincipals(array $searchProperties);
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Plugin.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Plugin.php
new file mode 100644
index 0000000..89269b4
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Plugin.php
@@ -0,0 +1,1402 @@
+ 'Display name',
+ '{http://sabredav.org/ns}email-address' => 'Email address',
+ );
+
+ /**
+ * Any principal uri's added here, will automatically be added to the list
+ * of ACL's. They will effectively receive {DAV:}all privileges, as a
+ * protected privilege.
+ *
+ * @var array
+ */
+ public $adminPrincipals = array();
+
+ /**
+ * Returns a list of features added by this plugin.
+ *
+ * This list is used in the response of a HTTP OPTIONS request.
+ *
+ * @return array
+ */
+ public function getFeatures() {
+
+ return array('access-control', 'calendarserver-principal-property-search');
+
+ }
+
+ /**
+ * Returns a list of available methods for a given url
+ *
+ * @param string $uri
+ * @return array
+ */
+ public function getMethods($uri) {
+
+ return array('ACL');
+
+ }
+
+ /**
+ * Returns a plugin name.
+ *
+ * Using this name other plugins will be able to access other plugins
+ * using SabreForRainLoop\DAV\Server::getPlugin
+ *
+ * @return string
+ */
+ public function getPluginName() {
+
+ return 'acl';
+
+ }
+
+ /**
+ * Returns a list of reports this plugin supports.
+ *
+ * This will be used in the {DAV:}supported-report-set property.
+ * Note that you still need to subscribe to the 'report' event to actually
+ * implement them
+ *
+ * @param string $uri
+ * @return array
+ */
+ public function getSupportedReportSet($uri) {
+
+ return array(
+ '{DAV:}expand-property',
+ '{DAV:}principal-property-search',
+ '{DAV:}principal-search-property-set',
+ );
+
+ }
+
+
+ /**
+ * Checks if the current user has the specified privilege(s).
+ *
+ * You can specify a single privilege, or a list of privileges.
+ * This method will throw an exception if the privilege is not available
+ * and return true otherwise.
+ *
+ * @param string $uri
+ * @param array|string $privileges
+ * @param int $recursion
+ * @param bool $throwExceptions if set to false, this method won't throw exceptions.
+ * @throws SabreForRainLoop\DAVACL\Exception\NeedPrivileges
+ * @return bool
+ */
+ public function checkPrivileges($uri, $privileges, $recursion = self::R_PARENT, $throwExceptions = true) {
+
+ if (!is_array($privileges)) $privileges = array($privileges);
+
+ $acl = $this->getCurrentUserPrivilegeSet($uri);
+
+ if (is_null($acl)) {
+ if ($this->allowAccessToNodesWithoutACL) {
+ return true;
+ } else {
+ if ($throwExceptions)
+ throw new Exception\NeedPrivileges($uri,$privileges);
+ else
+ return false;
+
+ }
+ }
+
+ $failed = array();
+ foreach($privileges as $priv) {
+
+ if (!in_array($priv, $acl)) {
+ $failed[] = $priv;
+ }
+
+ }
+
+ if ($failed) {
+ if ($throwExceptions)
+ throw new Exception\NeedPrivileges($uri,$failed);
+ else
+ return false;
+ }
+ return true;
+
+ }
+
+ /**
+ * Returns the standard users' principal.
+ *
+ * This is one authorative principal url for the current user.
+ * This method will return null if the user wasn't logged in.
+ *
+ * @return string|null
+ */
+ public function getCurrentUserPrincipal() {
+
+ $authPlugin = $this->server->getPlugin('auth');
+ if (is_null($authPlugin)) return null;
+ /** @var $authPlugin SabreForRainLoop\DAV\Auth\Plugin */
+
+ $userName = $authPlugin->getCurrentUser();
+ if (!$userName) return null;
+
+ return $this->defaultUsernamePath . '/' . $userName;
+
+ }
+
+
+ /**
+ * Returns a list of principals that's associated to the current
+ * user, either directly or through group membership.
+ *
+ * @return array
+ */
+ public function getCurrentUserPrincipals() {
+
+ $currentUser = $this->getCurrentUserPrincipal();
+
+ if (is_null($currentUser)) return array();
+
+ return array_merge(
+ array($currentUser),
+ $this->getPrincipalMembership($currentUser)
+ );
+
+ }
+
+ /**
+ * This array holds a cache for all the principals that are associated with
+ * a single principal.
+ *
+ * @var array
+ */
+ protected $principalMembershipCache = array();
+
+
+ /**
+ * Returns all the principal groups the specified principal is a member of.
+ *
+ * @param string $principal
+ * @return array
+ */
+ public function getPrincipalMembership($mainPrincipal) {
+
+ // First check our cache
+ if (isset($this->principalMembershipCache[$mainPrincipal])) {
+ return $this->principalMembershipCache[$mainPrincipal];
+ }
+
+ $check = array($mainPrincipal);
+ $principals = array();
+
+ while(count($check)) {
+
+ $principal = array_shift($check);
+
+ $node = $this->server->tree->getNodeForPath($principal);
+ if ($node instanceof IPrincipal) {
+ foreach($node->getGroupMembership() as $groupMember) {
+
+ if (!in_array($groupMember, $principals)) {
+
+ $check[] = $groupMember;
+ $principals[] = $groupMember;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ // Store the result in the cache
+ $this->principalMembershipCache[$mainPrincipal] = $principals;
+
+ return $principals;
+
+ }
+
+ /**
+ * Returns the supported privilege structure for this ACL plugin.
+ *
+ * See RFC3744 for more details. Currently we default on a simple,
+ * standard structure.
+ *
+ * You can either get the list of privileges by a uri (path) or by
+ * specifying a Node.
+ *
+ * @param string|DAV\INode $node
+ * @return array
+ */
+ public function getSupportedPrivilegeSet($node) {
+
+ if (is_string($node)) {
+ $node = $this->server->tree->getNodeForPath($node);
+ }
+
+ if ($node instanceof IACL) {
+ $result = $node->getSupportedPrivilegeSet();
+
+ if ($result)
+ return $result;
+ }
+
+ return self::getDefaultSupportedPrivilegeSet();
+
+ }
+
+ /**
+ * Returns a fairly standard set of privileges, which may be useful for
+ * other systems to use as a basis.
+ *
+ * @return array
+ */
+ static function getDefaultSupportedPrivilegeSet() {
+
+ return array(
+ 'privilege' => '{DAV:}all',
+ 'abstract' => true,
+ 'aggregates' => array(
+ array(
+ 'privilege' => '{DAV:}read',
+ 'aggregates' => array(
+ array(
+ 'privilege' => '{DAV:}read-acl',
+ 'abstract' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}read-current-user-privilege-set',
+ 'abstract' => true,
+ ),
+ ),
+ ), // {DAV:}read
+ array(
+ 'privilege' => '{DAV:}write',
+ 'aggregates' => array(
+ array(
+ 'privilege' => '{DAV:}write-acl',
+ 'abstract' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}write-properties',
+ 'abstract' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}write-content',
+ 'abstract' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}bind',
+ 'abstract' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}unbind',
+ 'abstract' => true,
+ ),
+ array(
+ 'privilege' => '{DAV:}unlock',
+ 'abstract' => true,
+ ),
+ ),
+ ), // {DAV:}write
+ ),
+ ); // {DAV:}all
+
+ }
+
+ /**
+ * Returns the supported privilege set as a flat list
+ *
+ * This is much easier to parse.
+ *
+ * The returned list will be index by privilege name.
+ * The value is a struct containing the following properties:
+ * - aggregates
+ * - abstract
+ * - concrete
+ *
+ * @param string|DAV\INode $node
+ * @return array
+ */
+ final public function getFlatPrivilegeSet($node) {
+
+ $privs = $this->getSupportedPrivilegeSet($node);
+
+ $flat = array();
+ $this->getFPSTraverse($privs, null, $flat);
+
+ return $flat;
+
+ }
+
+ /**
+ * Traverses the privilege set tree for reordering
+ *
+ * This function is solely used by getFlatPrivilegeSet, and would have been
+ * a closure if it wasn't for the fact I need to support PHP 5.2.
+ *
+ * @param array $priv
+ * @param $concrete
+ * @param array $flat
+ * @return void
+ */
+ final private function getFPSTraverse($priv, $concrete, &$flat) {
+
+ $myPriv = array(
+ 'privilege' => $priv['privilege'],
+ 'abstract' => isset($priv['abstract']) && $priv['abstract'],
+ 'aggregates' => array(),
+ 'concrete' => isset($priv['abstract']) && $priv['abstract']?$concrete:$priv['privilege'],
+ );
+
+ if (isset($priv['aggregates']))
+ foreach($priv['aggregates'] as $subPriv) $myPriv['aggregates'][] = $subPriv['privilege'];
+
+ $flat[$priv['privilege']] = $myPriv;
+
+ if (isset($priv['aggregates'])) {
+
+ foreach($priv['aggregates'] as $subPriv) {
+
+ $this->getFPSTraverse($subPriv, $myPriv['concrete'], $flat);
+
+ }
+
+ }
+
+ }
+
+ /**
+ * Returns the full ACL list.
+ *
+ * Either a uri or a DAV\INode may be passed.
+ *
+ * null will be returned if the node doesn't support ACLs.
+ *
+ * @param string|DAV\INode $node
+ * @return array
+ */
+ public function getACL($node) {
+
+ if (is_string($node)) {
+ $node = $this->server->tree->getNodeForPath($node);
+ }
+ if (!$node instanceof IACL) {
+ return null;
+ }
+ $acl = $node->getACL();
+ foreach($this->adminPrincipals as $adminPrincipal) {
+ $acl[] = array(
+ 'principal' => $adminPrincipal,
+ 'privilege' => '{DAV:}all',
+ 'protected' => true,
+ );
+ }
+ return $acl;
+
+ }
+
+ /**
+ * Returns a list of privileges the current user has
+ * on a particular node.
+ *
+ * Either a uri or a DAV\INode may be passed.
+ *
+ * null will be returned if the node doesn't support ACLs.
+ *
+ * @param string|DAV\INode $node
+ * @return array
+ */
+ public function getCurrentUserPrivilegeSet($node) {
+
+ if (is_string($node)) {
+ $node = $this->server->tree->getNodeForPath($node);
+ }
+
+ $acl = $this->getACL($node);
+
+ if (is_null($acl)) return null;
+
+ $principals = $this->getCurrentUserPrincipals();
+
+ $collected = array();
+
+ foreach($acl as $ace) {
+
+ $principal = $ace['principal'];
+
+ switch($principal) {
+
+ case '{DAV:}owner' :
+ $owner = $node->getOwner();
+ if ($owner && in_array($owner, $principals)) {
+ $collected[] = $ace;
+ }
+ break;
+
+
+ // 'all' matches for every user
+ case '{DAV:}all' :
+
+ // 'authenticated' matched for every user that's logged in.
+ // Since it's not possible to use ACL while not being logged
+ // in, this is also always true.
+ case '{DAV:}authenticated' :
+ $collected[] = $ace;
+ break;
+
+ // 'unauthenticated' can never occur either, so we simply
+ // ignore these.
+ case '{DAV:}unauthenticated' :
+ break;
+
+ default :
+ if (in_array($ace['principal'], $principals)) {
+ $collected[] = $ace;
+ }
+ break;
+
+ }
+
+
+ }
+
+ // Now we deduct all aggregated privileges.
+ $flat = $this->getFlatPrivilegeSet($node);
+
+ $collected2 = array();
+ while(count($collected)) {
+
+ $current = array_pop($collected);
+ $collected2[] = $current['privilege'];
+
+ foreach($flat[$current['privilege']]['aggregates'] as $subPriv) {
+ $collected2[] = $subPriv;
+ $collected[] = $flat[$subPriv];
+ }
+
+ }
+
+ return array_values(array_unique($collected2));
+
+ }
+
+ /**
+ * Principal property search
+ *
+ * This method can search for principals matching certain values in
+ * properties.
+ *
+ * This method will return a list of properties for the matched properties.
+ *
+ * @param array $searchProperties The properties to search on. This is a
+ * key-value list. The keys are property
+ * names, and the values the strings to
+ * match them on.
+ * @param array $requestedProperties This is the list of properties to
+ * return for every match.
+ * @param string $collectionUri The principal collection to search on.
+ * If this is ommitted, the standard
+ * principal collection-set will be used.
+ * @return array This method returns an array structure similar to
+ * SabreForRainLoop\DAV\Server::getPropertiesForPath. Returned
+ * properties are index by a HTTP status code.
+ *
+ */
+ public function principalSearch(array $searchProperties, array $requestedProperties, $collectionUri = null) {
+
+ if (!is_null($collectionUri)) {
+ $uris = array($collectionUri);
+ } else {
+ $uris = $this->principalCollectionSet;
+ }
+
+ $lookupResults = array();
+ foreach($uris as $uri) {
+
+ $principalCollection = $this->server->tree->getNodeForPath($uri);
+ if (!$principalCollection instanceof IPrincipalCollection) {
+ // Not a principal collection, we're simply going to ignore
+ // this.
+ continue;
+ }
+
+ $results = $principalCollection->searchPrincipals($searchProperties);
+ foreach($results as $result) {
+ $lookupResults[] = rtrim($uri,'/') . '/' . $result;
+ }
+
+ }
+
+ $matches = array();
+
+ foreach($lookupResults as $lookupResult) {
+
+ list($matches[]) = $this->server->getPropertiesForPath($lookupResult, $requestedProperties, 0);
+
+ }
+
+ return $matches;
+
+ }
+
+ /**
+ * Sets up the plugin
+ *
+ * This method is automatically called by the server class.
+ *
+ * @param DAV\Server $server
+ * @return void
+ */
+ public function initialize(DAV\Server $server) {
+
+ $this->server = $server;
+ $server->subscribeEvent('beforeGetProperties',array($this,'beforeGetProperties'));
+
+ $server->subscribeEvent('beforeMethod', array($this,'beforeMethod'),20);
+ $server->subscribeEvent('beforeBind', array($this,'beforeBind'),20);
+ $server->subscribeEvent('beforeUnbind', array($this,'beforeUnbind'),20);
+ $server->subscribeEvent('updateProperties',array($this,'updateProperties'));
+ $server->subscribeEvent('beforeUnlock', array($this,'beforeUnlock'),20);
+ $server->subscribeEvent('report',array($this,'report'));
+ $server->subscribeEvent('unknownMethod', array($this, 'unknownMethod'));
+
+ array_push($server->protectedProperties,
+ '{DAV:}alternate-URI-set',
+ '{DAV:}principal-URL',
+ '{DAV:}group-membership',
+ '{DAV:}principal-collection-set',
+ '{DAV:}current-user-principal',
+ '{DAV:}supported-privilege-set',
+ '{DAV:}current-user-privilege-set',
+ '{DAV:}acl',
+ '{DAV:}acl-restrictions',
+ '{DAV:}inherited-acl-set',
+ '{DAV:}owner',
+ '{DAV:}group'
+ );
+
+ // Automatically mapping nodes implementing IPrincipal to the
+ // {DAV:}principal resourcetype.
+ $server->resourceTypeMapping['SabreForRainLoop\\DAVACL\\IPrincipal'] = '{DAV:}principal';
+
+ // Mapping the group-member-set property to the HrefList property
+ // class.
+ $server->propertyMap['{DAV:}group-member-set'] = 'SabreForRainLoop\\DAV\\Property\\HrefList';
+
+ }
+
+
+ /* {{{ Event handlers */
+
+ /**
+ * Triggered before any method is handled
+ *
+ * @param string $method
+ * @param string $uri
+ * @return void
+ */
+ public function beforeMethod($method, $uri) {
+
+ $exists = $this->server->tree->nodeExists($uri);
+
+ // If the node doesn't exists, none of these checks apply
+ if (!$exists) return;
+
+ switch($method) {
+
+ case 'GET' :
+ case 'HEAD' :
+ case 'OPTIONS' :
+ // For these 3 we only need to know if the node is readable.
+ $this->checkPrivileges($uri,'{DAV:}read');
+ break;
+
+ case 'PUT' :
+ case 'LOCK' :
+ case 'UNLOCK' :
+ // This method requires the write-content priv if the node
+ // already exists, and bind on the parent if the node is being
+ // created.
+ // The bind privilege is handled in the beforeBind event.
+ $this->checkPrivileges($uri,'{DAV:}write-content');
+ break;
+
+
+ case 'PROPPATCH' :
+ $this->checkPrivileges($uri,'{DAV:}write-properties');
+ break;
+
+ case 'ACL' :
+ $this->checkPrivileges($uri,'{DAV:}write-acl');
+ break;
+
+ case 'COPY' :
+ case 'MOVE' :
+ // Copy requires read privileges on the entire source tree.
+ // If the target exists write-content normally needs to be
+ // checked, however, we're deleting the node beforehand and
+ // creating a new one after, so this is handled by the
+ // beforeUnbind event.
+ //
+ // The creation of the new node is handled by the beforeBind
+ // event.
+ //
+ // If MOVE is used beforeUnbind will also be used to check if
+ // the sourcenode can be deleted.
+ $this->checkPrivileges($uri,'{DAV:}read',self::R_RECURSIVE);
+
+ break;
+
+ }
+
+ }
+
+ /**
+ * Triggered before a new node is created.
+ *
+ * This allows us to check permissions for any operation that creates a
+ * new node, such as PUT, MKCOL, MKCALENDAR, LOCK, COPY and MOVE.
+ *
+ * @param string $uri
+ * @return void
+ */
+ public function beforeBind($uri) {
+
+ list($parentUri,$nodeName) = DAV\URLUtil::splitPath($uri);
+ $this->checkPrivileges($parentUri,'{DAV:}bind');
+
+ }
+
+ /**
+ * Triggered before a node is deleted
+ *
+ * This allows us to check permissions for any operation that will delete
+ * an existing node.
+ *
+ * @param string $uri
+ * @return void
+ */
+ public function beforeUnbind($uri) {
+
+ list($parentUri,$nodeName) = DAV\URLUtil::splitPath($uri);
+ $this->checkPrivileges($parentUri,'{DAV:}unbind',self::R_RECURSIVEPARENTS);
+
+ }
+
+ /**
+ * Triggered before a node is unlocked.
+ *
+ * @param string $uri
+ * @param DAV\Locks\LockInfo $lock
+ * @TODO: not yet implemented
+ * @return void
+ */
+ public function beforeUnlock($uri, DAV\Locks\LockInfo $lock) {
+
+
+ }
+
+ /**
+ * Triggered before properties are looked up in specific nodes.
+ *
+ * @param string $uri
+ * @param DAV\INode $node
+ * @param array $requestedProperties
+ * @param array $returnedProperties
+ * @TODO really should be broken into multiple methods, or even a class.
+ * @return bool
+ */
+ public function beforeGetProperties($uri, DAV\INode $node, &$requestedProperties, &$returnedProperties) {
+
+ // Checking the read permission
+ if (!$this->checkPrivileges($uri,'{DAV:}read',self::R_PARENT,false)) {
+
+ // User is not allowed to read properties
+ if ($this->hideNodesFromListings) {
+ return false;
+ }
+
+ // Marking all requested properties as '403'.
+ foreach($requestedProperties as $key=>$requestedProperty) {
+ unset($requestedProperties[$key]);
+ $returnedProperties[403][$requestedProperty] = null;
+ }
+ return;
+
+ }
+
+ /* Adding principal properties */
+ if ($node instanceof IPrincipal) {
+
+ if (false !== ($index = array_search('{DAV:}alternate-URI-set', $requestedProperties))) {
+
+ unset($requestedProperties[$index]);
+ $returnedProperties[200]['{DAV:}alternate-URI-set'] = new DAV\Property\HrefList($node->getAlternateUriSet());
+
+ }
+ if (false !== ($index = array_search('{DAV:}principal-URL', $requestedProperties))) {
+
+ unset($requestedProperties[$index]);
+ $returnedProperties[200]['{DAV:}principal-URL'] = new DAV\Property\Href($node->getPrincipalUrl() . '/');
+
+ }
+ if (false !== ($index = array_search('{DAV:}group-member-set', $requestedProperties))) {
+
+ unset($requestedProperties[$index]);
+ $returnedProperties[200]['{DAV:}group-member-set'] = new DAV\Property\HrefList($node->getGroupMemberSet());
+
+ }
+ if (false !== ($index = array_search('{DAV:}group-membership', $requestedProperties))) {
+
+ unset($requestedProperties[$index]);
+ $returnedProperties[200]['{DAV:}group-membership'] = new DAV\Property\HrefList($node->getGroupMembership());
+
+ }
+
+ if (false !== ($index = array_search('{DAV:}displayname', $requestedProperties))) {
+
+ $returnedProperties[200]['{DAV:}displayname'] = $node->getDisplayName();
+
+ }
+
+ }
+ if (false !== ($index = array_search('{DAV:}principal-collection-set', $requestedProperties))) {
+
+ unset($requestedProperties[$index]);
+ $val = $this->principalCollectionSet;
+ // Ensuring all collections end with a slash
+ foreach($val as $k=>$v) $val[$k] = $v . '/';
+ $returnedProperties[200]['{DAV:}principal-collection-set'] = new DAV\Property\HrefList($val);
+
+ }
+ if (false !== ($index = array_search('{DAV:}current-user-principal', $requestedProperties))) {
+
+ unset($requestedProperties[$index]);
+ if ($url = $this->getCurrentUserPrincipal()) {
+ $returnedProperties[200]['{DAV:}current-user-principal'] = new Property\Principal(Property\Principal::HREF, $url . '/');
+ } else {
+ $returnedProperties[200]['{DAV:}current-user-principal'] = new Property\Principal(Property\Principal::UNAUTHENTICATED);
+ }
+
+ }
+ if (false !== ($index = array_search('{DAV:}supported-privilege-set', $requestedProperties))) {
+
+ unset($requestedProperties[$index]);
+ $returnedProperties[200]['{DAV:}supported-privilege-set'] = new Property\SupportedPrivilegeSet($this->getSupportedPrivilegeSet($node));
+
+ }
+ if (false !== ($index = array_search('{DAV:}current-user-privilege-set', $requestedProperties))) {
+
+ if (!$this->checkPrivileges($uri, '{DAV:}read-current-user-privilege-set', self::R_PARENT, false)) {
+ $returnedProperties[403]['{DAV:}current-user-privilege-set'] = null;
+ unset($requestedProperties[$index]);
+ } else {
+ $val = $this->getCurrentUserPrivilegeSet($node);
+ if (!is_null($val)) {
+ unset($requestedProperties[$index]);
+ $returnedProperties[200]['{DAV:}current-user-privilege-set'] = new Property\CurrentUserPrivilegeSet($val);
+ }
+ }
+
+ }
+
+ /* The ACL property contains all the permissions */
+ if (false !== ($index = array_search('{DAV:}acl', $requestedProperties))) {
+
+ if (!$this->checkPrivileges($uri, '{DAV:}read-acl', self::R_PARENT, false)) {
+
+ unset($requestedProperties[$index]);
+ $returnedProperties[403]['{DAV:}acl'] = null;
+
+ } else {
+
+ $acl = $this->getACL($node);
+ if (!is_null($acl)) {
+ unset($requestedProperties[$index]);
+ $returnedProperties[200]['{DAV:}acl'] = new Property\Acl($this->getACL($node));
+ }
+
+ }
+
+ }
+
+ /* The acl-restrictions property contains information on how privileges
+ * must behave.
+ */
+ if (false !== ($index = array_search('{DAV:}acl-restrictions', $requestedProperties))) {
+ unset($requestedProperties[$index]);
+ $returnedProperties[200]['{DAV:}acl-restrictions'] = new Property\AclRestrictions();
+ }
+
+ /* Adding ACL properties */
+ if ($node instanceof IACL) {
+
+ if (false !== ($index = array_search('{DAV:}owner', $requestedProperties))) {
+
+ unset($requestedProperties[$index]);
+ $returnedProperties[200]['{DAV:}owner'] = new DAV\Property\Href($node->getOwner() . '/');
+
+ }
+
+ }
+
+ }
+
+ /**
+ * This method intercepts PROPPATCH methods and make sure the
+ * group-member-set is updated correctly.
+ *
+ * @param array $propertyDelta
+ * @param array $result
+ * @param DAV\INode $node
+ * @return bool
+ */
+ public function updateProperties(&$propertyDelta, &$result, DAV\INode $node) {
+
+ if (!array_key_exists('{DAV:}group-member-set', $propertyDelta))
+ return;
+
+ if (is_null($propertyDelta['{DAV:}group-member-set'])) {
+ $memberSet = array();
+ } elseif ($propertyDelta['{DAV:}group-member-set'] instanceof DAV\Property\HrefList) {
+ $memberSet = array_map(
+ array($this->server,'calculateUri'),
+ $propertyDelta['{DAV:}group-member-set']->getHrefs()
+ );
+ } else {
+ throw new DAV\Exception('The group-member-set property MUST be an instance of SabreForRainLoop\DAV\Property\HrefList or null');
+ }
+
+ if (!($node instanceof IPrincipal)) {
+ $result[403]['{DAV:}group-member-set'] = null;
+ unset($propertyDelta['{DAV:}group-member-set']);
+
+ // Returning false will stop the updateProperties process
+ return false;
+ }
+
+ $node->setGroupMemberSet($memberSet);
+ // We must also clear our cache, just in case
+
+ $this->principalMembershipCache = array();
+
+ $result[200]['{DAV:}group-member-set'] = null;
+ unset($propertyDelta['{DAV:}group-member-set']);
+
+ }
+
+ /**
+ * This method handles HTTP REPORT requests
+ *
+ * @param string $reportName
+ * @param \DOMNode $dom
+ * @return bool
+ */
+ public function report($reportName, $dom) {
+
+ switch($reportName) {
+
+ case '{DAV:}principal-property-search' :
+ $this->principalPropertySearchReport($dom);
+ return false;
+ case '{DAV:}principal-search-property-set' :
+ $this->principalSearchPropertySetReport($dom);
+ return false;
+ case '{DAV:}expand-property' :
+ $this->expandPropertyReport($dom);
+ return false;
+
+ }
+
+ }
+
+ /**
+ * This event is triggered for any HTTP method that is not known by the
+ * webserver.
+ *
+ * @param string $method
+ * @param string $uri
+ * @return bool
+ */
+ public function unknownMethod($method, $uri) {
+
+ if ($method!=='ACL') return;
+
+ $this->httpACL($uri);
+ return false;
+
+ }
+
+ /**
+ * This method is responsible for handling the 'ACL' event.
+ *
+ * @param string $uri
+ * @return void
+ */
+ public function httpACL($uri) {
+
+ $body = $this->server->httpRequest->getBody(true);
+ $dom = DAV\XMLUtil::loadDOMDocument($body);
+
+ $newAcl =
+ Property\Acl::unserialize($dom->firstChild)
+ ->getPrivileges();
+
+ // Normalizing urls
+ foreach($newAcl as $k=>$newAce) {
+ $newAcl[$k]['principal'] = $this->server->calculateUri($newAce['principal']);
+ }
+
+ $node = $this->server->tree->getNodeForPath($uri);
+
+ if (!($node instanceof IACL)) {
+ throw new DAV\Exception\MethodNotAllowed('This node does not support the ACL method');
+ }
+
+ $oldAcl = $this->getACL($node);
+
+ $supportedPrivileges = $this->getFlatPrivilegeSet($node);
+
+ /* Checking if protected principals from the existing principal set are
+ not overwritten. */
+ foreach($oldAcl as $oldAce) {
+
+ if (!isset($oldAce['protected']) || !$oldAce['protected']) continue;
+
+ $found = false;
+ foreach($newAcl as $newAce) {
+ if (
+ $newAce['privilege'] === $oldAce['privilege'] &&
+ $newAce['principal'] === $oldAce['principal'] &&
+ $newAce['protected']
+ )
+ $found = true;
+ }
+
+ if (!$found)
+ throw new Exception\AceConflict('This resource contained a protected {DAV:}ace, but this privilege did not occur in the ACL request');
+
+ }
+
+ foreach($newAcl as $newAce) {
+
+ // Do we recognize the privilege
+ if (!isset($supportedPrivileges[$newAce['privilege']])) {
+ throw new Exception\NotSupportedPrivilege('The privilege you specified (' . $newAce['privilege'] . ') is not recognized by this server');
+ }
+
+ if ($supportedPrivileges[$newAce['privilege']]['abstract']) {
+ throw new Exception\NoAbstract('The privilege you specified (' . $newAce['privilege'] . ') is an abstract privilege');
+ }
+
+ // Looking up the principal
+ try {
+ $principal = $this->server->tree->getNodeForPath($newAce['principal']);
+ } catch (DAV\Exception\NotFound $e) {
+ throw new Exception\NotRecognizedPrincipal('The specified principal (' . $newAce['principal'] . ') does not exist');
+ }
+ if (!($principal instanceof IPrincipal)) {
+ throw new Exception\NotRecognizedPrincipal('The specified uri (' . $newAce['principal'] . ') is not a principal');
+ }
+
+ }
+ $node->setACL($newAcl);
+
+ }
+
+ /* }}} */
+
+ /* Reports {{{ */
+
+ /**
+ * The expand-property report is defined in RFC3253 section 3-8.
+ *
+ * This report is very similar to a standard PROPFIND. The difference is
+ * that it has the additional ability to look at properties containing a
+ * {DAV:}href element, follow that property and grab additional elements
+ * there.
+ *
+ * Other rfc's, such as ACL rely on this report, so it made sense to put
+ * it in this plugin.
+ *
+ * @param \DOMElement $dom
+ * @return void
+ */
+ protected function expandPropertyReport($dom) {
+
+ $requestedProperties = $this->parseExpandPropertyReportRequest($dom->firstChild->firstChild);
+ $depth = $this->server->getHTTPDepth(0);
+ $requestUri = $this->server->getRequestUri();
+
+ $result = $this->expandProperties($requestUri,$requestedProperties,$depth);
+
+ $dom = new \DOMDocument('1.0','utf-8');
+ $dom->formatOutput = true;
+ $multiStatus = $dom->createElement('d:multistatus');
+ $dom->appendChild($multiStatus);
+
+ // Adding in default namespaces
+ foreach($this->server->xmlNamespaces as $namespace=>$prefix) {
+
+ $multiStatus->setAttribute('xmlns:' . $prefix,$namespace);
+
+ }
+
+ foreach($result as $response) {
+ $response->serialize($this->server, $multiStatus);
+ }
+
+ $xml = $dom->saveXML();
+ $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
+ $this->server->httpResponse->sendStatus(207);
+ $this->server->httpResponse->sendBody($xml);
+
+ }
+
+ /**
+ * This method is used by expandPropertyReport to parse
+ * out the entire HTTP request.
+ *
+ * @param \DOMElement $node
+ * @return array
+ */
+ protected function parseExpandPropertyReportRequest($node) {
+
+ $requestedProperties = array();
+ do {
+
+ if (DAV\XMLUtil::toClarkNotation($node)!=='{DAV:}property') continue;
+
+ if ($node->firstChild) {
+
+ $children = $this->parseExpandPropertyReportRequest($node->firstChild);
+
+ } else {
+
+ $children = array();
+
+ }
+
+ $namespace = $node->getAttribute('namespace');
+ if (!$namespace) $namespace = 'DAV:';
+
+ $propName = '{'.$namespace.'}' . $node->getAttribute('name');
+ $requestedProperties[$propName] = $children;
+
+ } while ($node = $node->nextSibling);
+
+ return $requestedProperties;
+
+ }
+
+ /**
+ * This method expands all the properties and returns
+ * a list with property values
+ *
+ * @param array $path
+ * @param array $requestedProperties the list of required properties
+ * @param int $depth
+ * @return array
+ */
+ protected function expandProperties($path, array $requestedProperties, $depth) {
+
+ $foundProperties = $this->server->getPropertiesForPath($path, array_keys($requestedProperties), $depth);
+
+ $result = array();
+
+ foreach($foundProperties as $node) {
+
+ foreach($requestedProperties as $propertyName=>$childRequestedProperties) {
+
+ // We're only traversing if sub-properties were requested
+ if(count($childRequestedProperties)===0) continue;
+
+ // We only have to do the expansion if the property was found
+ // and it contains an href element.
+ if (!array_key_exists($propertyName,$node[200])) continue;
+
+ if ($node[200][$propertyName] instanceof DAV\Property\IHref) {
+ $hrefs = array($node[200][$propertyName]->getHref());
+ } elseif ($node[200][$propertyName] instanceof DAV\Property\HrefList) {
+ $hrefs = $node[200][$propertyName]->getHrefs();
+ }
+
+ $childProps = array();
+ foreach($hrefs as $href) {
+ $childProps = array_merge($childProps, $this->expandProperties($href, $childRequestedProperties, 0));
+ }
+ $node[200][$propertyName] = new DAV\Property\ResponseList($childProps);
+
+ }
+ $result[] = new DAV\Property\Response($node['href'], $node);
+
+ }
+
+ return $result;
+
+ }
+
+ /**
+ * principalSearchPropertySetReport
+ *
+ * This method responsible for handing the
+ * {DAV:}principal-search-property-set report. This report returns a list
+ * of properties the client may search on, using the
+ * {DAV:}principal-property-search report.
+ *
+ * @param \DOMDocument $dom
+ * @return void
+ */
+ protected function principalSearchPropertySetReport(\DOMDocument $dom) {
+
+ $httpDepth = $this->server->getHTTPDepth(0);
+ if ($httpDepth!==0) {
+ throw new DAV\Exception\BadRequest('This report is only defined when Depth: 0');
+ }
+
+ if ($dom->firstChild->hasChildNodes())
+ throw new DAV\Exception\BadRequest('The principal-search-property-set report element is not allowed to have child elements');
+
+ $dom = new \DOMDocument('1.0','utf-8');
+ $dom->formatOutput = true;
+ $root = $dom->createElement('d:principal-search-property-set');
+ $dom->appendChild($root);
+ // Adding in default namespaces
+ foreach($this->server->xmlNamespaces as $namespace=>$prefix) {
+
+ $root->setAttribute('xmlns:' . $prefix,$namespace);
+
+ }
+
+ $nsList = $this->server->xmlNamespaces;
+
+ foreach($this->principalSearchPropertySet as $propertyName=>$description) {
+
+ $psp = $dom->createElement('d:principal-search-property');
+ $root->appendChild($psp);
+
+ $prop = $dom->createElement('d:prop');
+ $psp->appendChild($prop);
+
+ $propName = null;
+ preg_match('/^{([^}]*)}(.*)$/',$propertyName,$propName);
+
+ $currentProperty = $dom->createElement($nsList[$propName[1]] . ':' . $propName[2]);
+ $prop->appendChild($currentProperty);
+
+ $descriptionElem = $dom->createElement('d:description');
+ $descriptionElem->setAttribute('xml:lang','en');
+ $descriptionElem->appendChild($dom->createTextNode($description));
+ $psp->appendChild($descriptionElem);
+
+
+ }
+
+ $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
+ $this->server->httpResponse->sendStatus(200);
+ $this->server->httpResponse->sendBody($dom->saveXML());
+
+ }
+
+ /**
+ * principalPropertySearchReport
+ *
+ * This method is responsible for handing the
+ * {DAV:}principal-property-search report. This report can be used for
+ * clients to search for groups of principals, based on the value of one
+ * or more properties.
+ *
+ * @param \DOMDocument $dom
+ * @return void
+ */
+ protected function principalPropertySearchReport(\DOMDocument $dom) {
+
+ list($searchProperties, $requestedProperties, $applyToPrincipalCollectionSet) = $this->parsePrincipalPropertySearchReportRequest($dom);
+
+ $uri = null;
+ if (!$applyToPrincipalCollectionSet) {
+ $uri = $this->server->getRequestUri();
+ }
+ $result = $this->principalSearch($searchProperties, $requestedProperties, $uri);
+
+ $prefer = $this->server->getHTTPPRefer();
+
+ $this->server->httpResponse->sendStatus(207);
+ $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
+ $this->server->httpResponse->setHeader('Vary','Brief,Prefer');
+ $this->server->httpResponse->sendBody($this->server->generateMultiStatus($result, $prefer['return-minimal']));
+
+ }
+
+ /**
+ * parsePrincipalPropertySearchReportRequest
+ *
+ * This method parses the request body from a
+ * {DAV:}principal-property-search report.
+ *
+ * This method returns an array with two elements:
+ * 1. an array with properties to search on, and their values
+ * 2. a list of propertyvalues that should be returned for the request.
+ *
+ * @param \DOMDocument $dom
+ * @return array
+ */
+ protected function parsePrincipalPropertySearchReportRequest($dom) {
+
+ $httpDepth = $this->server->getHTTPDepth(0);
+ if ($httpDepth!==0) {
+ throw new DAV\Exception\BadRequest('This report is only defined when Depth: 0');
+ }
+
+ $searchProperties = array();
+
+ $applyToPrincipalCollectionSet = false;
+
+ // Parsing the search request
+ foreach($dom->firstChild->childNodes as $searchNode) {
+
+ if (DAV\XMLUtil::toClarkNotation($searchNode) == '{DAV:}apply-to-principal-collection-set') {
+ $applyToPrincipalCollectionSet = true;
+ }
+
+ if (DAV\XMLUtil::toClarkNotation($searchNode)!=='{DAV:}property-search')
+ continue;
+
+ $propertyName = null;
+ $propertyValue = null;
+
+ foreach($searchNode->childNodes as $childNode) {
+
+ switch(DAV\XMLUtil::toClarkNotation($childNode)) {
+
+ case '{DAV:}prop' :
+ $property = DAV\XMLUtil::parseProperties($searchNode);
+ reset($property);
+ $propertyName = key($property);
+ break;
+
+ case '{DAV:}match' :
+ $propertyValue = $childNode->textContent;
+ break;
+
+ }
+
+
+ }
+
+ if (is_null($propertyName) || is_null($propertyValue))
+ throw new DAV\Exception\BadRequest('Invalid search request. propertyname: ' . $propertyName . '. propertvvalue: ' . $propertyValue);
+
+ $searchProperties[$propertyName] = $propertyValue;
+
+ }
+
+ return array($searchProperties, array_keys(DAV\XMLUtil::parseProperties($dom->firstChild)), $applyToPrincipalCollectionSet);
+
+ }
+
+
+ /* }}} */
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Principal.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Principal.php
new file mode 100644
index 0000000..b2d9e9d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Principal.php
@@ -0,0 +1,281 @@
+principalBackend = $principalBackend;
+ $this->principalProperties = $principalProperties;
+
+ }
+
+ /**
+ * Returns the full principal url
+ *
+ * @return string
+ */
+ public function getPrincipalUrl() {
+
+ return $this->principalProperties['uri'];
+
+ }
+
+ /**
+ * Returns a list of alternative urls for a principal
+ *
+ * This can for example be an email address, or ldap url.
+ *
+ * @return array
+ */
+ public function getAlternateUriSet() {
+
+ $uris = array();
+ if (isset($this->principalProperties['{DAV:}alternate-URI-set'])) {
+
+ $uris = $this->principalProperties['{DAV:}alternate-URI-set'];
+
+ }
+
+ if (isset($this->principalProperties['{http://sabredav.org/ns}email-address'])) {
+ $uris[] = 'mailto:' . $this->principalProperties['{http://sabredav.org/ns}email-address'];
+ }
+
+ return array_unique($uris);
+
+ }
+
+ /**
+ * Returns the list of group members
+ *
+ * If this principal is a group, this function should return
+ * all member principal uri's for the group.
+ *
+ * @return array
+ */
+ public function getGroupMemberSet() {
+
+ return $this->principalBackend->getGroupMemberSet($this->principalProperties['uri']);
+
+ }
+
+ /**
+ * Returns the list of groups this principal is member of
+ *
+ * If this principal is a member of a (list of) groups, this function
+ * should return a list of principal uri's for it's members.
+ *
+ * @return array
+ */
+ public function getGroupMembership() {
+
+ return $this->principalBackend->getGroupMemberShip($this->principalProperties['uri']);
+
+ }
+
+
+ /**
+ * Sets a list of group members
+ *
+ * If this principal is a group, this method sets all the group members.
+ * The list of members is always overwritten, never appended to.
+ *
+ * This method should throw an exception if the members could not be set.
+ *
+ * @param array $groupMembers
+ * @return void
+ */
+ public function setGroupMemberSet(array $groupMembers) {
+
+ $this->principalBackend->setGroupMemberSet($this->principalProperties['uri'], $groupMembers);
+
+ }
+
+
+ /**
+ * Returns this principals name.
+ *
+ * @return string
+ */
+ public function getName() {
+
+ $uri = $this->principalProperties['uri'];
+ list(, $name) = DAV\URLUtil::splitPath($uri);
+ return $name;
+
+ }
+
+ /**
+ * Returns the name of the user
+ *
+ * @return string
+ */
+ public function getDisplayName() {
+
+ if (isset($this->principalProperties['{DAV:}displayname'])) {
+ return $this->principalProperties['{DAV:}displayname'];
+ } else {
+ return $this->getName();
+ }
+
+ }
+
+ /**
+ * Returns a list of properties
+ *
+ * @param array $requestedProperties
+ * @return array
+ */
+ public function getProperties($requestedProperties) {
+
+ $newProperties = array();
+ foreach($requestedProperties as $propName) {
+
+ if (isset($this->principalProperties[$propName])) {
+ $newProperties[$propName] = $this->principalProperties[$propName];
+ }
+
+ }
+
+ return $newProperties;
+
+ }
+
+ /**
+ * Updates this principals properties.
+ *
+ * @param array $mutations
+ * @see SabreForRainLoop\DAV\IProperties::updateProperties
+ * @return bool|array
+ */
+ public function updateProperties($mutations) {
+
+ return $this->principalBackend->updatePrincipal($this->principalProperties['uri'], $mutations);
+
+ }
+
+ /**
+ * Returns the owner principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getOwner() {
+
+ return $this->principalProperties['uri'];
+
+
+ }
+
+ /**
+ * Returns a group principal
+ *
+ * This must be a url to a principal, or null if there's no owner
+ *
+ * @return string|null
+ */
+ public function getGroup() {
+
+ return null;
+
+ }
+
+ /**
+ * Returns a list of ACE's for this node.
+ *
+ * Each ACE has the following properties:
+ * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
+ * currently the only supported privileges
+ * * 'principal', a url to the principal who owns the node
+ * * 'protected' (optional), indicating that this ACE is not allowed to
+ * be updated.
+ *
+ * @return array
+ */
+ public function getACL() {
+
+ return array(
+ array(
+ 'privilege' => '{DAV:}read',
+ 'principal' => $this->getPrincipalUrl(),
+ 'protected' => true,
+ ),
+ );
+
+ }
+
+ /**
+ * Updates the ACL
+ *
+ * This method will receive a list of new ACE's.
+ *
+ * @param array $acl
+ * @return void
+ */
+ public function setACL(array $acl) {
+
+ throw new DAV\Exception\MethodNotAllowed('Updating ACLs is not allowed here');
+
+ }
+
+ /**
+ * Returns the list of supported privileges for this node.
+ *
+ * The returned data structure is a list of nested privileges.
+ * See SabreForRainLoop\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
+ * standard structure.
+ *
+ * If null is returned from this method, the default privilege set is used,
+ * which is fine for most common usecases.
+ *
+ * @return array|null
+ */
+ public function getSupportedPrivilegeSet() {
+
+ return null;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/AbstractBackend.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/AbstractBackend.php
new file mode 100644
index 0000000..3f500e3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/AbstractBackend.php
@@ -0,0 +1,18 @@
+ array(
+ * '{DAV:}prop1' => null,
+ * ),
+ * 201 => array(
+ * '{DAV:}prop2' => null,
+ * ),
+ * 403 => array(
+ * '{DAV:}prop3' => null,
+ * ),
+ * 424 => array(
+ * '{DAV:}prop4' => null,
+ * ),
+ * );
+ *
+ * In this previous example prop1 was successfully updated or deleted, and
+ * prop2 was succesfully created.
+ *
+ * prop3 failed to update due to '403 Forbidden' and because of this prop4
+ * also could not be updated with '424 Failed dependency'.
+ *
+ * This last example was actually incorrect. While 200 and 201 could appear
+ * in 1 response, if there's any error (403) the other properties should
+ * always fail with 423 (failed dependency).
+ *
+ * But anyway, if you don't want to scratch your head over this, just
+ * return true or false.
+ *
+ * @param string $path
+ * @param array $mutations
+ * @return array|bool
+ */
+ function updatePrincipal($path, $mutations);
+
+ /**
+ * This method is used to search for principals matching a set of
+ * properties.
+ *
+ * This search is specifically used by RFC3744's principal-property-search
+ * REPORT. You should at least allow searching on
+ * http://sabredav.org/ns}email-address.
+ *
+ * The actual search should be a unicode-non-case-sensitive search. The
+ * keys in searchProperties are the WebDAV property names, while the values
+ * are the property values to search on.
+ *
+ * If multiple properties are being searched on, the search should be
+ * AND'ed.
+ *
+ * This method should simply return an array with full principal uri's.
+ *
+ * If somebody attempted to search on a property the backend does not
+ * support, you should simply return 0 results.
+ *
+ * You can also just return 0 results if you choose to not support
+ * searching at all, but keep in mind that this may stop certain features
+ * from working.
+ *
+ * @param string $prefixPath
+ * @param array $searchProperties
+ * @return array
+ */
+ function searchPrincipals($prefixPath, array $searchProperties);
+
+ /**
+ * Returns the list of members for a group-principal
+ *
+ * @param string $principal
+ * @return array
+ */
+ function getGroupMemberSet($principal);
+
+ /**
+ * Returns the list of groups a principal is a member of
+ *
+ * @param string $principal
+ * @return array
+ */
+ function getGroupMembership($principal);
+
+ /**
+ * Updates the list of group members for a group principal.
+ *
+ * The principals should be passed as a list of uri's.
+ *
+ * @param string $principal
+ * @param array $members
+ * @return void
+ */
+ function setGroupMemberSet($principal, array $members);
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/PDO.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/PDO.php
new file mode 100644
index 0000000..4717c49
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/PrincipalBackend/PDO.php
@@ -0,0 +1,428 @@
+ array(
+ 'dbField' => 'displayname',
+ ),
+
+ /**
+ * This property is actually used by the CardDAV plugin, where it gets
+ * mapped to {http://calendarserver.orgi/ns/}me-card.
+ *
+ * The reason we don't straight-up use that property, is because
+ * me-card is defined as a property on the users' addressbook
+ * collection.
+ */
+ '{http://sabredav.org/ns}vcard-url' => array(
+ 'dbField' => 'vcardurl',
+ ),
+ /**
+ * This is the users' primary email-address.
+ */
+ '{http://sabredav.org/ns}email-address' => array(
+ 'dbField' => 'email',
+ ),
+ );
+
+ /**
+ * Sets up the backend.
+ *
+ * @param PDO $pdo
+ * @param string $tableName
+ * @param string $groupMembersTableName
+ */
+ public function __construct(\PDO $pdo, $tableName = 'principals', $groupMembersTableName = 'groupmembers') {
+
+ $this->pdo = $pdo;
+ $this->tableName = $tableName;
+ $this->groupMembersTableName = $groupMembersTableName;
+
+ }
+
+
+ /**
+ * Returns a list of principals based on a prefix.
+ *
+ * This prefix will often contain something like 'principals'. You are only
+ * expected to return principals that are in this base path.
+ *
+ * You are expected to return at least a 'uri' for every user, you can
+ * return any additional properties if you wish so. Common properties are:
+ * {DAV:}displayname
+ * {http://sabredav.org/ns}email-address - This is a custom SabreDAV
+ * field that's actualy injected in a number of other properties. If
+ * you have an email address, use this property.
+ *
+ * @param string $prefixPath
+ * @return array
+ */
+ public function getPrincipalsByPrefix($prefixPath) {
+
+ $fields = array(
+ 'uri',
+ );
+
+ foreach($this->fieldMap as $key=>$value) {
+ $fields[] = $value['dbField'];
+ }
+ $result = $this->pdo->query('SELECT '.implode(',', $fields).' FROM '. $this->tableName);
+
+ $principals = array();
+
+ while($row = $result->fetch(\PDO::FETCH_ASSOC)) {
+
+ // Checking if the principal is in the prefix
+ list($rowPrefix) = DAV\URLUtil::splitPath($row['uri']);
+ if ($rowPrefix !== $prefixPath) continue;
+
+ $principal = array(
+ 'uri' => $row['uri'],
+ );
+ foreach($this->fieldMap as $key=>$value) {
+ if ($row[$value['dbField']]) {
+ $principal[$key] = $row[$value['dbField']];
+ }
+ }
+ $principals[] = $principal;
+
+ }
+
+ return $principals;
+
+ }
+
+ /**
+ * Returns a specific principal, specified by it's path.
+ * The returned structure should be the exact same as from
+ * getPrincipalsByPrefix.
+ *
+ * @param string $path
+ * @return array
+ */
+ public function getPrincipalByPath($path) {
+
+ $fields = array(
+ 'id',
+ 'uri',
+ );
+
+ foreach($this->fieldMap as $key=>$value) {
+ $fields[] = $value['dbField'];
+ }
+ $stmt = $this->pdo->prepare('SELECT '.implode(',', $fields).' FROM '. $this->tableName . ' WHERE uri = ?');
+ $stmt->execute(array($path));
+
+ $row = $stmt->fetch(\PDO::FETCH_ASSOC);
+ if (!$row) return;
+
+ $principal = array(
+ 'id' => $row['id'],
+ 'uri' => $row['uri'],
+ );
+ foreach($this->fieldMap as $key=>$value) {
+ if ($row[$value['dbField']]) {
+ $principal[$key] = $row[$value['dbField']];
+ }
+ }
+ return $principal;
+
+ }
+
+ /**
+ * Updates one ore more webdav properties on a principal.
+ *
+ * The list of mutations is supplied as an array. Each key in the array is
+ * a propertyname, such as {DAV:}displayname.
+ *
+ * Each value is the actual value to be updated. If a value is null, it
+ * must be deleted.
+ *
+ * This method should be atomic. It must either completely succeed, or
+ * completely fail. Success and failure can simply be returned as 'true' or
+ * 'false'.
+ *
+ * It is also possible to return detailed failure information. In that case
+ * an array such as this should be returned:
+ *
+ * array(
+ * 200 => array(
+ * '{DAV:}prop1' => null,
+ * ),
+ * 201 => array(
+ * '{DAV:}prop2' => null,
+ * ),
+ * 403 => array(
+ * '{DAV:}prop3' => null,
+ * ),
+ * 424 => array(
+ * '{DAV:}prop4' => null,
+ * ),
+ * );
+ *
+ * In this previous example prop1 was successfully updated or deleted, and
+ * prop2 was succesfully created.
+ *
+ * prop3 failed to update due to '403 Forbidden' and because of this prop4
+ * also could not be updated with '424 Failed dependency'.
+ *
+ * This last example was actually incorrect. While 200 and 201 could appear
+ * in 1 response, if there's any error (403) the other properties should
+ * always fail with 423 (failed dependency).
+ *
+ * But anyway, if you don't want to scratch your head over this, just
+ * return true or false.
+ *
+ * @param string $path
+ * @param array $mutations
+ * @return array|bool
+ */
+ public function updatePrincipal($path, $mutations) {
+
+ $updateAble = array();
+ foreach($mutations as $key=>$value) {
+
+ // We are not aware of this field, we must fail.
+ if (!isset($this->fieldMap[$key])) {
+
+ $response = array(
+ 403 => array(
+ $key => null,
+ ),
+ 424 => array(),
+ );
+
+ // Adding the rest to the response as a 424
+ foreach($mutations as $subKey=>$subValue) {
+ if ($subKey !== $key) {
+ $response[424][$subKey] = null;
+ }
+ }
+ return $response;
+ }
+
+ $updateAble[$this->fieldMap[$key]['dbField']] = $value;
+
+ }
+
+ // No fields to update
+ $query = "UPDATE " . $this->tableName . " SET ";
+
+ $first = true;
+ foreach($updateAble as $key => $value) {
+ if (!$first) {
+ $query.= ', ';
+ }
+ $first = false;
+ $query.= "$key = :$key ";
+ }
+ $query.='WHERE uri = :uri';
+ $stmt = $this->pdo->prepare($query);
+ $updateAble['uri'] = $path;
+ $stmt->execute($updateAble);
+
+ return true;
+
+ }
+
+ /**
+ * This method is used to search for principals matching a set of
+ * properties.
+ *
+ * This search is specifically used by RFC3744's principal-property-search
+ * REPORT. You should at least allow searching on
+ * http://sabredav.org/ns}email-address.
+ *
+ * The actual search should be a unicode-non-case-sensitive search. The
+ * keys in searchProperties are the WebDAV property names, while the values
+ * are the property values to search on.
+ *
+ * If multiple properties are being searched on, the search should be
+ * AND'ed.
+ *
+ * This method should simply return an array with full principal uri's.
+ *
+ * If somebody attempted to search on a property the backend does not
+ * support, you should simply return 0 results.
+ *
+ * You can also just return 0 results if you choose to not support
+ * searching at all, but keep in mind that this may stop certain features
+ * from working.
+ *
+ * @param string $prefixPath
+ * @param array $searchProperties
+ * @return array
+ */
+ public function searchPrincipals($prefixPath, array $searchProperties) {
+
+ $query = 'SELECT uri FROM ' . $this->tableName . ' WHERE 1=1 ';
+ $values = array();
+ foreach($searchProperties as $property => $value) {
+
+ switch($property) {
+
+ case '{DAV:}displayname' :
+ $query.=' AND displayname LIKE ?';
+ $values[] = '%' . $value . '%';
+ break;
+ case '{http://sabredav.org/ns}email-address' :
+ $query.=' AND email LIKE ?';
+ $values[] = '%' . $value . '%';
+ break;
+ default :
+ // Unsupported property
+ return array();
+
+ }
+
+ }
+ $stmt = $this->pdo->prepare($query);
+ $stmt->execute($values);
+
+ $principals = array();
+ while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+
+ // Checking if the principal is in the prefix
+ list($rowPrefix) = DAV\URLUtil::splitPath($row['uri']);
+ if ($rowPrefix !== $prefixPath) continue;
+
+ $principals[] = $row['uri'];
+
+ }
+
+ return $principals;
+
+ }
+
+ /**
+ * Returns the list of members for a group-principal
+ *
+ * @param string $principal
+ * @return array
+ */
+ public function getGroupMemberSet($principal) {
+
+ $principal = $this->getPrincipalByPath($principal);
+ if (!$principal) throw new DAV\Exception('Principal not found');
+
+ $stmt = $this->pdo->prepare('SELECT principals.uri as uri FROM '.$this->groupMembersTableName.' AS groupmembers LEFT JOIN '.$this->tableName.' AS principals ON groupmembers.member_id = principals.id WHERE groupmembers.principal_id = ?');
+ $stmt->execute(array($principal['id']));
+
+ $result = array();
+ while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+ $result[] = $row['uri'];
+ }
+ return $result;
+
+ }
+
+ /**
+ * Returns the list of groups a principal is a member of
+ *
+ * @param string $principal
+ * @return array
+ */
+ public function getGroupMembership($principal) {
+
+ $principal = $this->getPrincipalByPath($principal);
+ if (!$principal) throw new DAV\Exception('Principal not found');
+
+ $stmt = $this->pdo->prepare('SELECT principals.uri as uri FROM '.$this->groupMembersTableName.' AS groupmembers LEFT JOIN '.$this->tableName.' AS principals ON groupmembers.principal_id = principals.id WHERE groupmembers.member_id = ?');
+ $stmt->execute(array($principal['id']));
+
+ $result = array();
+ while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+ $result[] = $row['uri'];
+ }
+ return $result;
+
+ }
+
+ /**
+ * Updates the list of group members for a group principal.
+ *
+ * The principals should be passed as a list of uri's.
+ *
+ * @param string $principal
+ * @param array $members
+ * @return void
+ */
+ public function setGroupMemberSet($principal, array $members) {
+
+ // Grabbing the list of principal id's.
+ $stmt = $this->pdo->prepare('SELECT id, uri FROM '.$this->tableName.' WHERE uri IN (? ' . str_repeat(', ? ', count($members)) . ');');
+ $stmt->execute(array_merge(array($principal), $members));
+
+ $memberIds = array();
+ $principalId = null;
+
+ while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
+ if ($row['uri'] == $principal) {
+ $principalId = $row['id'];
+ } else {
+ $memberIds[] = $row['id'];
+ }
+ }
+ if (!$principalId) throw new DAV\Exception('Principal not found');
+
+ // Wiping out old members
+ $stmt = $this->pdo->prepare('DELETE FROM '.$this->groupMembersTableName.' WHERE principal_id = ?;');
+ $stmt->execute(array($principalId));
+
+ foreach($memberIds as $memberId) {
+
+ $stmt = $this->pdo->prepare('INSERT INTO '.$this->groupMembersTableName.' (principal_id, member_id) VALUES (?, ?);');
+ $stmt->execute(array($principalId, $memberId));
+
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/PrincipalCollection.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/PrincipalCollection.php
new file mode 100644
index 0000000..aa8cdd8
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/PrincipalCollection.php
@@ -0,0 +1,33 @@
+principalBackend, $principal);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Property/Acl.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Property/Acl.php
new file mode 100644
index 0000000..8284fd3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Property/Acl.php
@@ -0,0 +1,211 @@
+privileges = $privileges;
+ $this->prefixBaseUrl = $prefixBaseUrl;
+
+ }
+
+ /**
+ * Returns the list of privileges for this property
+ *
+ * @return array
+ */
+ public function getPrivileges() {
+
+ return $this->privileges;
+
+ }
+
+ /**
+ * Serializes the property into a DOMElement
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $node
+ * @return void
+ */
+ public function serialize(DAV\Server $server,\DOMElement $node) {
+
+ $doc = $node->ownerDocument;
+ foreach($this->privileges as $ace) {
+
+ $this->serializeAce($doc, $node, $ace, $server);
+
+ }
+
+ }
+
+ /**
+ * Unserializes the {DAV:}acl xml element.
+ *
+ * @param \DOMElement $dom
+ * @return Acl
+ */
+ static public function unserialize(\DOMElement $dom) {
+
+ $privileges = array();
+ $xaces = $dom->getElementsByTagNameNS('urn:DAV','ace');
+ for($ii=0; $ii < $xaces->length; $ii++) {
+
+ $xace = $xaces->item($ii);
+ $principal = $xace->getElementsByTagNameNS('urn:DAV','principal');
+ if ($principal->length !== 1) {
+ throw new DAV\Exception\BadRequest('Each {DAV:}ace element must have one {DAV:}principal element');
+ }
+ $principal = Principal::unserialize($principal->item(0));
+
+ switch($principal->getType()) {
+ case Principal::HREF :
+ $principal = $principal->getHref();
+ break;
+ case Principal::AUTHENTICATED :
+ $principal = '{DAV:}authenticated';
+ break;
+ case Principal::UNAUTHENTICATED :
+ $principal = '{DAV:}unauthenticated';
+ break;
+ case Principal::ALL :
+ $principal = '{DAV:}all';
+ break;
+
+ }
+
+ $protected = false;
+
+ if ($xace->getElementsByTagNameNS('urn:DAV','protected')->length > 0) {
+ $protected = true;
+ }
+
+ $grants = $xace->getElementsByTagNameNS('urn:DAV','grant');
+ if ($grants->length < 1) {
+ throw new DAV\Exception\NotImplemented('Every {DAV:}ace element must have a {DAV:}grant element. {DAV:}deny is not yet supported');
+ }
+ $grant = $grants->item(0);
+
+ $xprivs = $grant->getElementsByTagNameNS('urn:DAV','privilege');
+ for($jj=0; $jj<$xprivs->length; $jj++) {
+
+ $xpriv = $xprivs->item($jj);
+
+ $privilegeName = null;
+
+ for ($kk=0;$kk<$xpriv->childNodes->length;$kk++) {
+
+ $childNode = $xpriv->childNodes->item($kk);
+ if ($t = DAV\XMLUtil::toClarkNotation($childNode)) {
+ $privilegeName = $t;
+ break;
+ }
+ }
+ if (is_null($privilegeName)) {
+ throw new DAV\Exception\BadRequest('{DAV:}privilege elements must have a privilege element contained within them.');
+ }
+
+ $privileges[] = array(
+ 'principal' => $principal,
+ 'protected' => $protected,
+ 'privilege' => $privilegeName,
+ );
+
+ }
+
+ }
+
+ return new self($privileges);
+
+ }
+
+ /**
+ * Serializes a single access control entry.
+ *
+ * @param \DOMDocument $doc
+ * @param \DOMElement $node
+ * @param array $ace
+ * @param DAV\Server $server
+ * @return void
+ */
+ private function serializeAce($doc,$node,$ace, DAV\Server $server) {
+
+ $xace = $doc->createElementNS('DAV:','d:ace');
+ $node->appendChild($xace);
+
+ $principal = $doc->createElementNS('DAV:','d:principal');
+ $xace->appendChild($principal);
+ switch($ace['principal']) {
+ case '{DAV:}authenticated' :
+ $principal->appendChild($doc->createElementNS('DAV:','d:authenticated'));
+ break;
+ case '{DAV:}unauthenticated' :
+ $principal->appendChild($doc->createElementNS('DAV:','d:unauthenticated'));
+ break;
+ case '{DAV:}all' :
+ $principal->appendChild($doc->createElementNS('DAV:','d:all'));
+ break;
+ default:
+ $principal->appendChild($doc->createElementNS('DAV:','d:href',($this->prefixBaseUrl?$server->getBaseUri():'') . $ace['principal'] . '/'));
+ }
+
+ $grant = $doc->createElementNS('DAV:','d:grant');
+ $xace->appendChild($grant);
+
+ $privParts = null;
+
+ preg_match('/^{([^}]*)}(.*)$/',$ace['privilege'],$privParts);
+
+ $xprivilege = $doc->createElementNS('DAV:','d:privilege');
+ $grant->appendChild($xprivilege);
+
+ $xprivilege->appendChild($doc->createElementNS($privParts[1],'d:'.$privParts[2]));
+
+ if (isset($ace['protected']) && $ace['protected'])
+ $xace->appendChild($doc->createElement('d:protected'));
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Property/AclRestrictions.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Property/AclRestrictions.php
new file mode 100644
index 0000000..f512424
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Property/AclRestrictions.php
@@ -0,0 +1,34 @@
+ownerDocument;
+
+ $elem->appendChild($doc->createElementNS('DAV:','d:grant-only'));
+ $elem->appendChild($doc->createElementNS('DAV:','d:no-invert'));
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Property/CurrentUserPrivilegeSet.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Property/CurrentUserPrivilegeSet.php
new file mode 100644
index 0000000..4230793
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Property/CurrentUserPrivilegeSet.php
@@ -0,0 +1,124 @@
+privileges = $privileges;
+
+ }
+
+ /**
+ * Serializes the property in the DOM
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $node
+ * @return void
+ */
+ public function serialize(DAV\Server $server,\DOMElement $node) {
+
+ $doc = $node->ownerDocument;
+ foreach($this->privileges as $privName) {
+
+ $this->serializePriv($doc,$node,$privName);
+
+ }
+
+ }
+
+ /**
+ * Returns true or false, whether the specified principal appears in the
+ * list.
+ *
+ * @return bool
+ */
+ public function has($privilegeName) {
+
+ return in_array($privilegeName, $this->privileges);
+
+ }
+
+ /**
+ * Serializes one privilege
+ *
+ * @param \DOMDocument $doc
+ * @param \DOMElement $node
+ * @param string $privName
+ * @return void
+ */
+ protected function serializePriv($doc,$node,$privName) {
+
+ $xp = $doc->createElementNS('DAV:','d:privilege');
+ $node->appendChild($xp);
+
+ $privParts = null;
+ preg_match('/^{([^}]*)}(.*)$/',$privName,$privParts);
+
+ $xp->appendChild($doc->createElementNS($privParts[1],'d:'.$privParts[2]));
+
+ }
+
+ /**
+ * Unserializes the {DAV:}current-user-privilege-set element.
+ *
+ * @param DOMElement $node
+ * @return CurrentUserPrivilegeSet
+ */
+ static public function unserialize(\DOMElement $node) {
+
+ $result = array();
+
+ $xprivs = $node->getElementsByTagNameNS('urn:DAV','privilege');
+
+ for($jj=0; $jj<$xprivs->length; $jj++) {
+
+ $xpriv = $xprivs->item($jj);
+
+ $privilegeName = null;
+
+ for ($kk=0;$kk<$xpriv->childNodes->length;$kk++) {
+
+ $childNode = $xpriv->childNodes->item($kk);
+ if ($t = DAV\XMLUtil::toClarkNotation($childNode)) {
+ $privilegeName = $t;
+ break;
+ }
+ }
+
+ $result[] = $privilegeName;
+
+ }
+
+ return new self($result);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Property/Principal.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Property/Principal.php
new file mode 100644
index 0000000..c6f813f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Property/Principal.php
@@ -0,0 +1,161 @@
+type = $type;
+
+ if ($type===self::HREF && is_null($href)) {
+ throw new DAV\Exception('The href argument must be specified for the HREF principal type.');
+ }
+ $this->href = $href;
+
+ }
+
+ /**
+ * Returns the principal type
+ *
+ * @return int
+ */
+ public function getType() {
+
+ return $this->type;
+
+ }
+
+ /**
+ * Returns the principal uri.
+ *
+ * @return string
+ */
+ public function getHref() {
+
+ return $this->href;
+
+ }
+
+ /**
+ * Serializes the property into a DOMElement.
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $node
+ * @return void
+ */
+ public function serialize(DAV\Server $server, \DOMElement $node) {
+
+ $prefix = $server->xmlNamespaces['DAV:'];
+ switch($this->type) {
+
+ case self::UNAUTHENTICATED :
+ $node->appendChild(
+ $node->ownerDocument->createElement($prefix . ':unauthenticated')
+ );
+ break;
+ case self::AUTHENTICATED :
+ $node->appendChild(
+ $node->ownerDocument->createElement($prefix . ':authenticated')
+ );
+ break;
+ case self::HREF :
+ $href = $node->ownerDocument->createElement($prefix . ':href');
+ $href->nodeValue = $server->getBaseUri() . DAV\URLUtil::encodePath($this->href);
+ $node->appendChild($href);
+ break;
+
+ }
+
+ }
+
+ /**
+ * Deserializes a DOM element into a property object.
+ *
+ * @param \DOMElement $dom
+ * @return Principal
+ */
+ static public function unserialize(\DOMElement $dom) {
+
+ $parent = $dom->firstChild;
+ while(!DAV\XMLUtil::toClarkNotation($parent)) {
+ $parent = $parent->nextSibling;
+ }
+
+ switch(DAV\XMLUtil::toClarkNotation($parent)) {
+
+ case '{DAV:}unauthenticated' :
+ return new self(self::UNAUTHENTICATED);
+ case '{DAV:}authenticated' :
+ return new self(self::AUTHENTICATED);
+ case '{DAV:}href':
+ return new self(self::HREF, $parent->textContent);
+ case '{DAV:}all':
+ return new self(self::ALL);
+ default :
+ throw new DAV\Exception\BadRequest('Unexpected element (' . DAV\XMLUtil::toClarkNotation($parent) . '). Could not deserialize');
+
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Property/SupportedPrivilegeSet.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Property/SupportedPrivilegeSet.php
new file mode 100644
index 0000000..2f3e507
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Property/SupportedPrivilegeSet.php
@@ -0,0 +1,94 @@
+privileges = $privileges;
+
+ }
+
+ /**
+ * Serializes the property into a domdocument.
+ *
+ * @param DAV\Server $server
+ * @param \DOMElement $node
+ * @return void
+ */
+ public function serialize(DAV\Server $server,\DOMElement $node) {
+
+ $doc = $node->ownerDocument;
+ $this->serializePriv($doc, $node, $this->privileges);
+
+ }
+
+ /**
+ * Serializes a property
+ *
+ * This is a recursive function.
+ *
+ * @param \DOMDocument $doc
+ * @param \DOMElement $node
+ * @param array $privilege
+ * @return void
+ */
+ private function serializePriv($doc,$node,$privilege) {
+
+ $xsp = $doc->createElementNS('DAV:','d:supported-privilege');
+ $node->appendChild($xsp);
+
+ $xp = $doc->createElementNS('DAV:','d:privilege');
+ $xsp->appendChild($xp);
+
+ $privParts = null;
+ preg_match('/^{([^}]*)}(.*)$/',$privilege['privilege'],$privParts);
+
+ $xp->appendChild($doc->createElementNS($privParts[1],'d:'.$privParts[2]));
+
+ if (isset($privilege['abstract']) && $privilege['abstract']) {
+ $xsp->appendChild($doc->createElementNS('DAV:','d:abstract'));
+ }
+
+ if (isset($privilege['description'])) {
+ $xsp->appendChild($doc->createElementNS('DAV:','d:description',$privilege['description']));
+ }
+
+ if (isset($privilege['aggregates'])) {
+ foreach($privilege['aggregates'] as $subPrivilege) {
+ $this->serializePriv($doc,$xsp,$subPrivilege);
+ }
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Version.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Version.php
new file mode 100644
index 0000000..722ab49
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/DAVACL/Version.php
@@ -0,0 +1,24 @@
+httpRequest->getHeader('Authorization');
+ $authHeader = explode(' ',$authHeader);
+
+ if ($authHeader[0]!='AWS' || !isset($authHeader[1])) {
+ $this->errorCode = self::ERR_NOAWSHEADER;
+ return false;
+ }
+
+ list($this->accessKey,$this->signature) = explode(':',$authHeader[1]);
+
+ return true;
+
+ }
+
+ /**
+ * Returns the username for the request
+ *
+ * @return string
+ */
+ public function getAccessKey() {
+
+ return $this->accessKey;
+
+ }
+
+ /**
+ * Validates the signature based on the secretKey
+ *
+ * @param string $secretKey
+ * @return bool
+ */
+ public function validate($secretKey) {
+
+ $contentMD5 = $this->httpRequest->getHeader('Content-MD5');
+
+ if ($contentMD5) {
+ // We need to validate the integrity of the request
+ $body = $this->httpRequest->getBody(true);
+ $this->httpRequest->setBody($body,true);
+
+ if ($contentMD5!=base64_encode(md5($body,true))) {
+ // content-md5 header did not match md5 signature of body
+ $this->errorCode = self::ERR_MD5CHECKSUMWRONG;
+ return false;
+ }
+
+ }
+
+ if (!$requestDate = $this->httpRequest->getHeader('x-amz-date'))
+ $requestDate = $this->httpRequest->getHeader('Date');
+
+ if (!$this->validateRFC2616Date($requestDate))
+ return false;
+
+ $amzHeaders = $this->getAmzHeaders();
+
+ $signature = base64_encode(
+ $this->hmacsha1($secretKey,
+ $this->httpRequest->getMethod() . "\n" .
+ $contentMD5 . "\n" .
+ $this->httpRequest->getHeader('Content-type') . "\n" .
+ $requestDate . "\n" .
+ $amzHeaders .
+ $this->httpRequest->getURI()
+ )
+ );
+
+ if ($this->signature != $signature) {
+
+ $this->errorCode = self::ERR_INVALIDSIGNATURE;
+ return false;
+
+ }
+
+ return true;
+
+ }
+
+
+ /**
+ * Returns an HTTP 401 header, forcing login
+ *
+ * This should be called when username and password are incorrect, or not supplied at all
+ *
+ * @return void
+ */
+ public function requireLogin() {
+
+ $this->httpResponse->setHeader('WWW-Authenticate','AWS');
+ $this->httpResponse->sendStatus(401);
+
+ }
+
+ /**
+ * Makes sure the supplied value is a valid RFC2616 date.
+ *
+ * If we would just use strtotime to get a valid timestamp, we have no way of checking if a
+ * user just supplied the word 'now' for the date header.
+ *
+ * This function also makes sure the Date header is within 15 minutes of the operating
+ * system date, to prevent replay attacks.
+ *
+ * @param string $dateHeader
+ * @return bool
+ */
+ protected function validateRFC2616Date($dateHeader) {
+
+ $date = Util::parseHTTPDate($dateHeader);
+
+ // Unknown format
+ if (!$date) {
+ $this->errorCode = self::ERR_INVALIDDATEFORMAT;
+ return false;
+ }
+
+ $min = new \DateTime('-15 minutes');
+ $max = new \DateTime('+15 minutes');
+
+ // We allow 15 minutes around the current date/time
+ if ($date > $max || $date < $min) {
+ $this->errorCode = self::ERR_REQUESTTIMESKEWED;
+ return false;
+ }
+
+ return $date;
+
+ }
+
+ /**
+ * Returns a list of AMZ headers
+ *
+ * @return string
+ */
+ protected function getAmzHeaders() {
+
+ $amzHeaders = array();
+ $headers = $this->httpRequest->getHeaders();
+ foreach($headers as $headerName => $headerValue) {
+ if (strpos(strtolower($headerName),'x-amz-')===0) {
+ $amzHeaders[strtolower($headerName)] = str_replace(array("\r\n"),array(' '),$headerValue) . "\n";
+ }
+ }
+ ksort($amzHeaders);
+
+ $headerStr = '';
+ foreach($amzHeaders as $h=>$v) {
+ $headerStr.=$h.':'.$v;
+ }
+
+ return $headerStr;
+
+ }
+
+ /**
+ * Generates an HMAC-SHA1 signature
+ *
+ * @param string $key
+ * @param string $message
+ * @return string
+ */
+ private function hmacsha1($key, $message) {
+
+ $blocksize=64;
+ if (strlen($key)>$blocksize)
+ $key=pack('H*', sha1($key));
+ $key=str_pad($key,$blocksize,chr(0x00));
+ $ipad=str_repeat(chr(0x36),$blocksize);
+ $opad=str_repeat(chr(0x5c),$blocksize);
+ $hmac = pack('H*',sha1(($key^$opad).pack('H*',sha1(($key^$ipad).$message))));
+ return $hmac;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/AbstractAuth.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/AbstractAuth.php
new file mode 100644
index 0000000..0db2983
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/AbstractAuth.php
@@ -0,0 +1,111 @@
+httpResponse = new Response();
+ $this->httpRequest = new Request();
+
+ }
+
+ /**
+ * Sets an alternative HTTP response object
+ *
+ * @param Response $response
+ * @return void
+ */
+ public function setHTTPResponse(Response $response) {
+
+ $this->httpResponse = $response;
+
+ }
+
+ /**
+ * Sets an alternative HTTP request object
+ *
+ * @param Request $request
+ * @return void
+ */
+ public function setHTTPRequest(Request $request) {
+
+ $this->httpRequest = $request;
+
+ }
+
+
+ /**
+ * Sets the realm
+ *
+ * The realm is often displayed in authentication dialog boxes
+ * Commonly an application name displayed here
+ *
+ * @param string $realm
+ * @return void
+ */
+ public function setRealm($realm) {
+
+ $this->realm = $realm;
+
+ }
+
+ /**
+ * Returns the realm
+ *
+ * @return string
+ */
+ public function getRealm() {
+
+ return $this->realm;
+
+ }
+
+ /**
+ * Returns an HTTP 401 header, forcing login
+ *
+ * This should be called when username and password are incorrect, or not supplied at all
+ *
+ * @return void
+ */
+ abstract public function requireLogin();
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/BasicAuth.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/BasicAuth.php
new file mode 100644
index 0000000..bcb087e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/BasicAuth.php
@@ -0,0 +1,67 @@
+httpRequest->getRawServerValue('PHP_AUTH_USER')) && ($pass = $this->httpRequest->getRawServerValue('PHP_AUTH_PW'))) {
+
+ return array($user,$pass);
+
+ }
+
+ // Most other webservers
+ $auth = $this->httpRequest->getHeader('Authorization');
+
+ // Apache could prefix environment variables with REDIRECT_ when urls
+ // are passed through mod_rewrite
+ if (!$auth) {
+ $auth = $this->httpRequest->getRawServerValue('REDIRECT_HTTP_AUTHORIZATION');
+ }
+
+ if (!$auth) return false;
+
+ if (strpos(strtolower($auth),'basic')!==0) return false;
+
+ return explode(':', base64_decode(substr($auth, 6)),2);
+
+ }
+
+ /**
+ * Returns an HTTP 401 header, forcing login
+ *
+ * This should be called when username and password are incorrect, or not supplied at all
+ *
+ * @return void
+ */
+ public function requireLogin() {
+
+ $this->httpResponse->setHeader('WWW-Authenticate','Basic realm="' . $this->realm . '"');
+ $this->httpResponse->sendStatus(401);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/DigestAuth.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/DigestAuth.php
new file mode 100644
index 0000000..62310f7
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/DigestAuth.php
@@ -0,0 +1,240 @@
+nonce = uniqid();
+ $this->opaque = md5($this->realm);
+ parent::__construct();
+
+ }
+
+ /**
+ * Gathers all information from the headers
+ *
+ * This method needs to be called prior to anything else.
+ *
+ * @return void
+ */
+ public function init() {
+
+ $digest = $this->getDigest();
+ $this->digestParts = $this->parseDigest($digest);
+
+ }
+
+ /**
+ * Sets the quality of protection value.
+ *
+ * Possible values are:
+ * SabreForRainLoop\HTTP\DigestAuth::QOP_AUTH
+ * SabreForRainLoop\HTTP\DigestAuth::QOP_AUTHINT
+ *
+ * Multiple values can be specified using logical OR.
+ *
+ * QOP_AUTHINT ensures integrity of the request body, but this is not
+ * supported by most HTTP clients. QOP_AUTHINT also requires the entire
+ * request body to be md5'ed, which can put strains on CPU and memory.
+ *
+ * @param int $qop
+ * @return void
+ */
+ public function setQOP($qop) {
+
+ $this->qop = $qop;
+
+ }
+
+ /**
+ * Validates the user.
+ *
+ * The A1 parameter should be md5($username . ':' . $realm . ':' . $password);
+ *
+ * @param string $A1
+ * @return bool
+ */
+ public function validateA1($A1) {
+
+ $this->A1 = $A1;
+ return $this->validate();
+
+ }
+
+ /**
+ * Validates authentication through a password. The actual password must be provided here.
+ * It is strongly recommended not store the password in plain-text and use validateA1 instead.
+ *
+ * @param string $password
+ * @return bool
+ */
+ public function validatePassword($password) {
+
+ $this->A1 = md5($this->digestParts['username'] . ':' . $this->realm . ':' . $password);
+ return $this->validate();
+
+ }
+
+ /**
+ * Returns the username for the request
+ *
+ * @return string
+ */
+ public function getUsername() {
+
+ return $this->digestParts['username'];
+
+ }
+
+ /**
+ * Validates the digest challenge
+ *
+ * @return bool
+ */
+ protected function validate() {
+
+ $A2 = $this->httpRequest->getMethod() . ':' . $this->digestParts['uri'];
+
+ if ($this->digestParts['qop']=='auth-int') {
+ // Making sure we support this qop value
+ if (!($this->qop & self::QOP_AUTHINT)) return false;
+ // We need to add an md5 of the entire request body to the A2 part of the hash
+ $body = $this->httpRequest->getBody(true);
+ $this->httpRequest->setBody($body,true);
+ $A2 .= ':' . md5($body);
+ } else {
+
+ // We need to make sure we support this qop value
+ if (!($this->qop & self::QOP_AUTH)) return false;
+ }
+
+ $A2 = md5($A2);
+
+ $validResponse = md5("{$this->A1}:{$this->digestParts['nonce']}:{$this->digestParts['nc']}:{$this->digestParts['cnonce']}:{$this->digestParts['qop']}:{$A2}");
+
+ return $this->digestParts['response']==$validResponse;
+
+
+ }
+
+ /**
+ * Returns an HTTP 401 header, forcing login
+ *
+ * This should be called when username and password are incorrect, or not supplied at all
+ *
+ * @return void
+ */
+ public function requireLogin() {
+
+ $qop = '';
+ switch($this->qop) {
+ case self::QOP_AUTH : $qop = 'auth'; break;
+ case self::QOP_AUTHINT : $qop = 'auth-int'; break;
+ case self::QOP_AUTH | self::QOP_AUTHINT : $qop = 'auth,auth-int'; break;
+ }
+
+ $this->httpResponse->setHeader('WWW-Authenticate','Digest realm="' . $this->realm . '",qop="'.$qop.'",nonce="' . $this->nonce . '",opaque="' . $this->opaque . '"');
+ $this->httpResponse->sendStatus(401);
+
+ }
+
+
+ /**
+ * This method returns the full digest string.
+ *
+ * It should be compatibile with mod_php format and other webservers.
+ *
+ * If the header could not be found, null will be returned
+ *
+ * @return mixed
+ */
+ public function getDigest() {
+
+ // mod_php
+ $digest = $this->httpRequest->getRawServerValue('PHP_AUTH_DIGEST');
+ if ($digest) return $digest;
+
+ // most other servers
+ $digest = $this->httpRequest->getHeader('Authorization');
+
+ // Apache could prefix environment variables with REDIRECT_ when urls
+ // are passed through mod_rewrite
+ if (!$digest) {
+ $digest = $this->httpRequest->getRawServerValue('REDIRECT_HTTP_AUTHORIZATION');
+ }
+
+ if ($digest && strpos(strtolower($digest),'digest')===0) {
+ return substr($digest,7);
+ } else {
+ return null;
+ }
+
+ }
+
+
+ /**
+ * Parses the different pieces of the digest string into an array.
+ *
+ * This method returns false if an incomplete digest was supplied
+ *
+ * @param string $digest
+ * @return mixed
+ */
+ protected function parseDigest($digest) {
+
+ // protect against missing data
+ $needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
+ $data = array();
+
+ preg_match_all('@(\w+)=(?:(?:")([^"]+)"|([^\s,$]+))@', $digest, $matches, PREG_SET_ORDER);
+
+ foreach ($matches as $m) {
+ $data[$m[1]] = $m[2] ? $m[2] : $m[3];
+ unset($needed_parts[$m[1]]);
+ }
+
+ return $needed_parts ? false : $data;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/Request.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/Request.php
new file mode 100644
index 0000000..3942af8
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/Request.php
@@ -0,0 +1,284 @@
+_SERVER = $serverData;
+ else $this->_SERVER =& $_SERVER;
+
+ if ($postData) $this->_POST = $postData;
+ else $this->_POST =& $_POST;
+
+ }
+
+ /**
+ * Returns the value for a specific http header.
+ *
+ * This method returns null if the header did not exist.
+ *
+ * @param string $name
+ * @return string
+ */
+ public function getHeader($name) {
+
+ $name = strtoupper(str_replace(array('-'),array('_'),$name));
+ if (isset($this->_SERVER['HTTP_' . $name])) {
+ return $this->_SERVER['HTTP_' . $name];
+ }
+
+ // There's a few headers that seem to end up in the top-level
+ // server array.
+ switch($name) {
+ case 'CONTENT_TYPE' :
+ case 'CONTENT_LENGTH' :
+ if (isset($this->_SERVER[$name])) {
+ return $this->_SERVER[$name];
+ }
+ break;
+
+ }
+ return;
+
+ }
+
+ /**
+ * Returns all (known) HTTP headers.
+ *
+ * All headers are converted to lower-case, and additionally all underscores
+ * are automatically converted to dashes
+ *
+ * @return array
+ */
+ public function getHeaders() {
+
+ $hdrs = array();
+ foreach($this->_SERVER as $key=>$value) {
+
+ switch($key) {
+ case 'CONTENT_LENGTH' :
+ case 'CONTENT_TYPE' :
+ $hdrs[strtolower(str_replace('_','-',$key))] = $value;
+ break;
+ default :
+ if (strpos($key,'HTTP_')===0) {
+ $hdrs[substr(strtolower(str_replace('_','-',$key)),5)] = $value;
+ }
+ break;
+ }
+
+ }
+
+ return $hdrs;
+
+ }
+
+ /**
+ * Returns the HTTP request method
+ *
+ * This is for example POST or GET
+ *
+ * @return string
+ */
+ public function getMethod() {
+
+ return $this->_SERVER['REQUEST_METHOD'];
+
+ }
+
+ /**
+ * Returns the requested uri
+ *
+ * @return string
+ */
+ public function getUri() {
+
+ return $this->_SERVER['REQUEST_URI'];
+
+ }
+
+ /**
+ * Will return protocol + the hostname + the uri
+ *
+ * @return string
+ */
+ public function getAbsoluteUri() {
+
+ // Checking if the request was made through HTTPS. The last in line is for IIS
+ $protocol = isset($this->_SERVER['HTTPS']) && ($this->_SERVER['HTTPS']) && ($this->_SERVER['HTTPS']!='off');
+ return ($protocol?'https':'http') . '://' . $this->getHeader('Host') . $this->getUri();
+
+ }
+
+ /**
+ * Returns everything after the ? from the current url
+ *
+ * @return string
+ */
+ public function getQueryString() {
+
+ return isset($this->_SERVER['QUERY_STRING'])?$this->_SERVER['QUERY_STRING']:'';
+
+ }
+
+ /**
+ * Returns the HTTP request body body
+ *
+ * This method returns a readable stream resource.
+ * If the asString parameter is set to true, a string is sent instead.
+ *
+ * @param bool $asString
+ * @return resource
+ */
+ public function getBody($asString = false) {
+
+ if (is_null($this->body)) {
+ if (!is_null(self::$defaultInputStream)) {
+ $this->body = self::$defaultInputStream;
+ } else {
+ $this->body = fopen('php://input','r');
+ self::$defaultInputStream = $this->body;
+ }
+ }
+ if ($asString) {
+ $body = stream_get_contents($this->body);
+ return $body;
+ } else {
+ return $this->body;
+ }
+
+ }
+
+ /**
+ * Sets the contents of the HTTP request body
+ *
+ * This method can either accept a string, or a readable stream resource.
+ *
+ * If the setAsDefaultInputStream is set to true, it means for this run of the
+ * script the supplied body will be used instead of php://input.
+ *
+ * @param mixed $body
+ * @param bool $setAsDefaultInputStream
+ * @return void
+ */
+ public function setBody($body,$setAsDefaultInputStream = false) {
+
+ if(is_resource($body)) {
+ $this->body = $body;
+ } else {
+
+ $stream = fopen('php://temp','r+');
+ fputs($stream,$body);
+ rewind($stream);
+ // String is assumed
+ $this->body = $stream;
+ }
+ if ($setAsDefaultInputStream) {
+ self::$defaultInputStream = $this->body;
+ }
+
+ }
+
+ /**
+ * Returns PHP's _POST variable.
+ *
+ * The reason this is in a method is so it can be subclassed and
+ * overridden.
+ *
+ * @return array
+ */
+ public function getPostVars() {
+
+ return $this->_POST;
+
+ }
+
+ /**
+ * Returns a specific item from the _SERVER array.
+ *
+ * Do not rely on this feature, it is for internal use only.
+ *
+ * @param string $field
+ * @return string
+ */
+ public function getRawServerValue($field) {
+
+ return isset($this->_SERVER[$field])?$this->_SERVER[$field]:null;
+
+ }
+
+ /**
+ * Returns the HTTP version specified within the request.
+ *
+ * @return string
+ */
+ public function getHTTPVersion() {
+
+ $protocol = $this->getRawServerValue('SERVER_PROTOCOL');
+ if ($protocol==='HTTP/1.0') {
+ return '1.0';
+ } else {
+ return '1.1';
+ }
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/Response.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/Response.php
new file mode 100644
index 0000000..cb4b9da
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/Response.php
@@ -0,0 +1,175 @@
+ 'Continue',
+ 101 => 'Switching Protocols',
+ 102 => 'Processing',
+ 200 => 'OK',
+ 201 => 'Created',
+ 202 => 'Accepted',
+ 203 => 'Non-Authorative Information',
+ 204 => 'No Content',
+ 205 => 'Reset Content',
+ 206 => 'Partial Content',
+ 207 => 'Multi-Status', // RFC 4918
+ 208 => 'Already Reported', // RFC 5842
+ 226 => 'IM Used', // RFC 3229
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 306 => 'Reserved',
+ 307 => 'Temporary Redirect',
+ 400 => 'Bad request',
+ 401 => 'Unauthorized',
+ 402 => 'Payment Required',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 405 => 'Method Not Allowed',
+ 406 => 'Not Acceptable',
+ 407 => 'Proxy Authentication Required',
+ 408 => 'Request Timeout',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Long',
+ 415 => 'Unsupported Media Type',
+ 416 => 'Requested Range Not Satisfiable',
+ 417 => 'Expectation Failed',
+ 418 => 'I\'m a teapot', // RFC 2324
+ 422 => 'Unprocessable Entity', // RFC 4918
+ 423 => 'Locked', // RFC 4918
+ 424 => 'Failed Dependency', // RFC 4918
+ 426 => 'Upgrade required',
+ 428 => 'Precondition required', // draft-nottingham-http-new-status
+ 429 => 'Too Many Requests', // draft-nottingham-http-new-status
+ 431 => 'Request Header Fields Too Large', // draft-nottingham-http-new-status
+ 500 => 'Internal Server Error',
+ 501 => 'Not Implemented',
+ 502 => 'Bad Gateway',
+ 503 => 'Service Unavailable',
+ 504 => 'Gateway Timeout',
+ 505 => 'HTTP Version not supported',
+ 506 => 'Variant Also Negotiates',
+ 507 => 'Insufficient Storage', // RFC 4918
+ 508 => 'Loop Detected', // RFC 5842
+ 509 => 'Bandwidth Limit Exceeded', // non-standard
+ 510 => 'Not extended',
+ 511 => 'Network Authentication Required', // draft-nottingham-http-new-status
+ );
+
+ return 'HTTP/' . $httpVersion . ' ' . $code . ' ' . $msg[$code];
+
+ }
+
+ // @codeCoverageIgnoreStart
+ // We cannot reasonably test header() related methods.
+
+ /**
+ * Sends an HTTP status header to the client.
+ *
+ * @param int $code HTTP status code
+ * @return bool
+ */
+ public function sendStatus($code) {
+
+ if (!headers_sent())
+ return header($this->getStatusMessage($code, $this->defaultHttpVersion));
+ else return false;
+
+ }
+
+ /**
+ * Sets an HTTP header for the response
+ *
+ * @param string $name
+ * @param string $value
+ * @param bool $replace
+ * @return bool
+ */
+ public function setHeader($name, $value, $replace = true) {
+
+ $value = str_replace(array("\r","\n"),array('\r','\n'),$value);
+ if (!headers_sent())
+ return header($name . ': ' . $value, $replace);
+ else return false;
+
+
+ }
+ // @codeCoverageIgnoreEnd
+
+ /**
+ * Sets a bunch of HTTP Headers
+ *
+ * headersnames are specified as keys, value in the array value
+ *
+ * @param array $headers
+ * @return void
+ */
+ public function setHeaders(array $headers) {
+
+ foreach($headers as $key=>$value)
+ $this->setHeader($key, $value);
+
+ }
+
+ /**
+ * Sends the entire response body
+ *
+ * This method can accept either an open filestream, or a string.
+ *
+ * @param mixed $body
+ * @return void
+ */
+ public function sendBody($body) {
+
+ if (is_resource($body)) {
+
+ fpassthru($body);
+
+ } else {
+
+ // We assume a string
+ echo $body;
+
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/Util.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/Util.php
new file mode 100644
index 0000000..e308618
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/Util.php
@@ -0,0 +1,82 @@
+= 0)
+ return new \DateTime('@' . $realDate, new \DateTimeZone('UTC'));
+
+ }
+
+ /**
+ * Transforms a DateTime object to HTTP's most common date format.
+ *
+ * We're serializing it as the RFC 1123 date, which, for HTTP must be
+ * specified as GMT.
+ *
+ * @param \DateTime $dateTime
+ * @return string
+ */
+ static function toHTTPDate(\DateTime $dateTime) {
+
+ // We need to clone it, as we don't want to affect the existing
+ // DateTime.
+ $dateTime = clone $dateTime;
+ $dateTime->setTimeZone(new \DateTimeZone('GMT'));
+ return $dateTime->format('D, d M Y H:i:s \G\M\T');
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/Version.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/Version.php
new file mode 100644
index 0000000..c14bd03
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/HTTP/Version.php
@@ -0,0 +1,24 @@
+stderr) {
+ $this->stderr = STDERR;
+ }
+ if (!$this->stdout) {
+ $this->stdout = STDOUT;
+ }
+ if (!$this->stdin) {
+ $this->stdin = STDIN;
+ }
+
+ // @codeCoverageIgnoreEnd
+
+
+ try {
+
+ list($options, $positional) = $this->parseArguments($argv);
+
+ if (isset($options['q'])) {
+ $this->quiet = true;
+ }
+ $this->log($this->colorize('green', "sabre-vobject ") . $this->colorize('yellow', Version::VERSION));
+
+ foreach($options as $name=>$value) {
+
+ switch($name) {
+
+ case 'q' :
+ // Already handled earlier.
+ break;
+ case 'h' :
+ case 'help' :
+ $this->showHelp();
+ return 0;
+ break;
+ case 'format' :
+ switch($value) {
+
+ // jcard/jcal documents
+ case 'jcard' :
+ case 'jcal' :
+
+ // specific document versions
+ case 'vcard21' :
+ case 'vcard30' :
+ case 'vcard40' :
+ case 'icalendar20' :
+
+ // specific formats
+ case 'json' :
+ case 'mimedir' :
+
+ // icalendar/vcad
+ case 'icalendar' :
+ case 'vcard' :
+ $this->format = $value;
+ break;
+
+ default :
+ throw new InvalidArgumentException('Unknown format: ' . $value);
+
+ }
+ break;
+ case 'pretty' :
+ if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
+ $this->pretty = true;
+ }
+ break;
+ case 'forgiving' :
+ $this->forgiving = true;
+ break;
+ case 'inputformat' :
+ switch($value) {
+ // json formats
+ case 'jcard' :
+ case 'jcal' :
+ case 'json' :
+ $this->inputFormat = 'json';
+ break;
+
+ // mimedir formats
+ case 'mimedir' :
+ case 'icalendar' :
+ case 'vcard' :
+ case 'vcard21' :
+ case 'vcard30' :
+ case 'vcard40' :
+ case 'icalendar20' :
+
+ $this->inputFormat = 'mimedir';
+ break;
+
+ default :
+ throw new InvalidArgumentException('Unknown format: ' . $value);
+
+ }
+ break;
+ default :
+ throw new InvalidArgumentException('Unknown option: ' . $name);
+
+ }
+
+ }
+
+ if (count($positional) === 0) {
+ $this->showHelp();
+ return 1;
+ }
+
+ if (count($positional) === 1) {
+ throw new InvalidArgumentException('Inputfile is a required argument');
+ }
+
+ if (count($positional) > 3) {
+ throw new InvalidArgumentException('Too many arguments');
+ }
+
+ if (!in_array($positional[0], array('validate','repair','convert','color'))) {
+ throw new InvalidArgumentException('Uknown command: ' . $positional[0]);
+ }
+
+ } catch (InvalidArgumentException $e) {
+ $this->showHelp();
+ $this->log('Error: ' . $e->getMessage(),'red');
+ return 1;
+ }
+
+ $command = $positional[0];
+
+ $this->inputPath = $positional[1];
+ $this->outputPath = isset($positional[2])?$positional[2]:'-';
+
+ if ($this->outputPath !== '-') {
+ $this->stdout = fopen($this->outputPath,'w');
+ }
+
+ if (!$this->inputFormat) {
+ if (substr($this->inputPath,-5)==='.json') {
+ $this->inputFormat = 'json';
+ } else {
+ $this->inputFormat = 'mimedir';
+ }
+ }
+ if (!$this->format) {
+ if (substr($this->outputPath,-5)==='.json') {
+ $this->format = 'json';
+ } else {
+ $this->format = 'mimedir';
+ }
+ }
+
+
+ $realCode = 0;
+
+ try {
+
+ while($input = $this->readInput()) {
+
+ $returnCode = $this->$command($input);
+ if ($returnCode!==0) $realCode = $returnCode;
+
+ }
+
+ } catch (EofException $e) {
+ // end of file
+ } catch (\Exception $e) {
+ $this->log('Error: ' . $e->getMessage(),'red');
+ return 2;
+ }
+
+ return $realCode;
+
+ }
+
+ /**
+ * Shows the help message.
+ *
+ * @return void
+ */
+ protected function showHelp() {
+
+ $this->log('Usage:', 'yellow');
+ $this->log(" vobject [options] command [arguments]");
+ $this->log('');
+ $this->log('Options:', 'yellow');
+ $this->log($this->colorize('green', ' -q ') . "Don't output anything.");
+ $this->log($this->colorize('green', ' -help -h ') . "Display this help message.");
+ $this->log($this->colorize('green', ' --format ') . "Convert to a specific format. Must be one of: vcard, vcard21,");
+ $this->log($this->colorize('green', ' --forgiving ') . "Makes the parser less strict.");
+ $this->log(" vcard30, vcard40, icalendar20, jcal, jcard, json, mimedir.");
+ $this->log($this->colorize('green', ' --inputformat ') . "If the input format cannot be guessed from the extension, it");
+ $this->log(" must be specified here.");
+ // Only PHP 5.4 and up
+ if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
+ $this->log($this->colorize('green', ' --pretty ') . "json pretty-print.");
+ }
+ $this->log('');
+ $this->log('Commands:', 'yellow');
+ $this->log($this->colorize('green', ' validate') . ' source_file Validates a file for correctness.');
+ $this->log($this->colorize('green', ' repair') . ' source_file [output_file] Repairs a file.');
+ $this->log($this->colorize('green', ' convert') . ' source_file [output_file] Converts a file.');
+ $this->log($this->colorize('green', ' color') . ' source_file Colorize a file, useful for debbugging.');
+ $this->log(<<log('Examples:', 'yellow');
+ $this->log(' vobject convert contact.vcf contact.json');
+ $this->log(' vobject convert --format=vcard40 old.vcf new.vcf');
+ $this->log(' vobject convert --inputformat=json --format=mimedir - -');
+ $this->log(' vobject color calendar.ics');
+ $this->log('');
+ $this->log('https://github.com/fruux/sabre-vobject','purple');
+
+ }
+
+ /**
+ * Validates a VObject file
+ *
+ * @param Component $vObj
+ * @return int
+ */
+ protected function validate($vObj) {
+
+ $returnCode = 0;
+
+ switch($vObj->name) {
+ case 'VCALENDAR' :
+ $this->log("iCalendar: " . (string)$vObj->VERSION);
+ break;
+ case 'VCARD' :
+ $this->log("vCard: " . (string)$vObj->VERSION);
+ break;
+ }
+
+ $warnings = $vObj->validate();
+ if (!count($warnings)) {
+ $this->log(" No warnings!");
+ } else {
+
+ $returnCode = 2;
+ foreach($warnings as $warn) {
+
+ $this->log(" " . $warn['message']);
+
+ }
+
+ }
+
+ return $returnCode;
+
+ }
+
+ /**
+ * Repairs a VObject file
+ *
+ * @param Component $vObj
+ * @return int
+ */
+ protected function repair($vObj) {
+
+ $returnCode = 0;
+
+ switch($vObj->name) {
+ case 'VCALENDAR' :
+ $this->log("iCalendar: " . (string)$vObj->VERSION);
+ break;
+ case 'VCARD' :
+ $this->log("vCard: " . (string)$vObj->VERSION);
+ break;
+ }
+
+ $warnings = $vObj->validate(Node::REPAIR);
+ if (!count($warnings)) {
+ $this->log(" No warnings!");
+ } else {
+ foreach($warnings as $warn) {
+
+ $returnCode = 2;
+ $this->log(" " . $warn['message']);
+
+ }
+
+ }
+ fwrite($this->stdout, $vObj->serialize());
+
+ return $returnCode;
+
+ }
+
+ /**
+ * Converts a vObject file to a new format.
+ *
+ * @param Component $vObj
+ * @return int
+ */
+ protected function convert($vObj) {
+
+ $json = false;
+ $convertVersion = null;
+ $forceInput = null;
+
+ switch($this->format) {
+ case 'json' :
+ $json = true;
+ if ($vObj->name === 'VCARD') {
+ $convertVersion = Document::VCARD40;
+ }
+ break;
+ case 'jcard' :
+ $json = true;
+ $forceInput = 'VCARD';
+ $convertVersion = Document::VCARD40;
+ break;
+ case 'jcal' :
+ $json = true;
+ $forceInput = 'VCALENDAR';
+ break;
+ case 'mimedir' :
+ case 'icalendar' :
+ case 'icalendar20' :
+ case 'vcard' :
+ break;
+ case 'vcard21' :
+ $convertVersion = Document::VCARD21;
+ break;
+ case 'vcard30' :
+ $convertVersion = Document::VCARD30;
+ break;
+ case 'vcard40' :
+ $convertVersion = Document::VCARD40;
+ break;
+
+ }
+
+ if ($forceInput && $vObj->name !== $forceInput) {
+ throw new \Exception('You cannot convert a ' . strtolower($vObj->name) . ' to ' . $this->format);
+ }
+ if ($convertVersion) {
+ $vObj = $vObj->convert($convertVersion);
+ }
+ if ($json) {
+ $jsonOptions = 0;
+ if ($this->pretty) {
+ $jsonOptions = JSON_PRETTY_PRINT;
+ }
+ fwrite($this->stdout, json_encode($vObj->jsonSerialize(), $jsonOptions));
+ } else {
+ fwrite($this->stdout, $vObj->serialize());
+ }
+
+ return 0;
+
+ }
+
+ /**
+ * Colorizes a file
+ *
+ * @param Component $vObj
+ * @return int
+ */
+ protected function color($vObj) {
+
+ fwrite($this->stdout, $this->serializeComponent($vObj));
+
+ }
+
+ /**
+ * Returns an ansi color string for a color name.
+ *
+ * @param string $color
+ * @return string
+ */
+ protected function colorize($color, $str, $resetTo = 'default') {
+
+ $colors = array(
+ 'cyan' => '1;36',
+ 'red' => '1;31',
+ 'yellow' => '1;33',
+ 'blue' => '0;34',
+ 'green' => '0;32',
+ 'default' => '0',
+ 'purple' => '0;35',
+ );
+ return "\033[" . $colors[$color] . 'm' . $str . "\033[".$colors[$resetTo]."m";
+
+ }
+
+ /**
+ * Writes out a string in specific color.
+ *
+ * @param string $color
+ * @param string $str
+ * @return void
+ */
+ protected function cWrite($color, $str) {
+
+ fwrite($this->stdout, $this->colorize($color, $str));
+
+ }
+
+ protected function serializeComponent(Component $vObj) {
+
+ $this->cWrite('cyan', 'BEGIN');
+ $this->cWrite('red', ':');
+ $this->cWrite('yellow', $vObj->name . "\n");
+
+ /**
+ * Gives a component a 'score' for sorting purposes.
+ *
+ * This is solely used by the childrenSort method.
+ *
+ * A higher score means the item will be lower in the list.
+ * To avoid score collisions, each "score category" has a reasonable
+ * space to accomodate elements. The $key is added to the $score to
+ * preserve the original relative order of elements.
+ *
+ * @param int $key
+ * @param array $array
+ * @return int
+ */
+ $sortScore = function($key, $array) {
+
+ if ($array[$key] instanceof Component) {
+
+ // We want to encode VTIMEZONE first, this is a personal
+ // preference.
+ if ($array[$key]->name === 'VTIMEZONE') {
+ $score=300000000;
+ return $score+$key;
+ } else {
+ $score=400000000;
+ return $score+$key;
+ }
+ } else {
+ // Properties get encoded first
+ // VCARD version 4.0 wants the VERSION property to appear first
+ if ($array[$key] instanceof Property) {
+ if ($array[$key]->name === 'VERSION') {
+ $score=100000000;
+ return $score+$key;
+ } else {
+ // All other properties
+ $score=200000000;
+ return $score+$key;
+ }
+ }
+ }
+
+ };
+
+ $tmp = $vObj->children;
+ uksort($vObj->children, function($a, $b) use ($sortScore, $tmp) {
+
+ $sA = $sortScore($a, $tmp);
+ $sB = $sortScore($b, $tmp);
+
+ return $sA - $sB;
+
+ });
+
+ foreach($vObj->children as $child) {
+ if ($child instanceof Component) {
+ $this->serializeComponent($child);
+ } else {
+ $this->serializeProperty($child);
+ }
+ }
+
+ $this->cWrite('cyan', 'END');
+ $this->cWrite('red', ':');
+ $this->cWrite('yellow', $vObj->name . "\n");
+
+ }
+
+ /**
+ * Colorizes a property.
+ *
+ * @param Property $property
+ * @return void
+ */
+ protected function serializeProperty(Property $property) {
+
+ if ($property->group) {
+ $this->cWrite('default', $property->group);
+ $this->cWrite('red', '.');
+ }
+
+ $str = '';
+ $this->cWrite('yellow', $property->name);
+
+ foreach($property->parameters as $param) {
+
+ $this->cWrite('red',';');
+ $this->cWrite('blue', $param->serialize());
+
+ }
+ $this->cWrite('red',':');
+
+ if ($property instanceof Property\Binary) {
+
+ $this->cWrite('default', 'embedded binary stripped. (' . strlen($property->getValue()) . ' bytes)');
+
+ } else {
+
+ $parts = $property->getParts();
+ $first1 = true;
+ // Looping through property values
+ foreach($parts as $part) {
+ if ($first1) {
+ $first1 = false;
+ } else {
+ $this->cWrite('red', $property->delimiter);
+ }
+ $first2 = true;
+ // Looping through property sub-values
+ foreach((array)$part as $subPart) {
+ if ($first2) {
+ $first2 = false;
+ } else {
+ // The sub-value delimiter is always comma
+ $this->cWrite('red', ',');
+ }
+
+ $subPart = strtr($subPart, array(
+ '\\' => $this->colorize('purple', '\\\\', 'green'),
+ ';' => $this->colorize('purple', '\;', 'green'),
+ ',' => $this->colorize('purple', '\,', 'green'),
+ "\n" => $this->colorize('purple', "\\n\n\t", 'green'),
+ "\r" => "",
+ ));
+
+ $this->cWrite('green', $subPart);
+ }
+ }
+
+ }
+ $this->cWrite("default", "\n");
+
+ }
+
+ /**
+ * Parses the list of arguments.
+ *
+ * @param array $argv
+ * @return void
+ */
+ protected function parseArguments(array $argv) {
+
+ $positional = array();
+ $options = array();
+
+ for($ii=0; $ii < count($argv); $ii++) {
+
+ // Skipping the first argument.
+ if ($ii===0) continue;
+
+ $v = $argv[$ii];
+
+ if (substr($v,0,2)==='--') {
+ // This is a long-form option.
+ $optionName = substr($v,2);
+ $optionValue = true;
+ if (strpos($optionName,'=')) {
+ list($optionName, $optionValue) = explode('=', $optionName);
+ }
+ $options[$optionName] = $optionValue;
+ } elseif (substr($v,0,1) === '-' && strlen($v)>1) {
+ // This is a short-form option.
+ foreach(str_split(substr($v,1)) as $option) {
+ $options[$option] = true;
+ }
+
+ } else {
+
+ $positional[] = $v;
+
+ }
+
+ }
+
+ return array($options, $positional);
+
+ }
+
+ protected $parser;
+
+ /**
+ * Reads the input file
+ *
+ * @return Component
+ */
+ protected function readInput() {
+
+ if (!$this->parser) {
+ if ($this->inputPath!=='-') {
+ $this->stdin = fopen($this->inputPath,'r');
+ }
+
+ if ($this->inputFormat === 'mimedir') {
+ $this->parser = new Parser\MimeDir($this->stdin, ($this->forgiving?Reader::OPTION_FORGIVING:0));
+ } else {
+ $this->parser = new Parser\Json($this->stdin, ($this->forgiving?Reader::OPTION_FORGIVING:0));
+ }
+ }
+
+ return $this->parser->parse();
+
+ }
+
+ /**
+ * Sends a message to STDERR.
+ *
+ * @param string $msg
+ * @return void
+ */
+ protected function log($msg, $color = 'default') {
+
+ if (!$this->quiet) {
+ if ($color!=='default') {
+ $msg = $this->colorize($color, $msg);
+ }
+ fwrite($this->stderr, $msg . "\n");
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component.php
new file mode 100644
index 0000000..70cf550
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component.php
@@ -0,0 +1,473 @@
+value syntax, in which case
+ * properties will automatically be created, or you can just pass a list of
+ * Component and Property object.
+ *
+ * By default, a set of sensible values will be added to the component. For
+ * an iCalendar object, this may be something like CALSCALE:GREGORIAN. To
+ * ensure that this does not happen, set $defaults to false.
+ *
+ * @param Document $root
+ * @param string $name such as VCALENDAR, VEVENT.
+ * @param array $children
+ * @param bool $defaults
+ * @return void
+ */
+ public function __construct(Document $root, $name, array $children = array(), $defaults = true) {
+
+ $this->name = strtoupper($name);
+ $this->root = $root;
+
+ if ($defaults) {
+ $children = array_merge($this->getDefaults(), $children);
+ }
+
+ foreach($children as $k=>$child) {
+ if ($child instanceof Node) {
+
+ // Component or Property
+ $this->add($child);
+ } else {
+
+ // Property key=>value
+ $this->add($k, $child);
+ }
+ }
+
+ }
+
+ /**
+ * Adds a new property or component, and returns the new item.
+ *
+ * This method has 3 possible signatures:
+ *
+ * add(Component $comp) // Adds a new component
+ * add(Property $prop) // Adds a new property
+ * add($name, $value, array $parameters = array()) // Adds a new property
+ * add($name, array $children = array()) // Adds a new component
+ * by name.
+ *
+ * @return Node
+ */
+ public function add($a1, $a2 = null, $a3 = null) {
+
+ if ($a1 instanceof Node) {
+ if (!is_null($a2)) {
+ throw new \InvalidArgumentException('The second argument must not be specified, when passing a VObject Node');
+ }
+ $a1->parent = $this;
+ $this->children[] = $a1;
+
+ return $a1;
+
+ } elseif(is_string($a1)) {
+
+ $item = $this->root->create($a1, $a2, $a3);
+ $item->parent = $this;
+ $this->children[] = $item;
+
+ return $item;
+
+ } else {
+
+ throw new \InvalidArgumentException('The first argument must either be a \\SabreForRainLoop\\VObject\\Node or a string');
+
+ }
+
+ }
+
+ /**
+ * This method removes a component or property from this component.
+ *
+ * You can either specify the item by name (like DTSTART), in which case
+ * all properties/components with that name will be removed, or you can
+ * pass an instance of a property or component, in which case only that
+ * exact item will be removed.
+ *
+ * The removed item will be returned. In case there were more than 1 items
+ * removed, only the last one will be returned.
+ *
+ * @param mixed $item
+ * @return void
+ */
+ public function remove($item) {
+
+ if (is_string($item)) {
+ $children = $this->select($item);
+ foreach($children as $k=>$child) {
+ unset($this->children[$k]);
+ }
+ return $child;
+ } else {
+ foreach($this->children as $k => $child) {
+ if ($child===$item) {
+ unset($this->children[$k]);
+ return $child;
+ }
+ }
+
+ throw new \InvalidArgumentException('The item you passed to remove() was not a child of this component');
+
+ }
+
+ }
+
+ /**
+ * Returns an iterable list of children
+ *
+ * @return array
+ */
+ public function children() {
+
+ return $this->children;
+
+ }
+
+ /**
+ * This method only returns a list of sub-components. Properties are
+ * ignored.
+ *
+ * @return array
+ */
+ public function getComponents() {
+
+ $result = array();
+ foreach($this->children as $child) {
+ if ($child instanceof Component) {
+ $result[] = $child;
+ }
+ }
+
+ return $result;
+
+ }
+
+ /**
+ * Returns an array with elements that match the specified name.
+ *
+ * This function is also aware of MIME-Directory groups (as they appear in
+ * vcards). This means that if a property is grouped as "HOME.EMAIL", it
+ * will also be returned when searching for just "EMAIL". If you want to
+ * search for a property in a specific group, you can select on the entire
+ * string ("HOME.EMAIL"). If you want to search on a specific property that
+ * has not been assigned a group, specify ".EMAIL".
+ *
+ * Keys are retained from the 'children' array, which may be confusing in
+ * certain cases.
+ *
+ * @param string $name
+ * @return array
+ */
+ public function select($name) {
+
+ $group = null;
+ $name = strtoupper($name);
+ if (strpos($name,'.')!==false) {
+ list($group,$name) = explode('.', $name, 2);
+ }
+
+ $result = array();
+ foreach($this->children as $key=>$child) {
+
+ if (
+ strtoupper($child->name) === $name &&
+ (is_null($group) || ( $child instanceof Property && strtoupper($child->group) === $group))
+ ) {
+
+ $result[$key] = $child;
+
+ }
+ }
+
+ reset($result);
+ return $result;
+
+ }
+
+ /**
+ * Turns the object back into a serialized blob.
+ *
+ * @return string
+ */
+ public function serialize() {
+
+ $str = "BEGIN:" . $this->name . "\r\n";
+
+ /**
+ * Gives a component a 'score' for sorting purposes.
+ *
+ * This is solely used by the childrenSort method.
+ *
+ * A higher score means the item will be lower in the list.
+ * To avoid score collisions, each "score category" has a reasonable
+ * space to accomodate elements. The $key is added to the $score to
+ * preserve the original relative order of elements.
+ *
+ * @param int $key
+ * @param array $array
+ * @return int
+ */
+ $sortScore = function($key, $array) {
+
+ if ($array[$key] instanceof Component) {
+
+ // We want to encode VTIMEZONE first, this is a personal
+ // preference.
+ if ($array[$key]->name === 'VTIMEZONE') {
+ $score=300000000;
+ return $score+$key;
+ } else {
+ $score=400000000;
+ return $score+$key;
+ }
+ } else {
+ // Properties get encoded first
+ // VCARD version 4.0 wants the VERSION property to appear first
+ if ($array[$key] instanceof Property) {
+ if ($array[$key]->name === 'VERSION') {
+ $score=100000000;
+ return $score+$key;
+ } else {
+ // All other properties
+ $score=200000000;
+ return $score+$key;
+ }
+ }
+ }
+
+ };
+
+ $tmp = $this->children;
+ uksort($this->children, function($a, $b) use ($sortScore, $tmp) {
+
+ $sA = $sortScore($a, $tmp);
+ $sB = $sortScore($b, $tmp);
+
+ return $sA - $sB;
+
+ });
+
+ foreach($this->children as $child) $str.=$child->serialize();
+ $str.= "END:" . $this->name . "\r\n";
+
+ return $str;
+
+ }
+
+ /**
+ * This method returns an array, with the representation as it should be
+ * encoded in json. This is used to create jCard or jCal documents.
+ *
+ * @return array
+ */
+ public function jsonSerialize() {
+
+ $components = array();
+ $properties = array();
+
+ foreach($this->children as $child) {
+ if ($child instanceof Component) {
+ $components[] = $child->jsonSerialize();
+ } else {
+ $properties[] = $child->jsonSerialize();
+ }
+ }
+
+ return array(
+ strtolower($this->name),
+ $properties,
+ $components
+ );
+
+ }
+
+ /**
+ * This method should return a list of default property values.
+ *
+ * @return array
+ */
+ protected function getDefaults() {
+
+ return array();
+
+ }
+
+ /* Magic property accessors {{{ */
+
+ /**
+ * Using 'get' you will either get a property or component.
+ *
+ * If there were no child-elements found with the specified name,
+ * null is returned.
+ *
+ * To use this, this may look something like this:
+ *
+ * $event = $calendar->VEVENT;
+ *
+ * @param string $name
+ * @return Property
+ */
+ public function __get($name) {
+
+ $matches = $this->select($name);
+ if (count($matches)===0) {
+ return null;
+ } else {
+ $firstMatch = current($matches);
+ /** @var $firstMatch Property */
+ $firstMatch->setIterator(new ElementList(array_values($matches)));
+ return $firstMatch;
+ }
+
+ }
+
+ /**
+ * This method checks if a sub-element with the specified name exists.
+ *
+ * @param string $name
+ * @return bool
+ */
+ public function __isset($name) {
+
+ $matches = $this->select($name);
+ return count($matches)>0;
+
+ }
+
+ /**
+ * Using the setter method you can add properties or subcomponents
+ *
+ * You can either pass a Component, Property
+ * object, or a string to automatically create a Property.
+ *
+ * If the item already exists, it will be removed. If you want to add
+ * a new item with the same name, always use the add() method.
+ *
+ * @param string $name
+ * @param mixed $value
+ * @return void
+ */
+ public function __set($name, $value) {
+
+ $matches = $this->select($name);
+ $overWrite = count($matches)?key($matches):null;
+
+ if ($value instanceof Component || $value instanceof Property) {
+ $value->parent = $this;
+ if (!is_null($overWrite)) {
+ $this->children[$overWrite] = $value;
+ } else {
+ $this->children[] = $value;
+ }
+ } elseif (is_scalar($value) || is_array($value) || is_null($value)) {
+ $property = $this->root->create($name,$value);
+ $property->parent = $this;
+ if (!is_null($overWrite)) {
+ $this->children[$overWrite] = $property;
+ } else {
+ $this->children[] = $property;
+ }
+ } else {
+ throw new \InvalidArgumentException('You must pass a \\SabreForRainLoop\\VObject\\Component, \\SabreForRainLoop\\VObject\\Property or scalar type');
+ }
+
+ }
+
+ /**
+ * Removes all properties and components within this component with the
+ * specified name.
+ *
+ * @param string $name
+ * @return void
+ */
+ public function __unset($name) {
+
+ $matches = $this->select($name);
+ foreach($matches as $k=>$child) {
+
+ unset($this->children[$k]);
+ $child->parent = null;
+
+ }
+
+ }
+
+ /* }}} */
+
+ /**
+ * This method is automatically called when the object is cloned.
+ * Specifically, this will ensure all child elements are also cloned.
+ *
+ * @return void
+ */
+ public function __clone() {
+
+ foreach($this->children as $key=>$child) {
+ $this->children[$key] = clone $child;
+ $this->children[$key]->parent = $this;
+ }
+
+ }
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * - Node::REPAIR - If something is broken, an automatic repair may
+ * be attempted.
+ *
+ * An array is returned with warnings.
+ *
+ * Every item in the array has the following properties:
+ * * level - (number between 1 and 3 with severity information)
+ * * message - (human readable message)
+ * * node - (reference to the offending node)
+ *
+ * @param int $options
+ * @return array
+ */
+ public function validate($options = 0) {
+
+ $result = array();
+ foreach($this->children as $child) {
+ $result = array_merge($result, $child->validate($options));
+ }
+ return $result;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VAlarm.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VAlarm.php
new file mode 100644
index 0000000..6951c19
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VAlarm.php
@@ -0,0 +1,108 @@
+TRIGGER;
+ if(!isset($trigger['VALUE']) || strtoupper($trigger['VALUE']) === 'DURATION') {
+ $triggerDuration = VObject\DateTimeParser::parseDuration($this->TRIGGER);
+ $related = (isset($trigger['RELATED']) && strtoupper($trigger['RELATED']) == 'END') ? 'END' : 'START';
+
+ $parentComponent = $this->parent;
+ if ($related === 'START') {
+
+ if ($parentComponent->name === 'VTODO') {
+ $propName = 'DUE';
+ } else {
+ $propName = 'DTSTART';
+ }
+
+ $effectiveTrigger = clone $parentComponent->$propName->getDateTime();
+ $effectiveTrigger->add($triggerDuration);
+ } else {
+ if ($parentComponent->name === 'VTODO') {
+ $endProp = 'DUE';
+ } elseif ($parentComponent->name === 'VEVENT') {
+ $endProp = 'DTEND';
+ } else {
+ throw new \LogicException('time-range filters on VALARM components are only supported when they are a child of VTODO or VEVENT');
+ }
+
+ if (isset($parentComponent->$endProp)) {
+ $effectiveTrigger = clone $parentComponent->$endProp->getDateTime();
+ $effectiveTrigger->add($triggerDuration);
+ } elseif (isset($parentComponent->DURATION)) {
+ $effectiveTrigger = clone $parentComponent->DTSTART->getDateTime();
+ $duration = VObject\DateTimeParser::parseDuration($parentComponent->DURATION);
+ $effectiveTrigger->add($duration);
+ $effectiveTrigger->add($triggerDuration);
+ } else {
+ $effectiveTrigger = clone $parentComponent->DTSTART->getDateTime();
+ $effectiveTrigger->add($triggerDuration);
+ }
+ }
+ } else {
+ $effectiveTrigger = $trigger->getDateTime();
+ }
+ return $effectiveTrigger;
+
+ }
+
+ /**
+ * Returns true or false depending on if the event falls in the specified
+ * time-range. This is used for filtering purposes.
+ *
+ * The rules used to determine if an event falls within the specified
+ * time-range is based on the CalDAV specification.
+ *
+ * @param \DateTime $start
+ * @param \DateTime $end
+ * @return bool
+ */
+ public function isInTimeRange(\DateTime $start, \DateTime $end) {
+
+ $effectiveTrigger = $this->getEffectiveTriggerTime();
+
+ if (isset($this->DURATION)) {
+ $duration = VObject\DateTimeParser::parseDuration($this->DURATION);
+ $repeat = (string)$this->repeat;
+ if (!$repeat) {
+ $repeat = 1;
+ }
+
+ $period = new \DatePeriod($effectiveTrigger, $duration, (int)$repeat);
+
+ foreach($period as $occurrence) {
+
+ if ($start <= $occurrence && $end > $occurrence) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ return ($start <= $effectiveTrigger && $end > $effectiveTrigger);
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VCalendar.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VCalendar.php
new file mode 100644
index 0000000..ecc6784
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VCalendar.php
@@ -0,0 +1,369 @@
+ 'SabreForRainLoop\\VObject\\Component\\VEvent',
+ 'VFREEBUSY' => 'SabreForRainLoop\\VObject\\Component\\VFreeBusy',
+ 'VJOURNAL' => 'SabreForRainLoop\\VObject\\Component\\VJournal',
+ 'VTODO' => 'SabreForRainLoop\\VObject\\Component\\VTodo',
+ 'VALARM' => 'SabreForRainLoop\\VObject\\Component\\VAlarm',
+ );
+
+ /**
+ * List of value-types, and which classes they map to.
+ *
+ * @var array
+ */
+ static public $valueMap = array(
+ 'BINARY' => 'SabreForRainLoop\\VObject\\Property\\Binary',
+ 'BOOLEAN' => 'SabreForRainLoop\\VObject\\Property\\Boolean',
+ 'CAL-ADDRESS' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\CalAddress',
+ 'DATE' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\Date',
+ 'DATE-TIME' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\DateTime',
+ 'DURATION' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\Duration',
+ 'FLOAT' => 'SabreForRainLoop\\VObject\\Property\\Float',
+ 'INTEGER' => 'SabreForRainLoop\\VObject\\Property\\Integer',
+ 'PERIOD' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\Period',
+ 'RECUR' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\Recur',
+ 'TEXT' => 'SabreForRainLoop\\VObject\\Property\\Text',
+ 'TIME' => 'SabreForRainLoop\\VObject\\Property\\Time',
+ 'UNKNOWN' => 'SabreForRainLoop\\VObject\\Property\\Unknown', // jCard / jCal-only.
+ 'URI' => 'SabreForRainLoop\\VObject\\Property\\Uri',
+ 'UTC-OFFSET' => 'SabreForRainLoop\\VObject\\Property\\UtcOffset',
+ );
+
+ /**
+ * List of properties, and which classes they map to.
+ *
+ * @var array
+ */
+ static public $propertyMap = array(
+ // Calendar properties
+ 'CALSCALE' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'METHOD' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'PRODID' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'VERSION' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+
+ // Component properties
+ 'ATTACH' => 'SabreForRainLoop\\VObject\\Property\\Binary',
+ 'CATEGORIES' => 'SabreForRainLoop\\VObject\\Property\\Text',
+ 'CLASS' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'COMMENT' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'DESCRIPTION' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'GEO' => 'SabreForRainLoop\\VObject\\Property\\Float',
+ 'LOCATION' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'PERCENT-COMPLETE' => 'SabreForRainLoop\\VObject\\Property\\Integer',
+ 'PRIORITY' => 'SabreForRainLoop\\VObject\\Property\\Integer',
+ 'RESOURCES' => 'SabreForRainLoop\\VObject\\Property\\Text',
+ 'STATUS' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'SUMMARY' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+
+ // Date and Time Component Properties
+ 'COMPLETED' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\DateTime',
+ 'DTEND' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\DateTime',
+ 'DUE' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\DateTime',
+ 'DTSTART' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\DateTime',
+ 'DURATION' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\Duration',
+ 'FREEBUSY' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\Period',
+ 'TRANSP' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+
+ // Time Zone Component Properties
+ 'TZID' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'TZNAME' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'TZOFFSETFROM' => 'SabreForRainLoop\\VObject\\Property\\UtcOffset',
+ 'TZOFFSETTO' => 'SabreForRainLoop\\VObject\\Property\\UtcOffset',
+ 'TZURL' => 'SabreForRainLoop\\VObject\\Property\\Uri',
+
+ // Relationship Component Properties
+ 'ATTENDEE' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\CalAddress',
+ 'CONTACT' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'ORGANIZER' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\CalAddress',
+ 'RECURRENCE-ID' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\DateTime',
+ 'RELATED-TO' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'URL' => 'SabreForRainLoop\\VObject\\Property\\Uri',
+ 'UID' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+
+ // Recurrence Component Properties
+ 'EXDATE' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\DateTime',
+ 'RDATE' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\DateTime',
+ 'RRULE' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\Recur',
+ 'EXRULE' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\Recur', // Deprecated since rfc5545
+
+ // Alarm Component Properties
+ 'ACTION' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'REPEAT' => 'SabreForRainLoop\\VObject\\Property\\Integer',
+ 'TRIGGER' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\Duration',
+
+ // Change Management Component Properties
+ 'CREATED' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\DateTime',
+ 'DTSTAMP' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\DateTime',
+ 'LAST-MODIFIED' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\DateTime',
+ 'SEQUENCE' => 'SabreForRainLoop\\VObject\\Property\\Integer',
+
+ // Request Status
+ 'REQUEST-STATUS' => 'SabreForRainLoop\\VObject\\Property\\Text',
+
+ // Additions from draft-daboo-valarm-extensions-04
+ 'ALARM-AGENT' => 'SabreForRainLoop\\VObject\\Property\\Text',
+ 'ACKNOWLEDGED' => 'SabreForRainLoop\\VObject\\Property\\ICalendar\\DateTime',
+ 'PROXIMITY' => 'SabreForRainLoop\\VObject\\Property\\Text',
+ 'DEFAULT-ALARM' => 'SabreForRainLoop\\VObject\\Property\\Boolean',
+
+ );
+
+ /**
+ * Returns the current document type.
+ *
+ * @return void
+ */
+ public function getDocumentType() {
+
+ return self::ICALENDAR20;
+
+ }
+
+ /**
+ * Returns a list of all 'base components'. For instance, if an Event has
+ * a recurrence rule, and one instance is overridden, the overridden event
+ * will have the same UID, but will be excluded from this list.
+ *
+ * VTIMEZONE components will always be excluded.
+ *
+ * @param string $componentName filter by component name
+ * @return array
+ */
+ public function getBaseComponents($componentName = null) {
+
+ $components = array();
+ foreach($this->children as $component) {
+
+ if (!$component instanceof VObject\Component)
+ continue;
+
+ if (isset($component->{'RECURRENCE-ID'}))
+ continue;
+
+ if ($componentName && $component->name !== strtoupper($componentName))
+ continue;
+
+ if ($component->name === 'VTIMEZONE')
+ continue;
+
+ $components[] = $component;
+
+ }
+
+ return $components;
+
+ }
+
+ /**
+ * If this calendar object, has events with recurrence rules, this method
+ * can be used to expand the event into multiple sub-events.
+ *
+ * Each event will be stripped from it's recurrence information, and only
+ * the instances of the event in the specified timerange will be left
+ * alone.
+ *
+ * In addition, this method will cause timezone information to be stripped,
+ * and normalized to UTC.
+ *
+ * This method will alter the VCalendar. This cannot be reversed.
+ *
+ * This functionality is specifically used by the CalDAV standard. It is
+ * possible for clients to request expand events, if they are rather simple
+ * clients and do not have the possibility to calculate recurrences.
+ *
+ * @param DateTime $start
+ * @param DateTime $end
+ * @return void
+ */
+ public function expand(\DateTime $start, \DateTime $end) {
+
+ $newEvents = array();
+
+ foreach($this->select('VEVENT') as $key=>$vevent) {
+
+ if (isset($vevent->{'RECURRENCE-ID'})) {
+ unset($this->children[$key]);
+ continue;
+ }
+
+
+ if (!$vevent->rrule) {
+ unset($this->children[$key]);
+ if ($vevent->isInTimeRange($start, $end)) {
+ $newEvents[] = $vevent;
+ }
+ continue;
+ }
+
+ $uid = (string)$vevent->uid;
+ if (!$uid) {
+ throw new \LogicException('Event did not have a UID!');
+ }
+
+ $it = new VObject\RecurrenceIterator($this, $vevent->uid);
+ $it->fastForward($start);
+
+ while($it->valid() && $it->getDTStart() < $end) {
+
+ if ($it->getDTEnd() > $start) {
+
+ $newEvents[] = $it->getEventObject();
+
+ }
+ $it->next();
+
+ }
+ unset($this->children[$key]);
+
+ }
+
+ // Setting all properties to UTC time.
+ foreach($newEvents as $newEvent) {
+
+ foreach($newEvent->children as $child) {
+ if ($child instanceof VObject\Property\ICalendar\DateTime && $child->hasTime()) {
+ $dt = $child->getDateTimes();
+ // We only need to update the first timezone, because
+ // setDateTimes will match all other timezones to the
+ // first.
+ $dt[0]->setTimeZone(new \DateTimeZone('UTC'));
+ $child->setDateTimes($dt);
+ }
+
+ }
+
+ $this->add($newEvent);
+
+ }
+
+ // Removing all VTIMEZONE components
+ unset($this->VTIMEZONE);
+
+ }
+
+ /**
+ * This method should return a list of default property values.
+ *
+ * @return array
+ */
+ protected function getDefaults() {
+
+ return array(
+ 'VERSION' => '2.0',
+ 'PRODID' => '-//Sabre//Sabre VObject ' . VObject\Version::VERSION . '//EN',
+ 'CALSCALE' => 'GREGORIAN',
+ );
+
+ }
+
+ /**
+ * Validates the node for correctness.
+ * An array is returned with warnings.
+ *
+ * Every item in the array has the following properties:
+ * * level - (number between 1 and 3 with severity information)
+ * * message - (human readable message)
+ * * node - (reference to the offending node)
+ *
+ * @return array
+ */
+ public function validate($options = 0) {
+
+ $warnings = array();
+
+ $version = $this->select('VERSION');
+ if (count($version)!==1) {
+ $warnings[] = array(
+ 'level' => 1,
+ 'message' => 'The VERSION property must appear in the VCALENDAR component exactly 1 time',
+ 'node' => $this,
+ );
+ } else {
+ if ((string)$this->VERSION !== '2.0') {
+ $warnings[] = array(
+ 'level' => 1,
+ 'message' => 'Only iCalendar version 2.0 as defined in rfc5545 is supported.',
+ 'node' => $this,
+ );
+ }
+ }
+ $version = $this->select('PRODID');
+ if (count($version)!==1) {
+ $warnings[] = array(
+ 'level' => 2,
+ 'message' => 'The PRODID property must appear in the VCALENDAR component exactly 1 time',
+ 'node' => $this,
+ );
+ }
+ if (count($this->CALSCALE) > 1) {
+ $warnings[] = array(
+ 'level' => 2,
+ 'message' => 'The CALSCALE property must not be specified more than once.',
+ 'node' => $this,
+ );
+ }
+ if (count($this->METHOD) > 1) {
+ $warnings[] = array(
+ 'level' => 2,
+ 'message' => 'The METHOD property must not be specified more than once.',
+ 'node' => $this,
+ );
+ }
+
+ $componentsFound = 0;
+ foreach($this->children as $child) {
+ if($child instanceof Component) {
+ $componentsFound++;
+ }
+ }
+
+ if ($componentsFound===0) {
+ $warnings[] = array(
+ 'level' => 1,
+ 'message' => 'An iCalendar object must have at least 1 component.',
+ 'node' => $this,
+ );
+ }
+
+ return array_merge(
+ $warnings,
+ parent::validate()
+ );
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VCard.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VCard.php
new file mode 100644
index 0000000..e44ac3f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VCard.php
@@ -0,0 +1,353 @@
+ 'SabreForRainLoop\\VObject\\Property\\Binary',
+ 'BOOLEAN' => 'SabreForRainLoop\\VObject\\Property\\Boolean',
+ 'CONTENT-ID' => 'SabreForRainLoop\\VObject\\Property\\FlatText', // vCard 2.1 only
+ 'DATE' => 'SabreForRainLoop\\VObject\\Property\\VCard\\Date',
+ 'DATE-TIME' => 'SabreForRainLoop\\VObject\\Property\\VCard\\DateTime',
+ 'DATE-AND-OR-TIME' => 'SabreForRainLoop\\VObject\\Property\\VCard\\DateAndOrTime', // vCard only
+ 'FLOAT' => 'SabreForRainLoop\\VObject\\Property\\Float',
+ 'INTEGER' => 'SabreForRainLoop\\VObject\\Property\\Integer',
+ 'LANGUAGE-TAG' => 'SabreForRainLoop\\VObject\\Property\\VCard\\LanguageTag',
+ 'TIMESTAMP' => 'SabreForRainLoop\\VObject\\Property\\VCard\\TimeStamp',
+ 'TEXT' => 'SabreForRainLoop\\VObject\\Property\\Text',
+ 'TIME' => 'SabreForRainLoop\\VObject\\Property\\Time',
+ 'UNKNOWN' => 'SabreForRainLoop\\VObject\\Property\\Unknown', // jCard / jCal-only.
+ 'URI' => 'SabreForRainLoop\\VObject\\Property\\Uri',
+ 'URL' => 'SabreForRainLoop\\VObject\\Property\\Uri', // vCard 2.1 only
+ 'UTC-OFFSET' => 'SabreForRainLoop\\VObject\\Property\\UtcOffset',
+ );
+
+ /**
+ * List of properties, and which classes they map to.
+ *
+ * @var array
+ */
+ static public $propertyMap = array(
+
+ // vCard 2.1 properties and up
+ 'N' => 'SabreForRainLoop\\VObject\\Property\\Text',
+ 'FN' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'PHOTO' => 'SabreForRainLoop\\VObject\\Property\\Binary', // Todo: we should add a class for Binary values.
+ 'BDAY' => 'SabreForRainLoop\\VObject\\Property\\VCard\\DateAndOrTime',
+ 'ADR' => 'SabreForRainLoop\\VObject\\Property\\Text',
+ 'LABEL' => 'SabreForRainLoop\\VObject\\Property\\FlatText', // Removed in vCard 4.0
+ 'TEL' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'EMAIL' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'MAILER' => 'SabreForRainLoop\\VObject\\Property\\FlatText', // Removed in vCard 4.0
+ 'GEO' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'TITLE' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'ROLE' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'LOGO' => 'SabreForRainLoop\\VObject\\Property\\Binary',
+ // 'AGENT' => 'SabreForRainLoop\\VObject\\Property\\', // Todo: is an embedded vCard. Probably rare, so
+ // not supported at the moment
+ 'ORG' => 'SabreForRainLoop\\VObject\\Property\\Text',
+ 'NOTE' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'REV' => 'SabreForRainLoop\\VObject\\Property\\VCard\\TimeStamp',
+ 'SOUND' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'URL' => 'SabreForRainLoop\\VObject\\Property\\Uri',
+ 'UID' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'VERSION' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'KEY' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'TZ' => 'SabreForRainLoop\\VObject\\Property\\Text',
+
+ // vCard 3.0 properties
+ 'CATEGORIES' => 'SabreForRainLoop\\VObject\\Property\\Text',
+ 'SORT-STRING' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'PRODID' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'NICKNAME' => 'SabreForRainLoop\\VObject\\Property\\Text',
+ 'CLASS' => 'SabreForRainLoop\\VObject\\Property\\FlatText', // Removed in vCard 4.0
+
+ // rfc2739 properties
+ 'FBURL' => 'SabreForRainLoop\\VObject\\Property\\Uri',
+ 'CAPURI' => 'SabreForRainLoop\\VObject\\Property\\Uri',
+ 'CALURI' => 'SabreForRainLoop\\VObject\\Property\\Uri',
+
+ // rfc4770 properties
+ 'IMPP' => 'SabreForRainLoop\\VObject\\Property\\Uri',
+
+ // vCard 4.0 properties
+ 'XML' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+ 'ANNIVERSARY' => 'SabreForRainLoop\\VObject\\Property\\VCard\\DateAndOrTime',
+ 'CLIENTPIDMAP' => 'SabreForRainLoop\\VObject\\Property\\Text',
+ 'LANG' => 'SabreForRainLoop\\VObject\\Property\\VCard\\LanguageTag',
+ 'GENDER' => 'SabreForRainLoop\\VObject\\Property\\Text',
+ 'KIND' => 'SabreForRainLoop\\VObject\\Property\\FlatText',
+
+ );
+
+ /**
+ * Returns the current document type.
+ *
+ * @return void
+ */
+ public function getDocumentType() {
+
+ if (!$this->version) {
+ $version = (string)$this->VERSION;
+ switch($version) {
+ case '2.1' :
+ $this->version = self::VCARD21;
+ break;
+ case '3.0' :
+ $this->version = self::VCARD30;
+ break;
+ case '4.0' :
+ $this->version = self::VCARD40;
+ break;
+ default :
+ $this->version = self::UNKNOWN;
+ break;
+
+ }
+ }
+
+ return $this->version;
+
+ }
+
+ /**
+ * Converts the document to a different vcard version.
+ *
+ * Use one of the VCARD constants for the target. This method will return
+ * a copy of the vcard in the new version.
+ *
+ * At the moment the only supported conversion is from 3.0 to 4.0.
+ *
+ * If input and output version are identical, a clone is returned.
+ *
+ * @param int $target
+ * @return VCard
+ */
+ public function convert($target) {
+
+ $converter = new VObject\VCardConverter();
+ return $converter->convert($this, $target);
+
+ }
+
+ /**
+ * VCards with version 2.1, 3.0 and 4.0 are found.
+ *
+ * If the VCARD doesn't know its version, 2.1 is assumed.
+ */
+ const DEFAULT_VERSION = self::VCARD21;
+
+
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * - Node::REPAIR - If something is broken, and automatic repair may
+ * be attempted.
+ *
+ * An array is returned with warnings.
+ *
+ * Every item in the array has the following properties:
+ * * level - (number between 1 and 3 with severity information)
+ * * message - (human readable message)
+ * * node - (reference to the offending node)
+ *
+ * @param int $options
+ * @return array
+ */
+ public function validate($options = 0) {
+
+ $warnings = array();
+
+ $versionMap = array(
+ self::VCARD21 => '2.1',
+ self::VCARD30 => '3.0',
+ self::VCARD40 => '4.0',
+ );
+
+ $version = $this->select('VERSION');
+ if (count($version)!==1) {
+ $warnings[] = array(
+ 'level' => 1,
+ 'message' => 'The VERSION property must appear in the VCARD component exactly 1 time',
+ 'node' => $this,
+ );
+ if ($options & self::REPAIR) {
+ $this->VERSION = $versionMap[self::DEFAULT_VERSION];
+ }
+ } else {
+ $version = (string)$this->VERSION;
+ if ($version!=='2.1' && $version!=='3.0' && $version!=='4.0') {
+ $warnings[] = array(
+ 'level' => 1,
+ 'message' => 'Only vcard version 4.0 (RFC6350), version 3.0 (RFC2426) or version 2.1 (icm-vcard-2.1) are supported.',
+ 'node' => $this,
+ );
+ if ($options & self::REPAIR) {
+ $this->VERSION = $versionMap[self::DEFAULT_VERSION];
+ }
+ }
+
+ }
+ $fn = $this->select('FN');
+ if (count($fn)!==1) {
+ $warnings[] = array(
+ 'level' => 1,
+ 'message' => 'The FN property must appear in the VCARD component exactly 1 time',
+ 'node' => $this,
+ );
+ if (($options & self::REPAIR) && count($fn) === 0) {
+ // We're going to try to see if we can use the contents of the
+ // N property.
+ if (isset($this->N)) {
+ $value = explode(';', (string)$this->N);
+ if (isset($value[1]) && $value[1]) {
+ $this->FN = $value[1] . ' ' . $value[0];
+ } else {
+ $this->FN = $value[0];
+ }
+
+ // Otherwise, the ORG property may work
+ } elseif (isset($this->ORG)) {
+ $this->FN = (string)$this->ORG;
+ }
+
+ }
+ }
+
+ return array_merge(
+ parent::validate($options),
+ $warnings
+ );
+
+ }
+
+ /**
+ * Returns a preferred field.
+ *
+ * VCards can indicate wether a field such as ADR, TEL or EMAIL is
+ * preferred by specifying TYPE=PREF (vcard 2.1, 3) or PREF=x (vcard 4, x
+ * being a number between 1 and 100).
+ *
+ * If neither of those parameters are specified, the first is returned, if
+ * a field with that name does not exist, null is returned.
+ *
+ * @param string $fieldName
+ * @return VObject\Property|null
+ */
+ public function preferred($propertyName) {
+
+ $preferred = null;
+ $lastPref = 101;
+ foreach($this->select($propertyName) as $field) {
+
+ $pref = 101;
+ if (isset($field['TYPE']) && $field['TYPE']->has('PREF')) {
+ $pref = 1;
+ } elseif (isset($field['PREF'])) {
+ $pref = $field['PREF']->getValue();
+ }
+
+ if ($pref < $lastPref || is_null($preferred)) {
+ $preferred = $field;
+ $lastPref = $pref;
+ }
+
+ }
+ return $preferred;
+
+ }
+
+ /**
+ * This method should return a list of default property values.
+ *
+ * @return array
+ */
+ protected function getDefaults() {
+
+ return array(
+ 'VERSION' => '3.0',
+ 'PRODID' => '-//Sabre//Sabre VObject ' . VObject\Version::VERSION . '//EN',
+ );
+
+ }
+
+ /**
+ * This method returns an array, with the representation as it should be
+ * encoded in json. This is used to create jCard or jCal documents.
+ *
+ * @return array
+ */
+ public function jsonSerialize() {
+
+ // A vcard does not have sub-components, so we're overriding this
+ // method to remove that array element.
+ $properties = array();
+
+ foreach($this->children as $child) {
+ $properties[] = $child->jsonSerialize();
+ }
+
+ return array(
+ strtolower($this->name),
+ $properties,
+ );
+
+ }
+
+ /**
+ * Returns the default class for a property name.
+ *
+ * @param string $propertyName
+ * @return string
+ */
+ public function getClassNameForPropertyName($propertyName) {
+
+ $className = parent::getClassNameForPropertyName($propertyName);
+ // In vCard 4, BINARY no longer exists, and we need URI instead.
+
+ if ($className == 'SabreForRainLoop\\VObject\\Property\\Binary' && $this->getDocumentType()===self::VCARD40) {
+ return 'SabreForRainLoop\\VObject\\Property\\Uri';
+ }
+ return $className;
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VEvent.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VEvent.php
new file mode 100644
index 0000000..b1dc193
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VEvent.php
@@ -0,0 +1,70 @@
+RRULE) {
+ $it = new VObject\RecurrenceIterator($this);
+ $it->fastForward($start);
+
+ // We fast-forwarded to a spot where the end-time of the
+ // recurrence instance exceeded the start of the requested
+ // time-range.
+ //
+ // If the starttime of the recurrence did not exceed the
+ // end of the time range as well, we have a match.
+ return ($it->getDTStart() < $end && $it->getDTEnd() > $start);
+
+ }
+
+ $effectiveStart = $this->DTSTART->getDateTime();
+ if (isset($this->DTEND)) {
+
+ // The DTEND property is considered non inclusive. So for a 3 day
+ // event in july, dtstart and dtend would have to be July 1st and
+ // July 4th respectively.
+ //
+ // See:
+ // http://tools.ietf.org/html/rfc5545#page-54
+ $effectiveEnd = $this->DTEND->getDateTime();
+
+ } elseif (isset($this->DURATION)) {
+ $effectiveEnd = clone $effectiveStart;
+ $effectiveEnd->add( VObject\DateTimeParser::parseDuration($this->DURATION) );
+ } elseif (!$this->DTSTART->hasTime()) {
+ $effectiveEnd = clone $effectiveStart;
+ $effectiveEnd->modify('+1 day');
+ } else {
+ $effectiveEnd = clone $effectiveStart;
+ }
+ return (
+ ($start <= $effectiveEnd) && ($end > $effectiveStart)
+ );
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VFreeBusy.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VFreeBusy.php
new file mode 100644
index 0000000..1787c6b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VFreeBusy.php
@@ -0,0 +1,68 @@
+select('FREEBUSY') as $freebusy) {
+
+ // We are only interested in FBTYPE=BUSY (the default),
+ // FBTYPE=BUSY-TENTATIVE or FBTYPE=BUSY-UNAVAILABLE.
+ if (isset($freebusy['FBTYPE']) && strtoupper(substr((string)$freebusy['FBTYPE'],0,4))!=='BUSY') {
+ continue;
+ }
+
+ // The freebusy component can hold more than 1 value, separated by
+ // commas.
+ $periods = explode(',', (string)$freebusy);
+
+ foreach($periods as $period) {
+ // Every period is formatted as [start]/[end]. The start is an
+ // absolute UTC time, the end may be an absolute UTC time, or
+ // duration (relative) value.
+ list($busyStart, $busyEnd) = explode('/', $period);
+
+ $busyStart = VObject\DateTimeParser::parse($busyStart);
+ $busyEnd = VObject\DateTimeParser::parse($busyEnd);
+ if ($busyEnd instanceof \DateInterval) {
+ $tmp = clone $busyStart;
+ $tmp->add($busyEnd);
+ $busyEnd = $tmp;
+ }
+
+ if($start < $busyEnd && $end > $busyStart) {
+ return false;
+ }
+
+ }
+
+ }
+
+ return true;
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VJournal.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VJournal.php
new file mode 100644
index 0000000..8a54a2b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VJournal.php
@@ -0,0 +1,46 @@
+DTSTART)?$this->DTSTART->getDateTime():null;
+ if ($dtstart) {
+ $effectiveEnd = clone $dtstart;
+ if (!$this->DTSTART->hasTime()) {
+ $effectiveEnd->modify('+1 day');
+ }
+
+ return ($start <= $effectiveEnd && $end > $dtstart);
+
+ }
+ return false;
+
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VTodo.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VTodo.php
new file mode 100644
index 0000000..27bd2e3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Component/VTodo.php
@@ -0,0 +1,68 @@
+DTSTART)?$this->DTSTART->getDateTime():null;
+ $duration = isset($this->DURATION)?VObject\DateTimeParser::parseDuration($this->DURATION):null;
+ $due = isset($this->DUE)?$this->DUE->getDateTime():null;
+ $completed = isset($this->COMPLETED)?$this->COMPLETED->getDateTime():null;
+ $created = isset($this->CREATED)?$this->CREATED->getDateTime():null;
+
+ if ($dtstart) {
+ if ($duration) {
+ $effectiveEnd = clone $dtstart;
+ $effectiveEnd->add($duration);
+ return $start <= $effectiveEnd && $end > $dtstart;
+ } elseif ($due) {
+ return
+ ($start < $due || $start <= $dtstart) &&
+ ($end > $dtstart || $end >= $due);
+ } else {
+ return $start <= $dtstart && $end > $dtstart;
+ }
+ }
+ if ($due) {
+ return ($start < $due && $end >= $due);
+ }
+ if ($completed && $created) {
+ return
+ ($start <= $created || $start <= $completed) &&
+ ($end >= $created || $end >= $completed);
+ }
+ if ($completed) {
+ return ($start <= $completed && $end >= $completed);
+ }
+ if ($created) {
+ return ($end > $created);
+ }
+ return true;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/DateTimeParser.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/DateTimeParser.php
new file mode 100644
index 0000000..687a917
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/DateTimeParser.php
@@ -0,0 +1,415 @@
+setTimeZone(new \DateTimeZone('UTC'));
+ return $date;
+
+ }
+
+ /**
+ * Parses an iCalendar (rfc5545) formatted date and returns a DateTime object
+ *
+ * @param string $date
+ * @return DateTime
+ */
+ static public function parseDate($date) {
+
+ // Format is YYYYMMDD
+ $result = preg_match('/^([0-9]{4})([0-1][0-9])([0-3][0-9])$/',$date,$matches);
+
+ if (!$result) {
+ throw new \LogicException('The supplied iCalendar date value is incorrect: ' . $date);
+ }
+
+ $date = new \DateTime($matches[1] . '-' . $matches[2] . '-' . $matches[3], new \DateTimeZone('UTC'));
+ return $date;
+
+ }
+
+ /**
+ * Parses an iCalendar (RFC5545) formatted duration value.
+ *
+ * This method will either return a DateTimeInterval object, or a string
+ * suitable for strtotime or DateTime::modify.
+ *
+ * @param string $duration
+ * @param bool $asString
+ * @return DateInterval|string
+ */
+ static public function parseDuration($duration, $asString = false) {
+
+ $result = preg_match('/^(?P\+|-)?P((?P\d+)W)?((?P\d+)D)?(T((?P\d+)H)?((?P\d+)M)?((?P\d+)S)?)?$/', $duration, $matches);
+ if (!$result) {
+ throw new \LogicException('The supplied iCalendar duration value is incorrect: ' . $duration);
+ }
+
+ if (!$asString) {
+ $invert = false;
+ if ($matches['plusminus']==='-') {
+ $invert = true;
+ }
+
+
+ $parts = array(
+ 'week',
+ 'day',
+ 'hour',
+ 'minute',
+ 'second',
+ );
+ foreach($parts as $part) {
+ $matches[$part] = isset($matches[$part])&&$matches[$part]?(int)$matches[$part]:0;
+ }
+
+
+ // We need to re-construct the $duration string, because weeks and
+ // days are not supported by DateInterval in the same string.
+ $duration = 'P';
+ $days = $matches['day'];
+ if ($matches['week']) {
+ $days+=$matches['week']*7;
+ }
+ if ($days)
+ $duration.=$days . 'D';
+
+ if ($matches['minute'] || $matches['second'] || $matches['hour']) {
+ $duration.='T';
+
+ if ($matches['hour'])
+ $duration.=$matches['hour'].'H';
+
+ if ($matches['minute'])
+ $duration.=$matches['minute'].'M';
+
+ if ($matches['second'])
+ $duration.=$matches['second'].'S';
+
+ }
+
+ if ($duration==='P') {
+ $duration = 'PT0S';
+ }
+ $iv = new \DateInterval($duration);
+ if ($invert) $iv->invert = true;
+
+ return $iv;
+
+ }
+
+
+
+ $parts = array(
+ 'week',
+ 'day',
+ 'hour',
+ 'minute',
+ 'second',
+ );
+
+ $newDur = '';
+ foreach($parts as $part) {
+ if (isset($matches[$part]) && $matches[$part]) {
+ $newDur.=' '.$matches[$part] . ' ' . $part . 's';
+ }
+ }
+
+ $newDur = ($matches['plusminus']==='-'?'-':'+') . trim($newDur);
+ if ($newDur === '+') { $newDur = '+0 seconds'; };
+ return $newDur;
+
+ }
+
+ /**
+ * Parses either a Date or DateTime, or Duration value.
+ *
+ * @param string $date
+ * @param DateTimeZone|string $referenceTZ
+ * @return DateTime|DateInterval
+ */
+ static public function parse($date, $referenceTZ = null) {
+
+ if ($date[0]==='P' || ($date[0]==='-' && $date[1]==='P')) {
+ return self::parseDuration($date);
+ } elseif (strlen($date)===8) {
+ return self::parseDate($date);
+ } else {
+ return self::parseDateTime($date, $referenceTZ);
+ }
+
+ }
+
+ /**
+ * This method parses a vCard date and or time value.
+ *
+ * This can be used for the DATE, DATE-TIME, TIMESTAMP and
+ * DATE-AND-OR-TIME value.
+ *
+ * This method returns an array, not a DateTime value.
+ *
+ * The elements in the array are in the following order:
+ * year, month, date, hour, minute, second, timezone
+ *
+ * Almost any part of the string may be omitted. It's for example legal to
+ * just specify seconds, leave out the year, etc.
+ *
+ * Timezone is either returned as 'Z' or as '+08:00'
+ *
+ * For any non-specified values null is returned.
+ *
+ * List of date formats that are supported:
+ * YYYY
+ * YYYY-MM
+ * YYYYMMDD
+ * --MMDD
+ * ---DD
+ *
+ * YYYY-MM-DD
+ * --MM-DD
+ * ---DD
+ *
+ * List of supported time formats:
+ *
+ * HH
+ * HHMM
+ * HHMMSS
+ * -MMSS
+ * --SS
+ *
+ * HH
+ * HH:MM
+ * HH:MM:SS
+ * -MM:SS
+ * --SS
+ *
+ * A full basic-format date-time string looks like :
+ * 20130603T133901
+ *
+ * A full extended-format date-time string looks like :
+ * 2013-06-03T13:39:01
+ *
+ * Times may be postfixed by a timezone offset. This can be either 'Z' for
+ * UTC, or a string like -0500 or +1100.
+ *
+ * @param string $date
+ * @return array
+ */
+ static public function parseVCardDateTime($date) {
+
+ $regex = '/^
+ (?: # date part
+ (?:
+ (?: (?P [0-9]{4}) (?: -)?| --)
+ (?P [0-9]{2})?
+ |---)
+ (?P [0-9]{2})?
+ )?
+ (?:T # time part
+ (?P [0-9]{2} | -)
+ (?P [0-9]{2} | -)?
+ (?P [0-9]{2})?
+
+ (?P # timezone offset
+
+ Z | (?: \+|-)(?: [0-9]{4})
+
+ )?
+
+ )?
+ $/x';
+
+
+ if (!preg_match($regex, $date, $matches)) {
+
+ // Attempting to parse the extended format.
+ $regex = '/^
+ (?: # date part
+ (?: (?P [0-9]{4}) - | -- )
+ (?P [0-9]{2}) -
+ (?P [0-9]{2})
+ )?
+ (?:T # time part
+
+ (?: (?P [0-9]{2}) : | -)
+ (?: (?P [0-9]{2}) : | -)?
+ (?P [0-9]{2})?
+
+ (?P # timezone offset
+
+ Z | (?: \+|-)(?: [0-9]{2}:[0-9]{2})
+
+ )?
+
+ )?
+ $/x';
+
+ if (!preg_match($regex, $date, $matches)) {
+ throw new \InvalidArgumentException('Invalid vCard date-time string: ' . $date);
+ }
+
+ }
+ $parts = array(
+ 'year',
+ 'month',
+ 'date',
+ 'hour',
+ 'minute',
+ 'second',
+ 'timezone'
+ );
+
+ $result = array();
+ foreach($parts as $part) {
+
+ if (empty($matches[$part])) {
+ $result[$part] = null;
+ } elseif ($matches[$part] === '-' || $matches[$part] === '--') {
+ $result[$part] = null;
+ } else {
+ $result[$part] = $matches[$part];
+ }
+
+ }
+
+ return $result;
+
+ }
+
+ /**
+ * This method parses a vCard TIME value.
+ *
+ * This method returns an array, not a DateTime value.
+ *
+ * The elements in the array are in the following order:
+ * hour, minute, second, timezone
+ *
+ * Almost any part of the string may be omitted. It's for example legal to
+ * just specify seconds, leave out the hour etc.
+ *
+ * Timezone is either returned as 'Z' or as '+08:00'
+ *
+ * For any non-specified values null is returned.
+ *
+ * List of supported time formats:
+ *
+ * HH
+ * HHMM
+ * HHMMSS
+ * -MMSS
+ * --SS
+ *
+ * HH
+ * HH:MM
+ * HH:MM:SS
+ * -MM:SS
+ * --SS
+ *
+ * A full basic-format time string looks like :
+ * 133901
+ *
+ * A full extended-format time string looks like :
+ * 13:39:01
+ *
+ * Times may be postfixed by a timezone offset. This can be either 'Z' for
+ * UTC, or a string like -0500 or +11:00.
+ *
+ * @param string $date
+ * @return array
+ */
+ static public function parseVCardTime($date) {
+
+ $regex = '/^
+ (?P [0-9]{2} | -)
+ (?P [0-9]{2} | -)?
+ (?P [0-9]{2})?
+
+ (?P # timezone offset
+
+ Z | (?: \+|-)(?: [0-9]{4})
+
+ )?
+ $/x';
+
+
+ if (!preg_match($regex, $date, $matches)) {
+
+ // Attempting to parse the extended format.
+ $regex = '/^
+ (?: (?P [0-9]{2}) : | -)
+ (?: (?P [0-9]{2}) : | -)?
+ (?P [0-9]{2})?
+
+ (?P # timezone offset
+
+ Z | (?: \+|-)(?: [0-9]{2}:[0-9]{2})
+
+ )?
+ $/x';
+
+ if (!preg_match($regex, $date, $matches)) {
+ throw new \InvalidArgumentException('Invalid vCard time string: ' . $date);
+ }
+
+ }
+ $parts = array(
+ 'hour',
+ 'minute',
+ 'second',
+ 'timezone'
+ );
+
+ $result = array();
+ foreach($parts as $part) {
+
+ if (empty($matches[$part])) {
+ $result[$part] = null;
+ } elseif ($matches[$part] === '-') {
+ $result[$part] = null;
+ } else {
+ $result[$part] = $matches[$part];
+ }
+
+ }
+
+ return $result;
+
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Document.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Document.php
new file mode 100644
index 0000000..fd17b16
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Document.php
@@ -0,0 +1,261 @@
+value syntax, in which case
+ * properties will automatically be created, or you can just pass a list of
+ * Component and Property object.
+ *
+ * By default, a set of sensible values will be added to the component. For
+ * an iCalendar object, this may be something like CALSCALE:GREGORIAN. To
+ * ensure that this does not happen, set $defaults to false.
+ *
+ * @param string $name
+ * @param array $children
+ * @param bool $defaults
+ * @return Component
+ */
+ public function createComponent($name, array $children = null, $defaults = true) {
+
+ $name = strtoupper($name);
+ $class = 'SabreForRainLoop\\VObject\\Component';
+
+ if (isset(static::$componentMap[$name])) {
+ $class=static::$componentMap[$name];
+ }
+ if (is_null($children)) $children = array();
+ return new $class($this, $name, $children, $defaults);
+
+ }
+
+ /**
+ * Factory method for creating new properties
+ *
+ * This method automatically searches for the correct property class, based
+ * on its name.
+ *
+ * You can specify the parameters either in key=>value syntax, in which case
+ * parameters will automatically be created, or you can just pass a list of
+ * Parameter objects.
+ *
+ * @param string $name
+ * @param mixed $value
+ * @param array $parameters
+ * @param string $valueType Force a specific valuetype, such as URI or TEXT
+ * @return Property
+ */
+ public function createProperty($name, $value = null, array $parameters = null, $valueType = null) {
+
+ // If there's a . in the name, it means it's prefixed by a groupname.
+ if (($i=strpos($name,'.'))!==false) {
+ $group = substr($name, 0, $i);
+ $name = strtoupper(substr($name, $i+1));
+ } else {
+ $name = strtoupper($name);
+ $group = null;
+ }
+
+ $class = null;
+
+ if ($valueType) {
+ // The valueType argument comes first to figure out the correct
+ // class.
+ $class = $this->getClassNameForPropertyValue($valueType);
+ }
+
+ if (is_null($class) && isset($parameters['VALUE'])) {
+ // If a VALUE parameter is supplied, we should use that.
+ $class = $this->getClassNameForPropertyValue($parameters['VALUE']);
+ }
+ if (is_null($class)) {
+ $class = $this->getClassNameForPropertyName($name);
+ }
+ if (is_null($parameters)) $parameters = array();
+
+ return new $class($this, $name, $value, $parameters, $group);
+
+ }
+
+ /**
+ * This method returns a full class-name for a value parameter.
+ *
+ * For instance, DTSTART may have VALUE=DATE. In that case we will look in
+ * our valueMap table and return the appropriate class name.
+ *
+ * This method returns null if we don't have a specialized class.
+ *
+ * @param string $valueParam
+ * @return void
+ */
+ public function getClassNameForPropertyValue($valueParam) {
+
+ $valueParam = strtoupper($valueParam);
+ if (isset(static::$valueMap[$valueParam])) {
+ return static::$valueMap[$valueParam];
+ }
+
+ }
+
+ /**
+ * Returns the default class for a property name.
+ *
+ * @param string $propertyName
+ * @return string
+ */
+ public function getClassNameForPropertyName($propertyName) {
+
+ if (isset(static::$propertyMap[$propertyName])) {
+ return static::$propertyMap[$propertyName];
+ } else {
+ return 'SabreForRainLoop\\VObject\\Property\\Unknown';
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/ElementList.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/ElementList.php
new file mode 100644
index 0000000..807a085
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/ElementList.php
@@ -0,0 +1,172 @@
+vevent where there's multiple VEVENT objects.
+ *
+ * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/).
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
+ */
+class ElementList implements \Iterator, \Countable, \ArrayAccess {
+
+ /**
+ * Inner elements
+ *
+ * @var array
+ */
+ protected $elements = array();
+
+ /**
+ * Creates the element list.
+ *
+ * @param array $elements
+ */
+ public function __construct(array $elements) {
+
+ $this->elements = $elements;
+
+ }
+
+ /* {{{ Iterator interface */
+
+ /**
+ * Current position
+ *
+ * @var int
+ */
+ private $key = 0;
+
+ /**
+ * Returns current item in iteration
+ *
+ * @return Element
+ */
+ public function current() {
+
+ return $this->elements[$this->key];
+
+ }
+
+ /**
+ * To the next item in the iterator
+ *
+ * @return void
+ */
+ public function next() {
+
+ $this->key++;
+
+ }
+
+ /**
+ * Returns the current iterator key
+ *
+ * @return int
+ */
+ public function key() {
+
+ return $this->key;
+
+ }
+
+ /**
+ * Returns true if the current position in the iterator is a valid one
+ *
+ * @return bool
+ */
+ public function valid() {
+
+ return isset($this->elements[$this->key]);
+
+ }
+
+ /**
+ * Rewinds the iterator
+ *
+ * @return void
+ */
+ public function rewind() {
+
+ $this->key = 0;
+
+ }
+
+ /* }}} */
+
+ /* {{{ Countable interface */
+
+ /**
+ * Returns the number of elements
+ *
+ * @return int
+ */
+ public function count() {
+
+ return count($this->elements);
+
+ }
+
+ /* }}} */
+
+ /* {{{ ArrayAccess Interface */
+
+
+ /**
+ * Checks if an item exists through ArrayAccess.
+ *
+ * @param int $offset
+ * @return bool
+ */
+ public function offsetExists($offset) {
+
+ return isset($this->elements[$offset]);
+
+ }
+
+ /**
+ * Gets an item through ArrayAccess.
+ *
+ * @param int $offset
+ * @return mixed
+ */
+ public function offsetGet($offset) {
+
+ return $this->elements[$offset];
+
+ }
+
+ /**
+ * Sets an item through ArrayAccess.
+ *
+ * @param int $offset
+ * @param mixed $value
+ * @return void
+ */
+ public function offsetSet($offset,$value) {
+
+ throw new \LogicException('You can not add new objects to an ElementList');
+
+ }
+
+ /**
+ * Sets an item through ArrayAccess.
+ *
+ * This method just forwards the request to the inner iterator
+ *
+ * @param int $offset
+ * @return void
+ */
+ public function offsetUnset($offset) {
+
+ throw new \LogicException('You can not remove objects from an ElementList');
+
+ }
+
+ /* }}} */
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/EofException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/EofException.php
new file mode 100644
index 0000000..fc93509
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/EofException.php
@@ -0,0 +1,13 @@
+setTimeRange($start, $end);
+ }
+
+ if ($objects) {
+ $this->setObjects($objects);
+ }
+
+ }
+
+ /**
+ * Sets the VCALENDAR object.
+ *
+ * If this is set, it will not be generated for you. You are responsible
+ * for setting things like the METHOD, CALSCALE, VERSION, etc..
+ *
+ * The VFREEBUSY object will be automatically added though.
+ *
+ * @param Component $vcalendar
+ * @return void
+ */
+ public function setBaseObject(Component $vcalendar) {
+
+ $this->baseObject = $vcalendar;
+
+ }
+
+ /**
+ * Sets the input objects
+ *
+ * You must either specify a valendar object as a strong, or as the parse
+ * Component.
+ * It's also possible to specify multiple objects as an array.
+ *
+ * @param mixed $objects
+ * @return void
+ */
+ public function setObjects($objects) {
+
+ if (!is_array($objects)) {
+ $objects = array($objects);
+ }
+
+ $this->objects = array();
+ foreach($objects as $object) {
+
+ if (is_string($object)) {
+ $this->objects[] = Reader::read($object);
+ } elseif ($object instanceof Component) {
+ $this->objects[] = $object;
+ } else {
+ throw new \InvalidArgumentException('You can only pass strings or \\SabreForRainLoop\\VObject\\Component arguments to setObjects');
+ }
+
+ }
+
+ }
+
+ /**
+ * Sets the time range
+ *
+ * Any freebusy object falling outside of this time range will be ignored.
+ *
+ * @param DateTime $start
+ * @param DateTime $end
+ * @return void
+ */
+ public function setTimeRange(\DateTime $start = null, \DateTime $end = null) {
+
+ $this->start = $start;
+ $this->end = $end;
+
+ }
+
+ /**
+ * Parses the input data and returns a correct VFREEBUSY object, wrapped in
+ * a VCALENDAR.
+ *
+ * @return Component
+ */
+ public function getResult() {
+
+ $busyTimes = array();
+
+ foreach($this->objects as $object) {
+
+ foreach($object->getBaseComponents() as $component) {
+
+ switch($component->name) {
+
+ case 'VEVENT' :
+
+ $FBTYPE = 'BUSY';
+ if (isset($component->TRANSP) && (strtoupper($component->TRANSP) === 'TRANSPARENT')) {
+ break;
+ }
+ if (isset($component->STATUS)) {
+ $status = strtoupper($component->STATUS);
+ if ($status==='CANCELLED') {
+ break;
+ }
+ if ($status==='TENTATIVE') {
+ $FBTYPE = 'BUSY-TENTATIVE';
+ }
+ }
+
+ $times = array();
+
+ if ($component->RRULE) {
+
+ $iterator = new RecurrenceIterator($object, (string)$component->uid);
+ if ($this->start) {
+ $iterator->fastForward($this->start);
+ }
+
+ $maxRecurrences = 200;
+
+ while($iterator->valid() && --$maxRecurrences) {
+
+ $startTime = $iterator->getDTStart();
+ if ($this->end && $startTime > $this->end) {
+ break;
+ }
+ $times[] = array(
+ $iterator->getDTStart(),
+ $iterator->getDTEnd(),
+ );
+
+ $iterator->next();
+
+ }
+
+ } else {
+
+ $startTime = $component->DTSTART->getDateTime();
+ if ($this->end && $startTime > $this->end) {
+ break;
+ }
+ $endTime = null;
+ if (isset($component->DTEND)) {
+ $endTime = $component->DTEND->getDateTime();
+ } elseif (isset($component->DURATION)) {
+ $duration = DateTimeParser::parseDuration((string)$component->DURATION);
+ $endTime = clone $startTime;
+ $endTime->add($duration);
+ } elseif (!$component->DTSTART->hasTime()) {
+ $endTime = clone $startTime;
+ $endTime->modify('+1 day');
+ } else {
+ // The event had no duration (0 seconds)
+ break;
+ }
+
+ $times[] = array($startTime, $endTime);
+
+ }
+
+ foreach($times as $time) {
+
+ if ($this->end && $time[0] > $this->end) break;
+ if ($this->start && $time[1] < $this->start) break;
+
+ $busyTimes[] = array(
+ $time[0],
+ $time[1],
+ $FBTYPE,
+ );
+ }
+ break;
+
+ case 'VFREEBUSY' :
+ foreach($component->FREEBUSY as $freebusy) {
+
+ $fbType = isset($freebusy['FBTYPE'])?strtoupper($freebusy['FBTYPE']):'BUSY';
+
+ // Skipping intervals marked as 'free'
+ if ($fbType==='FREE')
+ continue;
+
+ $values = explode(',', $freebusy);
+ foreach($values as $value) {
+ list($startTime, $endTime) = explode('/', $value);
+ $startTime = DateTimeParser::parseDateTime($startTime);
+
+ if (substr($endTime,0,1)==='P' || substr($endTime,0,2)==='-P') {
+ $duration = DateTimeParser::parseDuration($endTime);
+ $endTime = clone $startTime;
+ $endTime->add($duration);
+ } else {
+ $endTime = DateTimeParser::parseDateTime($endTime);
+ }
+
+ if($this->start && $this->start > $endTime) continue;
+ if($this->end && $this->end < $startTime) continue;
+ $busyTimes[] = array(
+ $startTime,
+ $endTime,
+ $fbType
+ );
+
+ }
+
+
+ }
+ break;
+
+
+
+ }
+
+
+ }
+
+ }
+
+ if ($this->baseObject) {
+ $calendar = $this->baseObject;
+ } else {
+ $calendar = new VCalendar();
+ }
+
+ $vfreebusy = $calendar->createComponent('VFREEBUSY');
+ $calendar->add($vfreebusy);
+
+ if ($this->start) {
+ $dtstart = $calendar->createProperty('DTSTART');
+ $dtstart->setDateTime($this->start);
+ $vfreebusy->add($dtstart);
+ }
+ if ($this->end) {
+ $dtend = $calendar->createProperty('DTEND');
+ $dtend->setDateTime($this->end);
+ $vfreebusy->add($dtend);
+ }
+ $dtstamp = $calendar->createProperty('DTSTAMP');
+ $dtstamp->setDateTime(new \DateTime('now', new \DateTimeZone('UTC')));
+ $vfreebusy->add($dtstamp);
+
+ foreach($busyTimes as $busyTime) {
+
+ $busyTime[0]->setTimeZone(new \DateTimeZone('UTC'));
+ $busyTime[1]->setTimeZone(new \DateTimeZone('UTC'));
+
+ $prop = $calendar->createProperty(
+ 'FREEBUSY',
+ $busyTime[0]->format('Ymd\\THis\\Z') . '/' . $busyTime[1]->format('Ymd\\THis\\Z')
+ );
+ $prop['FBTYPE'] = $busyTime[2];
+ $vfreebusy->add($prop);
+
+ }
+
+ return $calendar;
+
+ }
+
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Node.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Node.php
new file mode 100644
index 0000000..3330fce
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Node.php
@@ -0,0 +1,201 @@
+iterator))
+ return $this->iterator;
+
+ return new ElementList(array($this));
+
+ }
+
+ /**
+ * Sets the overridden iterator
+ *
+ * Note that this is not actually part of the iterator interface
+ *
+ * @param ElementList $iterator
+ * @return void
+ */
+ public function setIterator(ElementList $iterator) {
+
+ $this->iterator = $iterator;
+
+ }
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * - Node::REPAIR - If something is broken, and automatic repair may
+ * be attempted.
+ *
+ * An array is returned with warnings.
+ *
+ * Every item in the array has the following properties:
+ * * level - (number between 1 and 3 with severity information)
+ * * message - (human readable message)
+ * * node - (reference to the offending node)
+ *
+ * @param int $options
+ * @return array
+ */
+ public function validate($options = 0) {
+
+ return array();
+
+ }
+
+ /* }}} */
+
+ /* {{{ Countable interface */
+
+ /**
+ * Returns the number of elements
+ *
+ * @return int
+ */
+ public function count() {
+
+ $it = $this->getIterator();
+ return $it->count();
+
+ }
+
+ /* }}} */
+
+ /* {{{ ArrayAccess Interface */
+
+
+ /**
+ * Checks if an item exists through ArrayAccess.
+ *
+ * This method just forwards the request to the inner iterator
+ *
+ * @param int $offset
+ * @return bool
+ */
+ public function offsetExists($offset) {
+
+ $iterator = $this->getIterator();
+ return $iterator->offsetExists($offset);
+
+ }
+
+ /**
+ * Gets an item through ArrayAccess.
+ *
+ * This method just forwards the request to the inner iterator
+ *
+ * @param int $offset
+ * @return mixed
+ */
+ public function offsetGet($offset) {
+
+ $iterator = $this->getIterator();
+ return $iterator->offsetGet($offset);
+
+ }
+
+ /**
+ * Sets an item through ArrayAccess.
+ *
+ * This method just forwards the request to the inner iterator
+ *
+ * @param int $offset
+ * @param mixed $value
+ * @return void
+ */
+ public function offsetSet($offset,$value) {
+
+ $iterator = $this->getIterator();
+ $iterator->offsetSet($offset,$value);
+
+ // @codeCoverageIgnoreStart
+ //
+ // This method always throws an exception, so we ignore the closing
+ // brace
+ }
+ // @codeCoverageIgnoreEnd
+
+ /**
+ * Sets an item through ArrayAccess.
+ *
+ * This method just forwards the request to the inner iterator
+ *
+ * @param int $offset
+ * @return void
+ */
+ public function offsetUnset($offset) {
+
+ $iterator = $this->getIterator();
+ $iterator->offsetUnset($offset);
+
+ // @codeCoverageIgnoreStart
+ //
+ // This method always throws an exception, so we ignore the closing
+ // brace
+ }
+ // @codeCoverageIgnoreEnd
+
+ /* }}} */
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Parameter.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Parameter.php
new file mode 100644
index 0000000..6e15317
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Parameter.php
@@ -0,0 +1,343 @@
+name = strtoupper($name);
+ $this->root = $root;
+ if (is_null($name)) {
+ $this->noName = true;
+ $this->name = static::guessParameterNameByValue($value);
+ }
+ $this->setValue($value);
+ }
+
+ /**
+ * Try to guess property name by value, can be used for vCard 2.1 nameless parameters.
+ *
+ * Figuring out what the name should have been. Note that a ton of
+ * these are rather silly in 2013 and would probably rarely be
+ * used, but we like to be complete.
+ *
+ * @param string $value
+ * @return string
+ */
+ public static function guessParameterNameByValue($value) {
+ switch(strtoupper($value)) {
+
+ // Encodings
+ case '7-BIT' :
+ case 'QUOTED-PRINTABLE' :
+ case 'BASE64' :
+ $name = 'ENCODING';
+ break;
+
+ // Common types
+ case 'WORK' :
+ case 'HOME' :
+ case 'PREF' :
+
+ // Delivery Label Type
+ case 'DOM' :
+ case 'INTL' :
+ case 'POSTAL' :
+ case 'PARCEL' :
+
+ // Telephone types
+ case 'VOICE' :
+ case 'FAX' :
+ case 'MSG' :
+ case 'CELL' :
+ case 'PAGER' :
+ case 'BBS' :
+ case 'MODEM' :
+ case 'CAR' :
+ case 'ISDN' :
+ case 'VIDEO' :
+
+ // EMAIL types (lol)
+ case 'AOL' :
+ case 'APPLELINK' :
+ case 'ATTMAIL' :
+ case 'CIS' :
+ case 'EWORLD' :
+ case 'INTERNET' :
+ case 'IBMMAIL' :
+ case 'MCIMAIL' :
+ case 'POWERSHARE' :
+ case 'PRODIGY' :
+ case 'TLX' :
+ case 'X400' :
+
+ // Photo / Logo format types
+ case 'GIF' :
+ case 'CGM' :
+ case 'WMF' :
+ case 'BMP' :
+ case 'DIB' :
+ case 'PICT' :
+ case 'TIFF' :
+ case 'PDF ':
+ case 'PS' :
+ case 'JPEG' :
+ case 'MPEG' :
+ case 'MPEG2' :
+ case 'AVI' :
+ case 'QTIME' :
+
+ // Sound Digital Audio Type
+ case 'WAVE' :
+ case 'PCM' :
+ case 'AIFF' :
+
+ // Key types
+ case 'X509' :
+ case 'PGP' :
+ $name = 'TYPE';
+ break;
+
+ // Value types
+ case 'INLINE' :
+ case 'URL' :
+ case 'CONTENT-ID' :
+ case 'CID' :
+ $name = 'VALUE';
+ break;
+
+ default:
+ $name = '';
+ }
+
+ return $name;
+ }
+
+ /**
+ * Updates the current value.
+ *
+ * This may be either a single, or multiple strings in an array.
+ *
+ * @param string|array $value
+ * @return void
+ */
+ public function setValue($value) {
+
+ $this->value = $value;
+
+ }
+
+ /**
+ * Returns the current value
+ *
+ * This method will always return a string, or null. If there were multiple
+ * values, it will automatically concatinate them (separated by comma).
+ *
+ * @return string|null
+ */
+ public function getValue() {
+
+ if (is_array($this->value)) {
+ return implode(',' , $this->value);
+ } else {
+ return $this->value;
+ }
+
+ }
+
+ /**
+ * Sets multiple values for this parameter.
+ *
+ * @param array $value
+ * @return void
+ */
+ public function setParts(array $value) {
+
+ $this->value = $value;
+
+ }
+
+ /**
+ * Returns all values for this parameter.
+ *
+ * If there were no values, an empty array will be returned.
+ *
+ * @return array
+ */
+ public function getParts() {
+
+ if (is_array($this->value)) {
+ return $this->value;
+ } elseif (is_null($this->value)) {
+ return array();
+ } else {
+ return array($this->value);
+ }
+
+ }
+
+ /**
+ * Adds a value to this parameter
+ *
+ * If the argument is specified as an array, all items will be added to the
+ * parameter value list.
+ *
+ * @param string|array $part
+ * @return void
+ */
+ public function addValue($part) {
+
+ if (is_null($this->value)) {
+ $this->value = $part;
+ } else {
+ $this->value = array_merge((array)$this->value, (array)$part);
+ }
+
+ }
+
+ /**
+ * Checks if this parameter contains the specified value.
+ *
+ * This is a case-insensitive match. It makes sense to call this for for
+ * instance the TYPE parameter, to see if it contains a keyword such as
+ * 'WORK' or 'FAX'.
+ *
+ * @param string $value
+ * @return bool
+ */
+ public function has($value) {
+
+ return in_array(
+ strtolower($value),
+ array_map('strtolower', (array)$this->value)
+ );
+
+ }
+
+ /**
+ * Turns the object back into a serialized blob.
+ *
+ * @return string
+ */
+ public function serialize() {
+
+ $value = $this->getParts();
+
+ if (count($value)===0) {
+ return $this->name;
+ }
+
+ if ($this->root->getDocumentType() === Document::VCARD21 && $this->noName) {
+
+ return implode(';', $value);
+
+ }
+
+ return $this->name . '=' . array_reduce($value, function($out, $item) {
+
+ if (!is_null($out)) $out.=',';
+
+ // If there's no special characters in the string, we'll use the simple
+ // format
+ if (!preg_match('#(?: [\n":;\^,] )#x', $item)) {
+ return $out.$item;
+ } else {
+ // Enclosing in double-quotes, and using RFC6868 for encoding any
+ // special characters
+ $out.='"' . strtr($item, array(
+ '^' => '^^',
+ "\n" => '^n',
+ '"' => '^\'',
+ )) . '"';
+ return $out;
+ }
+
+ });
+
+ }
+
+ /**
+ * This method returns an array, with the representation as it should be
+ * encoded in json. This is used to create jCard or jCal documents.
+ *
+ * @return array
+ */
+ public function jsonSerialize() {
+
+ return $this->value;
+
+ }
+
+ /**
+ * Called when this object is being cast to a string
+ *
+ * @return string
+ */
+ public function __toString() {
+
+ return $this->getValue();
+
+ }
+
+ /**
+ * Returns the iterator for this object
+ *
+ * @return ElementList
+ */
+ public function getIterator() {
+
+ if (!is_null($this->iterator))
+ return $this->iterator;
+
+ return $this->iterator = new ArrayObject((array)$this->value);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/ParseException.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/ParseException.php
new file mode 100644
index 0000000..5e3658c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/ParseException.php
@@ -0,0 +1,12 @@
+setInput($input);
+ }
+ if (is_null($this->input)) {
+ throw new EofException('End of input stream, or no input supplied');
+ }
+
+ if (!is_null($options)) {
+ $this->options = $options;
+ }
+
+ switch($this->input[0]) {
+ case 'vcalendar' :
+ $this->root = new VCalendar(array(), false);
+ break;
+ case 'vcard' :
+ $this->root = new VCard(array(), false);
+ break;
+ default :
+ throw new ParseException('The root component must either be a vcalendar, or a vcard');
+
+ }
+ foreach($this->input[1] as $prop) {
+ $this->root->add($this->parseProperty($prop));
+ }
+ if (isset($this->input[2])) foreach($this->input[2] as $comp) {
+ $this->root->add($this->parseComponent($comp));
+ }
+
+ // Resetting the input so we can throw an feof exception the next time.
+ $this->input = null;
+
+ return $this->root;
+
+ }
+
+ /**
+ * Parses a component
+ *
+ * @param array $jComp
+ * @return \SabreForRainLoop\VObject\Component
+ */
+ public function parseComponent(array $jComp) {
+
+ // We can remove $self from PHP 5.4 onward.
+ $self = $this;
+
+ $properties = array_map(function($jProp) use ($self) {
+ return $self->parseProperty($jProp);
+ }, $jComp[1]);
+
+ if (isset($jComp[2])) {
+
+ $components = array_map(function($jComp) use ($self) {
+ return $self->parseComponent($jComp);
+ }, $jComp[2]);
+
+ } else $components = array();
+
+ return $this->root->createComponent(
+ $jComp[0],
+ array_merge( $properties, $components),
+ $defaults = false
+ );
+
+ }
+
+ /**
+ * Parses properties.
+ *
+ * @param array $jProp
+ * @return \SabreForRainLoop\VObject\Property
+ */
+ public function parseProperty(array $jProp) {
+
+ list(
+ $propertyName,
+ $parameters,
+ $valueType
+ ) = $jProp;
+
+ $propertyName = strtoupper($propertyName);
+
+ // This is the default class we would be using if we didn't know the
+ // value type. We're using this value later in this function.
+ $defaultPropertyClass = $this->root->getClassNameForPropertyName($propertyName);
+
+ $parameters = (array)$parameters;
+
+ $value = array_slice($jProp, 3);
+
+ $valueType = strtoupper($valueType);
+
+ if (isset($parameters['group'])) {
+ $propertyName = $parameters['group'] . '.' . $propertyName;
+ unset($parameters['group']);
+ }
+
+ $prop = $this->root->createProperty($propertyName, null, $parameters, $valueType);
+ $prop->setJsonValue($value);
+
+ // We have to do something awkward here. FlatText as well as Text
+ // represents TEXT values. We have to normalize these here. In the
+ // future we can get rid of FlatText once we're allowed to break BC
+ // again.
+ if ($defaultPropertyClass === 'SabreForRainLoop\VObject\Property\FlatText') {
+ $defaultPropertyClass = 'SabreForRainLoop\VObject\Property\Text';
+ }
+
+ // If the value type we received (e.g.: TEXT) was not the default value
+ // type for the given property (e.g.: BDAY), we need to add a VALUE=
+ // parameter.
+ if ($defaultPropertyClass !== get_class($prop)) {
+ $prop["VALUE"] = $valueType;
+ }
+
+ return $prop;
+
+ }
+
+ /**
+ * Sets the input data
+ *
+ * @param resource|string|array $input
+ * @return void
+ */
+ public function setInput($input) {
+
+ if (is_resource($input)) {
+ $input = stream_get_contents($input);
+ }
+ if (is_string($input)) {
+ $input = json_decode($input);
+ }
+ $this->input = $input;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Parser/MimeDir.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Parser/MimeDir.php
new file mode 100644
index 0000000..e95741f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Parser/MimeDir.php
@@ -0,0 +1,602 @@
+root = null;
+ if (!is_null($input)) {
+
+ $this->setInput($input);
+
+ }
+
+ if (!is_null($options)) $this->options = $options;
+
+ $this->parseDocument();
+
+ return $this->root;
+
+ }
+
+ /**
+ * Sets the input buffer. Must be a string or stream.
+ *
+ * @param resource|string $input
+ * @return void
+ */
+ public function setInput($input) {
+
+ // Resetting the parser
+ $this->lineIndex = 0;
+ $this->startLine = 0;
+
+ if (is_string($input)) {
+ // Convering to a stream.
+ $stream = fopen('php://temp', 'r+');
+ fwrite($stream, $input);
+ rewind($stream);
+ $this->input = $stream;
+ } else {
+ $this->input = $input;
+ }
+
+ }
+
+ /**
+ * Parses an entire document.
+ *
+ * @return void
+ */
+ protected function parseDocument() {
+
+ $line = $this->readLine();
+ switch(strtoupper($line)) {
+ case 'BEGIN:VCALENDAR' :
+ $class = isset(VCalendar::$componentMap['VCALENDAR'])
+ ? VCalendar::$componentMap[$name]
+ : 'SabreForRainLoop\\VObject\\Component\\VCalendar';
+ break;
+ case 'BEGIN:VCARD' :
+ $class = isset(VCard::$componentMap['VCARD'])
+ ? VCard::$componentMap['VCARD']
+ : 'SabreForRainLoop\\VObject\\Component\\VCard';
+ break;
+ default :
+ throw new ParseException('This parser only supports VCARD and VCALENDAR files');
+ }
+
+ $this->root = new $class(array(), false);
+
+ while(true) {
+
+ // Reading until we hit END:
+ $line = $this->readLine();
+ if (strtoupper(substr($line,0,4)) === 'END:') {
+ break;
+ }
+ $result = $this->parseLine($line);
+ if ($result) {
+ $this->root->add($result);
+ }
+
+ }
+
+ $name = strtoupper(substr($line, 4));
+ if ($name!==$this->root->name) {
+ throw new ParseException('Invalid MimeDir file. expected: "END:' . $this->root->name . '" got: "END:' . $name . '"');
+ }
+
+ }
+
+ /**
+ * Parses a line, and if it hits a component, it will also attempt to parse
+ * the entire component
+ *
+ * @param string $line Unfolded line
+ * @return Node
+ */
+ protected function parseLine($line) {
+
+ // Start of a new component
+ if (strtoupper(substr($line, 0, 6)) === 'BEGIN:') {
+
+ $component = $this->root->createComponent(substr($line,6), array(), false);
+
+ while(true) {
+
+ // Reading until we hit END:
+ $line = $this->readLine();
+ if (strtoupper(substr($line,0,4)) === 'END:') {
+ break;
+ }
+ $result = $this->parseLine($line);
+ if ($result) {
+ $component->add($result);
+ }
+
+ }
+
+ $name = strtoupper(substr($line, 4));
+ if ($name!==$component->name) {
+ throw new ParseException('Invalid MimeDir file. expected: "END:' . $component->name . '" got: "END:' . $name . '"');
+ }
+
+ return $component;
+
+ } else {
+
+ // Property reader
+ $property = $this->readProperty($line);
+ if (!$property) {
+ // Ignored line
+ return false;
+ }
+ return $property;
+
+ }
+
+ }
+
+ /**
+ * We need to look ahead 1 line every time to see if we need to 'unfold'
+ * the next line.
+ *
+ * If that was not the case, we store it here.
+ *
+ * @var null|string
+ */
+ protected $lineBuffer;
+
+ /**
+ * The real current line number.
+ */
+ protected $lineIndex = 0;
+
+ /**
+ * In the case of unfolded lines, this property holds the line number for
+ * the start of the line.
+ *
+ * @var int
+ */
+ protected $startLine = 0;
+
+ /**
+ * Contains a 'raw' representation of the current line.
+ *
+ * @var string
+ */
+ protected $rawLine;
+
+ /**
+ * Reads a single line from the buffer.
+ *
+ * This method strips any newlines and also takes care of unfolding.
+ *
+ * @throws \SabreForRainLoop\VObject\EofException
+ * @return string
+ */
+ protected function readLine() {
+
+ if (!is_null($this->lineBuffer)) {
+ $rawLine = $this->lineBuffer;
+ $this->lineBuffer = null;
+ } else {
+ do {
+ $rawLine = fgets($this->input);
+ if ($rawLine === false && feof($this->input)) {
+ throw new EofException('End of document reached prematurely');
+ }
+ $rawLine = rtrim($rawLine, "\r\n");
+ } while ($rawLine === ''); // Skipping empty lines
+ $this->lineIndex++;
+ }
+ $line = $rawLine;
+
+ $this->startLine = $this->lineIndex;
+
+ // Looking ahead for folded lines.
+ while (true) {
+
+ $nextLine = rtrim(fgets($this->input), "\r\n");
+ $this->lineIndex++;
+ if (!$nextLine) {
+ break;
+ }
+ if ($nextLine[0] === "\t" || $nextLine[0] === " ") {
+ $line .= substr($nextLine, 1);
+ $rawLine .= "\n " . substr($nextLine, 1);
+ } else {
+ $this->lineBuffer = $nextLine;
+ break;
+ }
+
+ }
+ $this->rawLine = $rawLine;
+ return $line;
+
+ }
+
+ /**
+ * Reads a property or component from a line.
+ *
+ * @return void
+ */
+ protected function readProperty($line) {
+
+ if ($this->options & self::OPTION_FORGIVING) {
+ $propNameToken = 'A-Z0-9\-\._\\/';
+ } else {
+ $propNameToken = 'A-Z0-9\-\.';
+ }
+
+ $paramNameToken = 'A-Z0-9\-';
+ $safeChar = '^";:,';
+ $qSafeChar = '^"';
+
+ $regex = "/
+ ^(?P [$propNameToken]+ ) (?=[;:]) # property name
+ |
+ (?<=:)(?P .*)$ # property value
+ |
+ ;(?P [$paramNameToken]+) (?=[=;:]) # parameter name
+ |
+ (=|,)(?P # parameter value
+ (?: [$safeChar]*) |
+ \"(?: [$qSafeChar]+)\"
+ ) (?=[;:,])
+ /xi";
+
+ //echo $regex, "\n"; die();
+ preg_match_all($regex, $line, $matches, PREG_SET_ORDER );
+
+ $property = array(
+ 'name' => null,
+ 'parameters' => array(),
+ 'value' => null
+ );
+
+ $lastParam = null;
+
+ /**
+ * Looping through all the tokens.
+ *
+ * Note that we are looping through them in reverse order, because if a
+ * sub-pattern matched, the subsequent named patterns will not show up
+ * in the result.
+ */
+ foreach($matches as $match) {
+
+ if (isset($match['paramValue'])) {
+ if ($match['paramValue'] && $match['paramValue'][0] === '"') {
+ $value = substr($match['paramValue'], 1, -1);
+ } else {
+ $value = $match['paramValue'];
+ }
+
+ $value = $this->unescapeParam($value);
+
+ if (is_null($property['parameters'][$lastParam])) {
+ $property['parameters'][$lastParam] = $value;
+ } elseif (is_array($property['parameters'][$lastParam])) {
+ $property['parameters'][$lastParam][] = $value;
+ } else {
+ $property['parameters'][$lastParam] = array(
+ $property['parameters'][$lastParam],
+ $value
+ );
+ }
+ continue;
+ }
+ if (isset($match['paramName'])) {
+ $lastParam = strtoupper($match['paramName']);
+ if (!isset($property['parameters'][$lastParam])) {
+ $property['parameters'][$lastParam] = null;
+ }
+ continue;
+ }
+ if (isset($match['propValue'])) {
+ $property['value'] = $match['propValue'];
+ continue;
+ }
+ if (isset($match['name']) && $match['name']) {
+ $property['name'] = strtoupper($match['name']);
+ continue;
+ }
+
+ // @codeCoverageIgnoreStart
+ throw new \LogicException('This code should not be reachable');
+ // @codeCoverageIgnoreEnd
+
+ }
+
+ if (is_null($property['value']) || !$property['name']) {
+ if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
+ return false;
+ }
+ throw new ParseException('Invalid Mimedir file. Line starting at ' . $this->startLine . ' did not follow iCalendar/vCard conventions');
+ }
+
+ // vCard 2.1 states that parameters may appear without a name, and only
+ // a value. We can deduce the value based on it's name.
+ //
+ // Our parser will get those as parameters without a value instead, so
+ // we're filtering these parameters out first.
+ $namedParameters = array();
+ $namelessParameters = array();
+
+ foreach($property['parameters'] as $name=>$value) {
+ if (!is_null($value)) {
+ $namedParameters[$name] = $value;
+ } else {
+ $namelessParameters[] = $name;
+ }
+ }
+
+ $propObj = $this->root->createProperty($property['name'], null, $namedParameters);
+
+ foreach($namelessParameters as $namelessParameter) {
+ $propObj->add(null, $namelessParameter);
+ }
+
+ if (strtoupper($propObj['ENCODING']) === 'QUOTED-PRINTABLE') {
+ $propObj->setQuotedPrintableValue($this->extractQuotedPrintableValue());
+ } else {
+ $propObj->setRawMimeDirValue($property['value']);
+ }
+
+ return $propObj;
+
+ }
+
+ /**
+ * Unescapes a property value.
+ *
+ * vCard 2.1 says:
+ * * Semi-colons must be escaped in some property values, specifically
+ * ADR, ORG and N.
+ * * Semi-colons must be escaped in parameter values, because semi-colons
+ * are also use to separate values.
+ * * No mention of escaping backslashes with another backslash.
+ * * newlines are not escaped either, instead QUOTED-PRINTABLE is used to
+ * span values over more than 1 line.
+ *
+ * vCard 3.0 says:
+ * * (rfc2425) Backslashes, newlines (\n or \N) and comma's must be
+ * escaped, all time time.
+ * * Comma's are used for delimeters in multiple values
+ * * (rfc2426) Adds to to this that the semi-colon MUST also be escaped,
+ * as in some properties semi-colon is used for separators.
+ * * Properties using semi-colons: N, ADR, GEO, ORG
+ * * Both ADR and N's individual parts may be broken up further with a
+ * comma.
+ * * Properties using commas: NICKNAME, CATEGORIES
+ *
+ * vCard 4.0 (rfc6350) says:
+ * * Commas must be escaped.
+ * * Semi-colons may be escaped, an unescaped semi-colon _may_ be a
+ * delimiter, depending on the property.
+ * * Backslashes must be escaped
+ * * Newlines must be escaped as either \N or \n.
+ * * Some compound properties may contain multiple parts themselves, so a
+ * comma within a semi-colon delimited property may also be unescaped
+ * to denote multiple parts _within_ the compound property.
+ * * Text-properties using semi-colons: N, ADR, ORG, CLIENTPIDMAP.
+ * * Text-properties using commas: NICKNAME, RELATED, CATEGORIES, PID.
+ *
+ * Even though the spec says that commas must always be escaped, the
+ * example for GEO in Section 6.5.2 seems to violate this.
+ *
+ * iCalendar 2.0 (rfc5545) says:
+ * * Commas or semi-colons may be used as delimiters, depending on the
+ * property.
+ * * Commas, semi-colons, backslashes, newline (\N or \n) are always
+ * escaped, unless they are delimiters.
+ * * Colons shall not be escaped.
+ * * Commas can be considered the 'default delimiter' and is described as
+ * the delimiter in cases where the order of the multiple values is
+ * insignificant.
+ * * Semi-colons are described as the delimiter for 'structured values'.
+ * They are specifically used in Semi-colons are used as a delimiter in
+ * REQUEST-STATUS, RRULE, GEO and EXRULE. EXRULE is deprecated however.
+ *
+ * Now for the parameters
+ *
+ * If delimiter is not set (null) this method will just return a string.
+ * If it's a comma or a semi-colon the string will be split on those
+ * characters, and always return an array.
+ *
+ * @param string $input
+ * @param string $delimiter
+ * @return string|string[]
+ */
+ static public function unescapeValue($input, $delimiter = ';') {
+
+ $regex = '# (?: (\\\\ (?: \\\\ | N | n | ; | , ) )';
+ if ($delimiter) {
+ $regex .= ' | (' . $delimiter . ')';
+ }
+ $regex .= ') #x';
+
+ $matches = preg_split($regex, $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
+
+ $resultArray = array();
+ $result = '';
+
+ foreach($matches as $match) {
+
+ switch ($match) {
+ case '\\\\' :
+ $result .='\\';
+ break;
+ case '\N' :
+ case '\n' :
+ $result .="\n";
+ break;
+ case '\;' :
+ $result .=';';
+ break;
+ case '\,' :
+ $result .=',';
+ break;
+ case $delimiter :
+ $resultArray[] = $result;
+ $result = '';
+ break;
+ default :
+ $result .= $match;
+ break;
+
+ }
+
+ }
+
+ $resultArray[] = $result;
+ return $delimiter ? $resultArray : $result;
+
+ }
+
+ /**
+ * Unescapes a parameter value.
+ *
+ * vCard 2.1:
+ * * Does not mention a mechanism for this. In addition, double quotes
+ * are never used to wrap values.
+ * * This means that parameters can simply not contain colons or
+ * semi-colons.
+ *
+ * vCard 3.0 (rfc2425, rfc2426):
+ * * Parameters _may_ be surrounded by double quotes.
+ * * If this is not the case, semi-colon, colon and comma may simply not
+ * occur (the comma used for multiple parameter values though).
+ * * If it is surrounded by double-quotes, it may simply not contain
+ * double-quotes.
+ * * This means that a parameter can in no case encode double-quotes, or
+ * newlines.
+ *
+ * vCard 4.0 (rfc6350)
+ * * Behavior seems to be identical to vCard 3.0
+ *
+ * iCalendar 2.0 (rfc5545)
+ * * Behavior seems to be identical to vCard 3.0
+ *
+ * Parameter escaping mechanism (rfc6868) :
+ * * This rfc describes a new way to escape parameter values.
+ * * New-line is encoded as ^n
+ * * ^ is encoded as ^^.
+ * * " is encoded as ^'
+ *
+ * @param string $input
+ * @return void
+ */
+ private function unescapeParam($input) {
+
+ return
+ preg_replace_callback('#(\^(\^|n|\'))#',function($matches) {
+ switch($matches[2]) {
+ case 'n' :
+ return "\n";
+ case '^' :
+ return '^';
+ case '\'' :
+ return '"';
+
+ // @codeCoverageIgnoreStart
+ }
+ // @codeCoverageIgnoreEnd
+ }, $input);
+
+ }
+
+ /**
+ * Gets the full quoted printable value.
+ *
+ * We need a special method for this, because newlines have both a meaning
+ * in vCards, and in QuotedPrintable.
+ *
+ * This method does not do any decoding.
+ *
+ * @return string
+ */
+ private function extractQuotedPrintableValue() {
+
+ // We need to parse the raw line again to get the start of the value.
+ //
+ // We are basically looking for the first colon (:), but we need to
+ // skip over the parameters first, as they may contain one.
+ $regex = '/^
+ (?: [^:])+ # Anything but a colon
+ (?: "[^"]")* # A parameter in double quotes
+ : # start of the value we really care about
+ (.*)$
+ /xs';
+
+ preg_match($regex, $this->rawLine, $matches);
+
+ $value = $matches[1];
+ // Removing the first whitespace character from every line. Kind of
+ // like unfolding, but we keep the newline.
+ $value = str_replace("\n ", "\n", $value);
+
+ // Microsoft products don't always correctly fold lines, they may be
+ // missing a whitespace. So if 'forgiving' is turned on, we will take
+ // those as well.
+ if ($this->options & self::OPTION_FORGIVING) {
+ while(substr($value,-1) === '=') {
+ // Reading the line
+ $this->readLine();
+ // Grabbing the raw form
+ $value.="\n" . $this->rawLine;
+ }
+ }
+
+ return $value;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Parser/Parser.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Parser/Parser.php
new file mode 100644
index 0000000..22c90a1
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Parser/Parser.php
@@ -0,0 +1,77 @@
+setInput($input);
+ }
+ $this->options = $options;
+ }
+
+ /**
+ * This method starts the parsing process.
+ *
+ * If the input was not supplied during construction, it's possible to pass
+ * it here instead.
+ *
+ * If either input or options are not supplied, the defaults will be used.
+ *
+ * @param mixed $input
+ * @param int|null $options
+ * @return array
+ */
+ abstract public function parse($input = null, $options = null);
+
+ /**
+ * Sets the input data
+ *
+ * @param mixed $input
+ * @return void
+ */
+ abstract public function setInput($input);
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property.php
new file mode 100644
index 0000000..0dde8d0
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property.php
@@ -0,0 +1,502 @@
+value syntax.
+ *
+ * @param Component $root The root document
+ * @param string $name
+ * @param string|array|null $value
+ * @param array $parameters List of parameters
+ * @param string $group The vcard property group
+ * @return void
+ */
+ public function __construct(Component $root, $name, $value = null, array $parameters = array(), $group = null) {
+
+ $this->name = $name;
+ $this->group = $group;
+
+ $this->root = $root;
+
+ if (!is_null($value)) {
+ $this->setValue($value);
+ }
+
+ foreach($parameters as $k=>$v) {
+ $this->add($k, $v);
+ }
+
+ }
+
+ /**
+ * Updates the current value.
+ *
+ * This may be either a single, or multiple strings in an array.
+ *
+ * @param string|array $value
+ * @return void
+ */
+ public function setValue($value) {
+
+ $this->value = $value;
+
+ }
+
+ /**
+ * Returns the current value.
+ *
+ * This method will always return a singular value. If this was a
+ * multi-value object, some decision will be made first on how to represent
+ * it as a string.
+ *
+ * To get the correct multi-value version, use getParts.
+ *
+ * @return string
+ */
+ public function getValue() {
+
+ if (is_array($this->value)) {
+ if (count($this->value)==0) {
+ return null;
+ } elseif (count($this->value)===1) {
+ return $this->value[0];
+ } else {
+ return $this->getRawMimeDirValue($this->value);
+ }
+ } else {
+ return $this->value;
+ }
+
+ }
+
+ /**
+ * Sets a multi-valued property.
+ *
+ * @param array $parts
+ * @return void
+ */
+ public function setParts(array $parts) {
+
+ $this->value = $parts;
+
+ }
+
+ /**
+ * Returns a multi-valued property.
+ *
+ * This method always returns an array, if there was only a single value,
+ * it will still be wrapped in an array.
+ *
+ * @return array
+ */
+ public function getParts() {
+
+ if (is_null($this->value)) {
+ return array();
+ } elseif (is_array($this->value)) {
+ return $this->value;
+ } else {
+ return array($this->value);
+ }
+
+ }
+
+ /**
+ * Adds a new parameter, and returns the new item.
+ *
+ * If a parameter with same name already existed, the values will be
+ * combined.
+ * If nameless parameter is added, we try to guess it's name.
+ *
+ * @param string $name
+ * @param string|null|array $value
+ * @return Node
+ */
+ public function add($name, $value = null) {
+ $noName = false;
+ if ($name === null) {
+ $name = Parameter::guessParameterNameByValue($value);
+ $noName = true;
+ }
+
+ if (isset($this->parameters[strtoupper($name)])) {
+ $this->parameters[strtoupper($name)]->addValue($value);
+ }
+ else {
+ $param = new Parameter($this->root, $name, $value);
+ $param->noName = $noName;
+ $this->parameters[$param->name] = $param;
+ }
+ }
+
+ /**
+ * Returns an iterable list of children
+ *
+ * @return array
+ */
+ public function parameters() {
+
+ return $this->parameters;
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ abstract public function getValueType();
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ * @return void
+ */
+ abstract public function setRawMimeDirValue($val);
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ abstract public function getRawMimeDirValue();
+
+ /**
+ * Turns the object back into a serialized blob.
+ *
+ * @return string
+ */
+ public function serialize() {
+
+ $str = $this->name;
+ if ($this->group) $str = $this->group . '.' . $this->name;
+
+ foreach($this->parameters as $param) {
+
+ $str.=';' . $param->serialize();
+
+ }
+
+ $str.=':' . $this->getRawMimeDirValue();
+
+ $out = '';
+ while(strlen($str)>0) {
+ if (strlen($str)>75) {
+ $out.= mb_strcut($str,0,75,'utf-8') . "\r\n";
+ $str = ' ' . mb_strcut($str,75,strlen($str),'utf-8');
+ } else {
+ $out.=$str . "\r\n";
+ $str='';
+ break;
+ }
+ }
+
+ return $out;
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ public function getJsonValue() {
+
+ return $this->getParts();
+
+ }
+
+ /**
+ * Sets the json value, as it would appear in a jCard or jCal object.
+ *
+ * The value must always be an array.
+ *
+ * @param array $value
+ * @return void
+ */
+ public function setJsonValue(array $value) {
+
+ if (count($value)===1) {
+ $this->setValue(reset($value));
+ } else {
+ $this->setValue($value);
+ }
+
+ }
+
+ /**
+ * This method returns an array, with the representation as it should be
+ * encoded in json. This is used to create jCard or jCal documents.
+ *
+ * @return array
+ */
+ public function jsonSerialize() {
+
+ $parameters = array();
+
+ foreach($this->parameters as $parameter) {
+ if ($parameter->name === 'VALUE') {
+ continue;
+ }
+ $parameters[strtolower($parameter->name)] = $parameter->jsonSerialize();
+ }
+ // In jCard, we need to encode the property-group as a separate 'group'
+ // parameter.
+ if ($this->group) {
+ $parameters['group'] = $this->group;
+ }
+
+ return array_merge(
+ array(
+ strtolower($this->name),
+ (object)$parameters,
+ strtolower($this->getValueType()),
+ ),
+ $this->getJsonValue()
+ );
+ }
+
+
+ /**
+ * Called when this object is being cast to a string.
+ *
+ * If the property only had a single value, you will get just that. In the
+ * case the property had multiple values, the contents will be escaped and
+ * combined with ,.
+ *
+ * @return string
+ */
+ public function __toString() {
+
+ return (string)$this->getValue();
+
+ }
+
+ /* ArrayAccess interface {{{ */
+
+ /**
+ * Checks if an array element exists
+ *
+ * @param mixed $name
+ * @return bool
+ */
+ public function offsetExists($name) {
+
+ if (is_int($name)) return parent::offsetExists($name);
+
+ $name = strtoupper($name);
+
+ foreach($this->parameters as $parameter) {
+ if ($parameter->name == $name) return true;
+ }
+ return false;
+
+ }
+
+ /**
+ * Returns a parameter.
+ *
+ * If the parameter does not exist, null is returned.
+ *
+ * @param string $name
+ * @return Node
+ */
+ public function offsetGet($name) {
+
+ if (is_int($name)) return parent::offsetGet($name);
+ $name = strtoupper($name);
+
+ if (!isset($this->parameters[$name])) {
+ return null;
+ }
+
+ return $this->parameters[$name];
+
+ }
+
+ /**
+ * Creates a new parameter
+ *
+ * @param string $name
+ * @param mixed $value
+ * @return void
+ */
+ public function offsetSet($name, $value) {
+
+ if (is_int($name)) {
+ parent::offsetSet($name, $value);
+ // @codeCoverageIgnoreStart
+ // This will never be reached, because an exception is always
+ // thrown.
+ return;
+ // @codeCoverageIgnoreEnd
+ }
+
+ $param = new Parameter($this->root, $name, $value);
+ $this->parameters[$param->name] = $param;
+
+ }
+
+ /**
+ * Removes one or more parameters with the specified name
+ *
+ * @param string $name
+ * @return void
+ */
+ public function offsetUnset($name) {
+
+ if (is_int($name)) {
+ parent::offsetUnset($name);
+ // @codeCoverageIgnoreStart
+ // This will never be reached, because an exception is always
+ // thrown.
+ return;
+ // @codeCoverageIgnoreEnd
+ }
+
+ unset($this->parameters[strtoupper($name)]);
+
+ }
+ /* }}} */
+
+ /**
+ * This method is automatically called when the object is cloned.
+ * Specifically, this will ensure all child elements are also cloned.
+ *
+ * @return void
+ */
+ public function __clone() {
+
+ foreach($this->parameters as $key=>$child) {
+ $this->parameters[$key] = clone $child;
+ $this->parameters[$key]->parent = $this;
+ }
+
+ }
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * - Node::REPAIR - If something is broken, and automatic repair may
+ * be attempted.
+ *
+ * An array is returned with warnings.
+ *
+ * Every item in the array has the following properties:
+ * * level - (number between 1 and 3 with severity information)
+ * * message - (human readable message)
+ * * node - (reference to the offending node)
+ *
+ * @param int $options
+ * @return array
+ */
+ public function validate($options = 0) {
+
+ $warnings = array();
+
+ // Checking if our value is UTF-8
+ if (!StringUtil::isUTF8($this->getRawMimeDirValue())) {
+ $warnings[] = array(
+ 'level' => 1,
+ 'message' => 'Property is not valid UTF-8!',
+ 'node' => $this,
+ );
+ if ($options & self::REPAIR) {
+ $this->setRawMimeDirValue(StringUtil::convertToUTF8($this->getRawMimeDirValue()));
+ }
+ }
+
+ // Checking if the propertyname does not contain any invalid bytes.
+ if (!preg_match('/^([A-Z0-9-]+)$/', $this->name)) {
+ $warnings[] = array(
+ 'level' => 1,
+ 'message' => 'The propertyname: ' . $this->name . ' contains invalid characters. Only A-Z, 0-9 and - are allowed',
+ 'node' => $this,
+ );
+ if ($options & self::REPAIR) {
+ // Uppercasing and converting underscores to dashes.
+ $this->name = strtoupper(
+ str_replace('_', '-', $this->name)
+ );
+ // Removing every other invalid character
+ $this->name = preg_replace('/([^A-Z0-9-])/u', '', $this->name);
+
+ }
+
+ }
+
+ // Validating inner parameters
+ foreach($this->parameters as $param) {
+ $warnings = array_merge($warnings, $param->validate($options));
+ }
+
+ return $warnings;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Binary.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Binary.php
new file mode 100644
index 0000000..2e857c3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Binary.php
@@ -0,0 +1,127 @@
+value = $value[0];
+ } else {
+ throw new \InvalidArgumentException('The argument must either be a string or an array with only one child');
+ }
+
+ } else {
+
+ $this->value = $value;
+
+ }
+
+ }
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ * @return void
+ */
+ public function setRawMimeDirValue($val) {
+
+ $this->value = base64_decode($val);
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ public function getRawMimeDirValue() {
+
+ return base64_encode($this->value);
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ public function getValueType() {
+
+ return 'BINARY';
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ public function getJsonValue() {
+
+ return array(base64_encode($this->getValue()));
+
+ }
+
+ /**
+ * Sets the json value, as it would appear in a jCard or jCal object.
+ *
+ * The value must always be an array.
+ *
+ * @param array $value
+ * @return void
+ */
+ public function setJsonValue(array $value) {
+
+ $value = array_map('base64_decode', $value);
+ parent::setJsonValue($value);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Boolean.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Boolean.php
new file mode 100644
index 0000000..75ea0d6
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Boolean.php
@@ -0,0 +1,63 @@
+setValue($val);
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ public function getRawMimeDirValue() {
+
+ return $this->value?'TRUE':'FALSE';
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ public function getValueType() {
+
+ return 'BOOLEAN';
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/FlatText.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/FlatText.php
new file mode 100644
index 0000000..57f30cd
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/FlatText.php
@@ -0,0 +1,49 @@
+setValue($val);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Float.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Float.php
new file mode 100644
index 0000000..02476f8
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Float.php
@@ -0,0 +1,101 @@
+delimiter, $val);
+ foreach($val as &$item) {
+ $item = (float)$item;
+ }
+ $this->setParts($val);
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ public function getRawMimeDirValue() {
+
+ return implode(
+ $this->delimiter,
+ $this->getParts()
+ );
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ public function getValueType() {
+
+ return "FLOAT";
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ public function getJsonValue() {
+
+ $val = array_map(function($item) {
+
+ return (float)$item;
+
+ }, $this->getParts());
+
+ // Special-casing the GEO property.
+ //
+ // See:
+ // http://tools.ietf.org/html/draft-ietf-jcardcal-jcal-04#section-3.4.1.2
+ if ($this->name==='GEO') {
+ return array($val);
+ } else {
+ return $val;
+ }
+
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/CalAddress.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/CalAddress.php
new file mode 100644
index 0000000..e76a302
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/CalAddress.php
@@ -0,0 +1,41 @@
+setDateTimes($parts);
+ } else {
+ parent::setParts($parts);
+ }
+
+ }
+
+ /**
+ * Updates the current value.
+ *
+ * This may be either a single, or multiple strings in an array.
+ *
+ * Instead of strings, you may also use DateTime here.
+ *
+ * @param string|array|\DateTime $value
+ * @return void
+ */
+ public function setValue($value) {
+
+ if (is_array($value) && isset($value[0]) && $value[0] instanceof \DateTime) {
+ $this->setDateTimes($value);
+ } elseif ($value instanceof \DateTime) {
+ $this->setDateTimes(array($value));
+ } else {
+ parent::setValue($value);
+ }
+
+ }
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ * @return void
+ */
+ public function setRawMimeDirValue($val) {
+
+ $this->setValue(explode($this->delimiter, $val));
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ public function getRawMimeDirValue() {
+
+ return implode($this->delimiter, $this->getParts());
+
+ }
+
+ /**
+ * Returns true if this is a DATE-TIME value, false if it's a DATE.
+ *
+ * @return bool
+ */
+ public function hasTime() {
+
+ return strtoupper((string)$this['VALUE']) !== 'DATE';
+
+ }
+
+ /**
+ * Returns a date-time value.
+ *
+ * Note that if this property contained more than 1 date-time, only the
+ * first will be returned. To get an array with multiple values, call
+ * getDateTimes.
+ *
+ * @return \DateTime
+ */
+ public function getDateTime() {
+
+ $dt = $this->getDateTimes();
+ if (!$dt) return null;
+
+ return $dt[0];
+
+ }
+
+ /**
+ * Returns multiple date-time values.
+ *
+ * @return \DateTime[]
+ */
+ public function getDateTimes() {
+
+ // Finding the timezone.
+ $tz = $this['TZID'];
+
+ if ($tz) {
+ $tz = TimeZoneUtil::getTimeZone((string)$tz, $this->root);
+ }
+
+ $dts = array();
+ foreach($this->getParts() as $part) {
+ $dts[] = DateTimeParser::parse($part, $tz);
+ }
+ return $dts;
+
+ }
+
+ /**
+ * Sets the property as a DateTime object.
+ *
+ * @param \DateTime $dt
+ * @param bool isFloating If set to true, timezones will be ignored.
+ * @return void
+ */
+ public function setDateTime(\DateTime $dt, $isFloating = false) {
+
+ $this->setDateTimes(array($dt), $isFloating);
+
+ }
+
+ /**
+ * Sets the property as multiple date-time objects.
+ *
+ * The first value will be used as a reference for the timezones, and all
+ * the otehr values will be adjusted for that timezone
+ *
+ * @param \DateTime[] $dt
+ * @param bool isFloating If set to true, timezones will be ignored.
+ * @return void
+ */
+ public function setDateTimes(array $dt, $isFloating = false) {
+
+ $values = array();
+
+ if($this->hasTime()) {
+
+ $tz = null;
+ $isUtc = false;
+
+ foreach($dt as $d) {
+
+ if ($isFloating) {
+ $values[] = $d->format('Ymd\\THis');
+ continue;
+ }
+ if (is_null($tz)) {
+ $tz = $d->getTimeZone();
+ $isUtc = in_array($tz->getName() , array('UTC', 'GMT', 'Z'));
+ if (!$isUtc) {
+ $this->offsetSet('TZID', $tz->getName());
+ }
+ } else {
+ $d->setTimeZone($tz);
+ }
+
+ if ($isUtc) {
+ $values[] = $d->format('Ymd\\THis\\Z');
+ } else {
+ $values[] = $d->format('Ymd\\THis');
+ }
+
+ }
+ if ($isUtc || $isFloating) {
+ $this->offsetUnset('TZID');
+ }
+
+ } else {
+
+ foreach($dt as $d) {
+
+ $values[] = $d->format('Ymd');
+
+ }
+ $this->offsetUnset('TZID');
+
+ }
+
+ $this->value = $values;
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ public function getValueType() {
+
+ return $this->hasTime()?'DATE-TIME':'DATE';
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ public function getJsonValue() {
+
+ $dts = $this->getDateTimes();
+ $hasTime = $this->hasTime();
+
+ $tz = $dts[0]->getTimeZone();
+ $isUtc = in_array($tz->getName() , array('UTC', 'GMT', 'Z'));
+
+ return array_map(function($dt) use ($hasTime, $isUtc) {
+
+ if ($hasTime) {
+ return $dt->format('Y-m-d\\TH:i:s') . ($isUtc?'Z':'');
+ } else {
+ return $dt->format('Y-m-d');
+ }
+
+ }, $dts);
+
+ }
+
+ /**
+ * Sets the json value, as it would appear in a jCard or jCal object.
+ *
+ * The value must always be an array.
+ *
+ * @param array $value
+ * @return void
+ */
+ public function setJsonValue(array $value) {
+
+ // dates and times in jCal have one difference to dates and times in
+ // iCalendar. In jCal date-parts are separated by dashes, and
+ // time-parts are separated by colons. It makes sense to just remove
+ // those.
+ $this->setValue(array_map(function($item) {
+
+ return strtr($item, array(':'=>'', '-'=>''));
+
+ }, $value));
+
+ }
+ /**
+ * We need to intercept offsetSet, because it may be used to alter the
+ * VALUE from DATE-TIME to DATE or vice-versa.
+ *
+ * @param string $name
+ * @param mixed $value
+ * @return void
+ */
+ public function offsetSet($name, $value) {
+
+ parent::offsetSet($name, $value);
+ if (strtoupper($name)!=='VALUE') {
+ return;
+ }
+
+ // This will ensure that dates are correctly encoded.
+ $this->setDateTimes($this->getDateTimes());
+
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Duration.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Duration.php
new file mode 100644
index 0000000..0f25110
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Duration.php
@@ -0,0 +1,86 @@
+setValue(explode($this->delimiter, $val));
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ public function getRawMimeDirValue() {
+
+ return implode($this->delimiter, $this->getParts());
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ public function getValueType() {
+
+ return 'DURATION';
+
+ }
+
+ /**
+ * Returns a DateInterval representation of the Duration property.
+ *
+ * If the property has more than one value, only the first is returned.
+ *
+ * @return \DateInterval
+ */
+ public function getDateInterval() {
+
+ $parts = $this->getParts();
+ $value = $parts[0];
+ return DateTimeParser::parseDuration($value);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Period.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Period.php
new file mode 100644
index 0000000..67c818c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Period.php
@@ -0,0 +1,126 @@
+setValue(explode($this->delimiter, $val));
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ public function getRawMimeDirValue() {
+
+ return implode($this->delimiter, $this->getParts());
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ public function getValueType() {
+
+ return "PERIOD";
+
+ }
+
+ /**
+ * Sets the json value, as it would appear in a jCard or jCal object.
+ *
+ * The value must always be an array.
+ *
+ * @param array $value
+ * @return void
+ */
+ public function setJsonValue(array $value) {
+
+ $value = array_map(function($item) {
+
+ return strtr(implode('/', $item), array(':' => '', '-' => ''));
+
+ }, $value);
+ parent::setJsonValue($value);
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ public function getJsonValue() {
+
+ $return = array();
+ foreach($this->getParts() as $item) {
+
+ list($start, $end) = explode('/', $item, 2);
+
+ $start = DateTimeParser::parseDateTime($start);
+
+ // This is a duration value.
+ if ($end[0]==='P') {
+ $return[] = array(
+ $start->format('Y-m-d\\TH:i:s'),
+ $end
+ );
+ } else {
+ $end = DateTimeParser::parseDateTime($end);
+ $return[] = array(
+ $start->format('Y-m-d\\TH:i:s'),
+ $end->format('Y-m-d\\TH:i:s'),
+ );
+ }
+
+ }
+
+ return $return;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Recur.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Recur.php
new file mode 100644
index 0000000..98e3f19
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/ICalendar/Recur.php
@@ -0,0 +1,189 @@
+value array that is accessible using
+ * getParts, and may be set using setParts.
+ *
+ * @copyright Copyright (C) 2007-2013 fruux GmbH. All rights reserved.
+ * @author Evert Pot (http://evertpot.com/)
+ * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
+ */
+class Recur extends Property {
+
+ /**
+ * Updates the current value.
+ *
+ * This may be either a single, or multiple strings in an array.
+ *
+ * @param string|array $value
+ * @return void
+ */
+ public function setValue($value) {
+
+ // If we're getting the data from json, we'll be receiving an object
+ if ($value instanceof \StdClass) {
+ $value = (array)$value;
+ }
+
+ if (is_array($value)) {
+ $newVal = array();
+ foreach($value as $k=>$v) {
+
+ if (is_string($v)) {
+ $v = strtoupper($v);
+
+ // The value had multiple sub-values
+ if (strpos($v,',')!==false) {
+ $v = explode(',', $v);
+ }
+ } else {
+ $v = array_map('strtoupper', $v);
+ }
+
+ $newVal[strtoupper($k)] = $v;
+ }
+ $this->value = $newVal;
+ } elseif (is_string($value)) {
+ $value = strtoupper($value);
+ $newValue = array();
+ foreach(explode(';', $value) as $part) {
+
+ // Skipping empty parts.
+ if (empty($part)) {
+ continue;
+ }
+ list($partName, $partValue) = explode('=', $part);
+
+ // The value itself had multiple values..
+ if (strpos($partValue,',')!==false) {
+ $partValue=explode(',', $partValue);
+ }
+ $newValue[$partName] = $partValue;
+
+ }
+ $this->value = $newValue;
+ } else {
+ throw new \InvalidArgumentException('You must either pass a string, or a key=>value array');
+ }
+
+ }
+
+ /**
+ * Returns the current value.
+ *
+ * This method will always return a singular value. If this was a
+ * multi-value object, some decision will be made first on how to represent
+ * it as a string.
+ *
+ * To get the correct multi-value version, use getParts.
+ *
+ * @return string
+ */
+ public function getValue() {
+
+ $out = array();
+ foreach($this->value as $key=>$value) {
+ $out[] = $key . '=' . (is_array($value)?implode(',', $value):$value);
+ }
+ return strtoupper(implode(';',$out));
+
+ }
+
+ /**
+ * Sets a multi-valued property.
+ *
+ * @param array $parts
+ * @return void
+ */
+ public function setParts(array $parts) {
+
+ $this->setValue($parts);
+
+ }
+
+ /**
+ * Returns a multi-valued property.
+ *
+ * This method always returns an array, if there was only a single value,
+ * it will still be wrapped in an array.
+ *
+ * @return array
+ */
+ public function getParts() {
+
+ return $this->value;
+
+ }
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ * @return void
+ */
+ public function setRawMimeDirValue($val) {
+
+ $this->setValue($val);
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ public function getRawMimeDirValue() {
+
+ return $this->getValue();
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ public function getValueType() {
+
+ return "RECUR";
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ public function getJsonValue() {
+
+ $values = array();
+ foreach($this->getParts() as $k=>$v) {
+ $values[strtolower($k)] = $v;
+ }
+ return array($values);
+
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Integer.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Integer.php
new file mode 100644
index 0000000..a48c874
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Integer.php
@@ -0,0 +1,72 @@
+setValue((int)$val);
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ public function getRawMimeDirValue() {
+
+ return $this->value;
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ public function getValueType() {
+
+ return "INTEGER";
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ public function getJsonValue() {
+
+ return array((int)$this->getValue());
+
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Text.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Text.php
new file mode 100644
index 0000000..b1651e3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Text.php
@@ -0,0 +1,330 @@
+ 5,
+ 'ADR' => 7,
+ );
+
+ /**
+ * Creates the property.
+ *
+ * You can specify the parameters either in key=>value syntax, in which case
+ * parameters will automatically be created, or you can just pass a list of
+ * Parameter objects.
+ *
+ * @param Component $root The root document
+ * @param string $name
+ * @param string|array|null $value
+ * @param array $parameters List of parameters
+ * @param string $group The vcard property group
+ * @return void
+ */
+ public function __construct(Component $root, $name, $value = null, array $parameters = array(), $group = null) {
+
+ // There's two types of multi-valued text properties:
+ // 1. multivalue properties.
+ // 2. structured value properties
+ //
+ // The former is always separated by a comma, the latter by semi-colon.
+ if (in_array($name, $this->structuredValues)) {
+ $this->delimiter = ';';
+ }
+
+ parent::__construct($root, $name, $value, $parameters, $group);
+
+ }
+
+
+ /**
+ * Sets a raw value coming from a mimedir (iCalendar/vCard) file.
+ *
+ * This has been 'unfolded', so only 1 line will be passed. Unescaping is
+ * not yet done, but parameters are not included.
+ *
+ * @param string $val
+ * @return void
+ */
+ public function setRawMimeDirValue($val) {
+
+ $this->setValue(MimeDir::unescapeValue($val, $this->delimiter));
+
+ }
+
+ /**
+ * Sets the value as a quoted-printable encoded string.
+ *
+ * @param string $val
+ * @return void
+ */
+ public function setQuotedPrintableValue($val) {
+
+ $val = quoted_printable_decode($val);
+
+ // Quoted printable only appears in vCard 2.1, and the only character
+ // that may be escaped there is ;. So we are simply splitting on just
+ // that.
+ //
+ // We also don't have to unescape \\, so all we need to look for is a ;
+ // that's not preceeded with a \.
+ $regex = '# (?setValue($matches);
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ public function getRawMimeDirValue() {
+
+ $val = $this->getParts();
+
+ if (isset($this->minimumPropertyValues[$this->name])) {
+ $val = array_pad($val, $this->minimumPropertyValues[$this->name], '');
+ }
+
+ foreach($val as &$item) {
+
+ if (!is_array($item)) {
+ $item = array($item);
+ }
+
+ foreach($item as &$subItem) {
+ $subItem = strtr($subItem, array(
+ '\\' => '\\\\',
+ ';' => '\;',
+ ',' => '\,',
+ "\n" => '\n',
+ "\r" => "",
+ ));
+ }
+ $item = implode(',', $item);
+
+ }
+
+ return implode($this->delimiter, $val);
+
+ }
+
+ /**
+ * Returns the value, in the format it should be encoded for json.
+ *
+ * This method must always return an array.
+ *
+ * @return array
+ */
+ public function getJsonValue() {
+
+ // Structured text values should always be returned as a single
+ // array-item. Multi-value text should be returned as multiple items in
+ // the top-array.
+ if (in_array($this->name, $this->structuredValues)) {
+ return array($this->getParts());
+ } else {
+ return $this->getParts();
+ }
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ public function getValueType() {
+
+ return "TEXT";
+
+ }
+
+ /**
+ * Turns the object back into a serialized blob.
+ *
+ * @return string
+ */
+ public function serialize() {
+
+ // We need to kick in a special type of encoding, if it's a 2.1 vcard.
+ if ($this->root->getDocumentType() !== Document::VCARD21) {
+ return parent::serialize();
+ }
+
+ $val = $this->getParts();
+
+ if (isset($this->minimumPropertyValues[$this->name])) {
+ $val = array_pad($val, $this->minimumPropertyValues[$this->name], '');
+ }
+
+ // Imploding multiple parts into a single value, and splitting the
+ // values with ;.
+ if (count($val)>1) {
+ foreach($val as $k=>$v) {
+ $val[$k] = str_replace(';','\;', $v);
+ }
+ $val = implode(';', $val);
+ } else {
+ $val = $val[0];
+ }
+
+ $str = $this->name;
+ if ($this->group) $str = $this->group . '.' . $this->name;
+ foreach($this->parameters as $param) {
+
+ if ($param->getValue() === 'QUOTED-PRINTABLE') {
+ continue;
+ }
+ $str.=';' . $param->serialize();
+
+ }
+
+
+
+ // If the resulting value contains a \n, we must encode it as
+ // quoted-printable.
+ if (strpos($val,"\n") !== false) {
+
+ $str.=';ENCODING=QUOTED-PRINTABLE:';
+ $lastLine=$str;
+ $out = null;
+
+ // The PHP built-in quoted-printable-encode does not correctly
+ // encode newlines for us. Specifically, the \r\n sequence must in
+ // vcards be encoded as =0D=OA and we must insert soft-newlines
+ // every 75 bytes.
+ for($ii=0;$ii= 32 && $ord <=126) {
+ $lastLine.=$val[$ii];
+ } else {
+ $lastLine.='=' . strtoupper(bin2hex($val[$ii]));
+ }
+ if (strlen($lastLine)>=75) {
+ // Soft line break
+ $out.=$lastLine. "=\r\n ";
+ $lastLine = null;
+ }
+
+ }
+ if (!is_null($lastLine)) $out.= $lastLine . "\r\n";
+ return $out;
+
+ } else {
+ $str.=':' . $val;
+ $out = '';
+ while(strlen($str)>0) {
+ if (strlen($str)>75) {
+ $out.= mb_strcut($str,0,75,'utf-8') . "\r\n";
+ $str = ' ' . mb_strcut($str,75,strlen($str),'utf-8');
+ } else {
+ $out.=$str . "\r\n";
+ $str='';
+ break;
+ }
+ }
+
+ return $out;
+
+
+ }
+
+ }
+
+ /**
+ * Validates the node for correctness.
+ *
+ * The following options are supported:
+ * - Node::REPAIR - If something is broken, and automatic repair may
+ * be attempted.
+ *
+ * An array is returned with warnings.
+ *
+ * Every item in the array has the following properties:
+ * * level - (number between 1 and 3 with severity information)
+ * * message - (human readable message)
+ * * node - (reference to the offending node)
+ *
+ * @param int $options
+ * @return array
+ */
+ public function validate($options = 0) {
+
+ $warnings = parent::validate($options);
+
+ if (isset($this->minimumPropertyValues[$this->name])) {
+
+ $minimum = $this->minimumPropertyValues[$this->name];
+ $parts = $this->getParts();
+ if (count($parts) < $minimum) {
+ $warnings[] = array(
+ 'level' => 1,
+ 'message' => 'This property must have at least ' . $minimum . ' components. It only has ' . count($parts),
+ 'node' => $this,
+ );
+ if ($options & self::REPAIR) {
+ $parts = array_pad($parts, $minimum, '');
+ $this->setParts($parts);
+ }
+ }
+
+ }
+ return $warnings;
+
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Time.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Time.php
new file mode 100644
index 0000000..394e37f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Time.php
@@ -0,0 +1,94 @@
+getValue());
+
+ $timeStr = '';
+
+ // Hour
+ if (!is_null($parts['hour'])) {
+ $timeStr.=$parts['hour'];
+
+ if (!is_null($parts['minute'])) {
+ $timeStr.=':';
+ }
+ } else {
+ // We know either minute or second _must_ be set, so we insert a
+ // dash for an empty value.
+ $timeStr.='-';
+ }
+
+ // Minute
+ if (!is_null($parts['minute'])) {
+ $timeStr.=$parts['minute'];
+
+ if (!is_null($parts['second'])) {
+ $timeStr.=':';
+ }
+ } else {
+ if (isset($parts['second'])) {
+ // Dash for empty minute
+ $timeStr.='-';
+ }
+ }
+
+ // Second
+ if (!is_null($parts['second'])) {
+ $timeStr.=$parts['second'];
+ }
+
+ // Timezone
+ if (!is_null($parts['timezone'])) {
+ $timeStr.=$parts['timezone'];
+ }
+
+ return array($timeStr);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Unknown.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Unknown.php
new file mode 100644
index 0000000..c2a4951
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Unknown.php
@@ -0,0 +1,50 @@
+getRawMimeDirValue());
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ public function getValueType() {
+
+ return "UNKNOWN";
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Uri.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Uri.php
new file mode 100644
index 0000000..b610780
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/Uri.php
@@ -0,0 +1,70 @@
+value = $val;
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ public function getRawMimeDirValue() {
+
+ if (is_array($this->value)) {
+ return $this->value[0];
+ } else {
+ return $this->value;
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/UtcOffset.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/UtcOffset.php
new file mode 100644
index 0000000..f2d0d17
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/UtcOffset.php
@@ -0,0 +1,37 @@
+getValue());
+
+ $dateStr = '';
+
+ // Year
+ if (!is_null($parts['year'])) {
+ $dateStr.=$parts['year'];
+
+ if (!is_null($parts['month'])) {
+ // If a year and a month is set, we need to insert a separator
+ // dash.
+ $dateStr.='-';
+ }
+
+ } else {
+
+ if (!is_null($parts['month']) || !is_null($parts['date'])) {
+ // Inserting two dashes
+ $dateStr.='--';
+ }
+
+ }
+
+ // Month
+
+ if (!is_null($parts['month'])) {
+ $dateStr.=$parts['month'];
+
+ if (isset($parts['date'])) {
+ // If month and date are set, we need the separator dash.
+ $dateStr.='-';
+ }
+ } else {
+ if (isset($parts['date'])) {
+ // If the month is empty, and a date is set, we need a 'empty
+ // dash'
+ $dateStr.='-';
+ }
+ }
+
+ // Date
+ if (!is_null($parts['date'])) {
+ $dateStr.=$parts['date'];
+ }
+
+
+ // Early exit if we don't have a time string.
+ if (is_null($parts['hour']) && is_null($parts['minute']) && is_null($parts['second'])) {
+ return array($dateStr);
+ }
+
+ $dateStr.='T';
+
+ // Hour
+ if (!is_null($parts['hour'])) {
+ $dateStr.=$parts['hour'];
+
+ if (!is_null($parts['minute'])) {
+ $dateStr.=':';
+ }
+ } else {
+ // We know either minute or second _must_ be set, so we insert a
+ // dash for an empty value.
+ $dateStr.='-';
+ }
+
+ // Minute
+ if (!is_null($parts['minute'])) {
+ $dateStr.=$parts['minute'];
+
+ if (!is_null($parts['second'])) {
+ $dateStr.=':';
+ }
+ } else {
+ if (isset($parts['second'])) {
+ // Dash for empty minute
+ $dateStr.='-';
+ }
+ }
+
+ // Second
+ if (!is_null($parts['second'])) {
+ $dateStr.=$parts['second'];
+ }
+
+ // Timezone
+ if (!is_null($parts['timezone'])) {
+ $dateStr.=$parts['timezone'];
+ }
+
+ return array($dateStr);
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateTime.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateTime.php
new file mode 100644
index 0000000..ae8ffd3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/VCard/DateTime.php
@@ -0,0 +1,33 @@
+setValue($val);
+
+ }
+
+ /**
+ * Returns a raw mime-dir representation of the value.
+ *
+ * @return string
+ */
+ public function getRawMimeDirValue() {
+
+ return $this->value;
+
+ }
+
+ /**
+ * Returns the type of value.
+ *
+ * This corresponds to the VALUE= parameter. Every property also has a
+ * 'default' valueType.
+ *
+ * @return string
+ */
+ public function getValueType() {
+
+ return "LANGUAGE-TAG";
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/VCard/TimeStamp.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/VCard/TimeStamp.php
new file mode 100644
index 0000000..00522dc
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Property/VCard/TimeStamp.php
@@ -0,0 +1,69 @@
+getValue());
+
+ $dateStr =
+ $parts['year'] . '-' .
+ $parts['month'] . '-' .
+ $parts['date'] . 'T' .
+ $parts['hour'] . ':' .
+ $parts['minute'] . ':' .
+ $parts['second'];
+
+ // Timezone
+ if (!is_null($parts['timezone'])) {
+ $dateStr.=$parts['timezone'];
+ }
+
+ return array($dateStr);
+
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Reader.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Reader.php
new file mode 100644
index 0000000..89432f1
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Reader.php
@@ -0,0 +1,73 @@
+parse($data, $options);
+
+ return $result;
+
+ }
+
+ /**
+ * Parses a jCard or jCal object, and returns the top component.
+ *
+ * The options argument is a bitfield. Pass any of the OPTIONS constant to
+ * alter the parsers' behaviour.
+ *
+ * You can either a string, a readable stream, or an array for it's input.
+ * Specifying the array is useful if json_decode was already called on the
+ * input.
+ *
+ * @param string|resource|array $data
+ * @param int $options
+ * @return Node
+ */
+ static function readJson($data, $options = 0) {
+
+ $parser = new Parser\Json();
+ $result = $parser->parse($data, $options);
+
+ return $result;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/RecurrenceIterator.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/RecurrenceIterator.php
new file mode 100644
index 0000000..5d6d8e2
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/RecurrenceIterator.php
@@ -0,0 +1,1153 @@
+ 0,
+ 'MO' => 1,
+ 'TU' => 2,
+ 'WE' => 3,
+ 'TH' => 4,
+ 'FR' => 5,
+ 'SA' => 6,
+ );
+
+ /**
+ * Mappings between the day number and english day name.
+ *
+ * @var array
+ */
+ private $dayNames = array(
+ 0 => 'Sunday',
+ 1 => 'Monday',
+ 2 => 'Tuesday',
+ 3 => 'Wednesday',
+ 4 => 'Thursday',
+ 5 => 'Friday',
+ 6 => 'Saturday',
+ );
+
+ /**
+ * If the current iteration of the event is an overriden event, this
+ * property will hold the VObject
+ *
+ * @var Component
+ */
+ private $currentOverriddenEvent;
+
+ /**
+ * This property may contain the date of the next not-overridden event.
+ * This date is calculated sometimes a bit early, before overridden events
+ * are evaluated.
+ *
+ * @var DateTime
+ */
+ private $nextDate;
+
+ /**
+ * This counts the number of overridden events we've handled so far
+ *
+ * @var int
+ */
+ private $handledOverridden = 0;
+
+ /**
+ * Creates the iterator
+ *
+ * You should pass a VCALENDAR component, as well as the UID of the event
+ * we're going to traverse.
+ *
+ * @param Component $vcal
+ * @param string|null $uid
+ */
+ public function __construct(Component $vcal, $uid=null) {
+
+ if (is_null($uid)) {
+ if ($vcal instanceof Component\VCalendar) {
+ throw new \InvalidArgumentException('If you pass a VCALENDAR object, you must pass a uid argument as well');
+ }
+ $components = array($vcal);
+ $uid = (string)$vcal->uid;
+ } else {
+ $components = $vcal->select('VEVENT');
+ }
+ foreach($components as $component) {
+ if ((string)$component->uid == $uid) {
+ if (isset($component->{'RECURRENCE-ID'})) {
+ $this->overriddenEvents[$component->DTSTART->getDateTime()->getTimeStamp()] = $component;
+ $this->overriddenDates[] = $component->{'RECURRENCE-ID'}->getDateTime();
+ } else {
+ $this->baseEvent = $component;
+ }
+ }
+ }
+
+ ksort($this->overriddenEvents);
+
+ if (!$this->baseEvent) {
+ // No base event was found. CalDAV does allow cases where only
+ // overridden instances are stored.
+ //
+ // In this barticular case, we're just going to grab the first
+ // event and use that instead. This may not always give the
+ // desired result.
+ if (!count($this->overriddenEvents)) {
+ throw new \InvalidArgumentException('Could not find an event with uid: ' . $uid);
+ }
+ ksort($this->overriddenEvents, SORT_NUMERIC);
+ $this->baseEvent = array_shift($this->overriddenEvents);
+ }
+
+ $this->startDate = clone $this->baseEvent->DTSTART->getDateTime();
+
+ $this->endDate = null;
+ if (isset($this->baseEvent->DTEND)) {
+ $this->endDate = clone $this->baseEvent->DTEND->getDateTime();
+ } else {
+ $this->endDate = clone $this->startDate;
+ if (isset($this->baseEvent->DURATION)) {
+ $this->endDate->add(DateTimeParser::parse((string)$this->baseEvent->DURATION));
+ } elseif (!$this->baseEvent->DTSTART->hasTime()) {
+ $this->endDate->modify('+1 day');
+ }
+ }
+ $this->currentDate = clone $this->startDate;
+
+ $rrule = $this->baseEvent->RRULE;
+
+ // If no rrule was specified, we create a default setting
+ if (!$rrule) {
+ $this->frequency = 'daily';
+ $this->count = 1;
+ } else foreach($rrule->getParts() as $key=>$value) {
+
+ switch($key) {
+
+ case 'FREQ' :
+ if (!in_array(
+ strtolower($value),
+ array('secondly','minutely','hourly','daily','weekly','monthly','yearly')
+ )) {
+ throw new \InvalidArgumentException('Unknown value for FREQ=' . strtoupper($value));
+
+ }
+ $this->frequency = strtolower($value);
+ break;
+
+ case 'UNTIL' :
+ $this->until = DateTimeParser::parse($value);
+
+ // In some cases events are generated with an UNTIL=
+ // parameter before the actual start of the event.
+ //
+ // Not sure why this is happening. We assume that the
+ // intention was that the event only recurs once.
+ //
+ // So we are modifying the parameter so our code doesn't
+ // break.
+ if($this->until < $this->baseEvent->DTSTART->getDateTime()) {
+ $this->until = $this->baseEvent->DTSTART->getDateTime();
+ }
+ break;
+
+ case 'COUNT' :
+ $this->count = (int)$value;
+ break;
+
+ case 'INTERVAL' :
+ $this->interval = (int)$value;
+ if ($this->interval < 1) {
+ throw new \InvalidArgumentException('INTERVAL in RRULE must be a positive integer!');
+ }
+ break;
+
+ case 'BYSECOND' :
+ $this->bySecond = (array)$value;
+ break;
+
+ case 'BYMINUTE' :
+ $this->byMinute = (array)$value;
+ break;
+
+ case 'BYHOUR' :
+ $this->byHour = (array)$value;
+ break;
+
+ case 'BYDAY' :
+ $this->byDay = (array)$value;
+ break;
+
+ case 'BYMONTHDAY' :
+ $this->byMonthDay = (array)$value;
+ break;
+
+ case 'BYYEARDAY' :
+ $this->byYearDay = (array)$value;
+ break;
+
+ case 'BYWEEKNO' :
+ $this->byWeekNo = (array)$value;
+ break;
+
+ case 'BYMONTH' :
+ $this->byMonth = (array)$value;
+ break;
+
+ case 'BYSETPOS' :
+ $this->bySetPos = (array)$value;
+ break;
+
+ case 'WKST' :
+ $this->weekStart = strtoupper($value);
+ break;
+
+ }
+
+ }
+
+ // Parsing exception dates
+ if (isset($this->baseEvent->EXDATE)) {
+ foreach($this->baseEvent->EXDATE as $exDate) {
+
+ foreach(explode(',', (string)$exDate) as $exceptionDate) {
+
+ $this->exceptionDates[] =
+ DateTimeParser::parse($exceptionDate, $this->startDate->getTimeZone());
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /**
+ * Returns the current item in the list
+ *
+ * @return DateTime
+ */
+ public function current() {
+
+ if (!$this->valid()) return null;
+ return clone $this->currentDate;
+
+ }
+
+ /**
+ * This method returns the startdate for the current iteration of the
+ * event.
+ *
+ * @return DateTime
+ */
+ public function getDtStart() {
+
+ if (!$this->valid()) return null;
+ return clone $this->currentDate;
+
+ }
+
+ /**
+ * This method returns the enddate for the current iteration of the
+ * event.
+ *
+ * @return DateTime
+ */
+ public function getDtEnd() {
+
+ if (!$this->valid()) return null;
+ $dtEnd = clone $this->currentDate;
+ $dtEnd->add( $this->startDate->diff( $this->endDate ) );
+ return clone $dtEnd;
+
+ }
+
+ /**
+ * Returns a VEVENT object with the updated start and end date.
+ *
+ * Any recurrence information is removed, and this function may return an
+ * 'overridden' event instead.
+ *
+ * This method always returns a cloned instance.
+ *
+ * @return Component\VEvent
+ */
+ public function getEventObject() {
+
+ if ($this->currentOverriddenEvent) {
+ return clone $this->currentOverriddenEvent;
+ }
+ $event = clone $this->baseEvent;
+ unset($event->RRULE);
+ unset($event->EXDATE);
+ unset($event->RDATE);
+ unset($event->EXRULE);
+
+ $event->DTSTART->setDateTime($this->getDTStart());
+ if (isset($event->DTEND)) {
+ $event->DTEND->setDateTime($this->getDtEnd());
+ }
+ if ($this->counter > 0) {
+ $event->{'RECURRENCE-ID'} = (string)$event->DTSTART;
+ }
+
+ return $event;
+
+ }
+
+ /**
+ * Returns the current item number
+ *
+ * @return int
+ */
+ public function key() {
+
+ return $this->counter;
+
+ }
+
+ /**
+ * Whether or not there is a 'next item'
+ *
+ * @return bool
+ */
+ public function valid() {
+
+ if (!is_null($this->count)) {
+ return $this->counter < $this->count;
+ }
+ if (!is_null($this->until) && $this->currentDate > $this->until) {
+
+ // Need to make sure there's no overridden events past the
+ // until date.
+ foreach($this->overriddenEvents as $overriddenEvent) {
+
+ if ($overriddenEvent->DTSTART->getDateTime() >= $this->currentDate) {
+
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+
+ }
+
+ /**
+ * Resets the iterator
+ *
+ * @return void
+ */
+ public function rewind() {
+
+ $this->currentDate = clone $this->startDate;
+ $this->counter = 0;
+
+ }
+
+ /**
+ * This method allows you to quickly go to the next occurrence after the
+ * specified date.
+ *
+ * Note that this checks the current 'endDate', not the 'stardDate'. This
+ * means that if you forward to January 1st, the iterator will stop at the
+ * first event that ends *after* January 1st.
+ *
+ * @param DateTime $dt
+ * @return void
+ */
+ public function fastForward(\DateTime $dt) {
+
+ while($this->valid() && $this->getDTEnd() <= $dt) {
+ $this->next();
+ }
+
+ }
+
+ /**
+ * Returns true if this recurring event never ends.
+ *
+ * @return bool
+ */
+ public function isInfinite() {
+
+ return !$this->count && !$this->until;
+
+ }
+
+ /**
+ * Goes on to the next iteration
+ *
+ * @return void
+ */
+ public function next() {
+
+ $previousStamp = $this->currentDate->getTimeStamp();
+
+ // Finding the next overridden event in line, and storing that for
+ // later use.
+ $overriddenEvent = null;
+ $overriddenDate = null;
+ $this->currentOverriddenEvent = null;
+
+ foreach($this->overriddenEvents as $index=>$event) {
+ if ($index > $previousStamp) {
+ $overriddenEvent = $event;
+ $overriddenDate = clone $event->DTSTART->getDateTime();
+ break;
+ }
+ }
+
+ // If we have a stored 'next date', we will use that.
+ if ($this->nextDate) {
+ if (!$overriddenDate || $this->nextDate < $overriddenDate) {
+ $this->currentDate = $this->nextDate;
+ $currentStamp = $this->currentDate->getTimeStamp();
+ $this->nextDate = null;
+ } else {
+ $this->currentDate = clone $overriddenDate;
+ $this->currentOverriddenEvent = $overriddenEvent;
+ }
+ $this->counter++;
+ return;
+ }
+
+ while(true) {
+
+ // Otherwise, we find the next event in the normal RRULE
+ // sequence.
+ switch($this->frequency) {
+
+ case 'hourly' :
+ $this->nextHourly();
+ break;
+
+ case 'daily' :
+ $this->nextDaily();
+ break;
+
+ case 'weekly' :
+ $this->nextWeekly();
+ break;
+
+ case 'monthly' :
+ $this->nextMonthly();
+ break;
+
+ case 'yearly' :
+ $this->nextYearly();
+ break;
+
+ }
+ $currentStamp = $this->currentDate->getTimeStamp();
+
+
+ // Checking exception dates
+ foreach($this->exceptionDates as $exceptionDate) {
+ if ($this->currentDate == $exceptionDate) {
+ $this->counter++;
+ continue 2;
+ }
+ }
+ foreach($this->overriddenDates as $check) {
+ if ($this->currentDate == $check) {
+ continue 2;
+ }
+ }
+ break;
+
+ }
+
+
+
+ // Is the date we have actually higher than the next overiddenEvent?
+ if ($overriddenDate && $this->currentDate > $overriddenDate) {
+ $this->nextDate = clone $this->currentDate;
+ $this->currentDate = clone $overriddenDate;
+ $this->currentOverriddenEvent = $overriddenEvent;
+ $this->handledOverridden++;
+ }
+ $this->counter++;
+
+
+ /*
+ * If we have overridden events left in the queue, but our counter is
+ * running out, we should grab one of those.
+ */
+ if (!is_null($overriddenEvent) && !is_null($this->count) && count($this->overriddenEvents) - $this->handledOverridden >= ($this->count - $this->counter)) {
+
+ $this->currentOverriddenEvent = $overriddenEvent;
+ $this->currentDate = clone $overriddenDate;
+ $this->handledOverridden++;
+
+ }
+
+ }
+
+ /**
+ * Does the processing for advancing the iterator for hourly frequency.
+ *
+ * @return void
+ */
+ protected function nextHourly() {
+
+ if (!$this->byHour) {
+ $this->currentDate->modify('+' . $this->interval . ' hours');
+ return;
+ }
+ // @codeCoverageIgnoreStart
+ }
+ // @codeCoverageIgnoreEnd
+
+ /**
+ * Does the processing for advancing the iterator for daily frequency.
+ *
+ * @return void
+ */
+ protected function nextDaily() {
+
+ if (!$this->byHour && !$this->byDay) {
+ $this->currentDate->modify('+' . $this->interval . ' days');
+ return;
+ }
+
+ if (isset($this->byHour)) {
+ $recurrenceHours = $this->getHours();
+ }
+
+ if (isset($this->byDay)) {
+ $recurrenceDays = $this->getDays();
+ }
+
+ do {
+
+ if ($this->byHour) {
+ if ($this->currentDate->format('G') == '23') {
+ // to obey the interval rule
+ $this->currentDate->modify('+' . $this->interval-1 . ' days');
+ }
+
+ $this->currentDate->modify('+1 hours');
+
+ } else {
+ $this->currentDate->modify('+' . $this->interval . ' days');
+
+ }
+
+ // Current day of the week
+ $currentDay = $this->currentDate->format('w');
+
+ // Current hour of the day
+ $currentHour = $this->currentDate->format('G');
+
+ } while (($this->byDay && !in_array($currentDay, $recurrenceDays)) || ($this->byHour && !in_array($currentHour, $recurrenceHours)));
+
+ }
+
+ /**
+ * Does the processing for advancing the iterator for weekly frequency.
+ *
+ * @return void
+ */
+ protected function nextWeekly() {
+
+ if (!$this->byHour && !$this->byDay) {
+ $this->currentDate->modify('+' . $this->interval . ' weeks');
+ return;
+ }
+
+ if ($this->byHour) {
+ $recurrenceHours = $this->getHours();
+ }
+
+ if ($this->byDay) {
+ $recurrenceDays = $this->getDays();
+ }
+
+ // First day of the week:
+ $firstDay = $this->dayMap[$this->weekStart];
+
+ do {
+
+ if ($this->byHour) {
+ $this->currentDate->modify('+1 hours');
+ } else {
+ $this->currentDate->modify('+1 days');
+ }
+
+ // Current day of the week
+ $currentDay = (int) $this->currentDate->format('w');
+
+ // Current hour of the day
+ $currentHour = (int) $this->currentDate->format('G');
+
+ // We need to roll over to the next week
+ if ($currentDay === $firstDay && (!$this->byHour || $currentHour == '0')) {
+ $this->currentDate->modify('+' . $this->interval-1 . ' weeks');
+
+ // We need to go to the first day of this week, but only if we
+ // are not already on this first day of this week.
+ if($this->currentDate->format('w') != $firstDay) {
+ $this->currentDate->modify('last ' . $this->dayNames[$this->dayMap[$this->weekStart]]);
+ }
+ }
+
+ // We have a match
+ } while (($this->byDay && !in_array($currentDay, $recurrenceDays)) || ($this->byHour && !in_array($currentHour, $recurrenceHours)));
+ }
+
+ /**
+ * Does the processing for advancing the iterator for monthly frequency.
+ *
+ * @return void
+ */
+ protected function nextMonthly() {
+
+ $currentDayOfMonth = $this->currentDate->format('j');
+ if (!$this->byMonthDay && !$this->byDay) {
+
+ // If the current day is higher than the 28th, rollover can
+ // occur to the next month. We Must skip these invalid
+ // entries.
+ if ($currentDayOfMonth < 29) {
+ $this->currentDate->modify('+' . $this->interval . ' months');
+ } else {
+ $increase = 0;
+ do {
+ $increase++;
+ $tempDate = clone $this->currentDate;
+ $tempDate->modify('+ ' . ($this->interval*$increase) . ' months');
+ } while ($tempDate->format('j') != $currentDayOfMonth);
+ $this->currentDate = $tempDate;
+ }
+ return;
+ }
+
+ while(true) {
+
+ $occurrences = $this->getMonthlyOccurrences();
+
+ foreach($occurrences as $occurrence) {
+
+ // The first occurrence thats higher than the current
+ // day of the month wins.
+ if ($occurrence > $currentDayOfMonth) {
+ break 2;
+ }
+
+ }
+
+ // If we made it all the way here, it means there were no
+ // valid occurrences, and we need to advance to the next
+ // month.
+ $this->currentDate->modify('first day of this month');
+ $this->currentDate->modify('+ ' . $this->interval . ' months');
+
+ // This goes to 0 because we need to start counting at hte
+ // beginning.
+ $currentDayOfMonth = 0;
+
+ }
+
+ $this->currentDate->setDate($this->currentDate->format('Y'), $this->currentDate->format('n'), $occurrence);
+
+ }
+
+ /**
+ * Does the processing for advancing the iterator for yearly frequency.
+ *
+ * @return void
+ */
+ protected function nextYearly() {
+
+ $currentMonth = $this->currentDate->format('n');
+ $currentYear = $this->currentDate->format('Y');
+ $currentDayOfMonth = $this->currentDate->format('j');
+
+ // No sub-rules, so we just advance by year
+ if (!$this->byMonth) {
+
+ // Unless it was a leap day!
+ if ($currentMonth==2 && $currentDayOfMonth==29) {
+
+ $counter = 0;
+ do {
+ $counter++;
+ // Here we increase the year count by the interval, until
+ // we hit a date that's also in a leap year.
+ //
+ // We could just find the next interval that's dividable by
+ // 4, but that would ignore the rule that there's no leap
+ // year every year that's dividable by a 100, but not by
+ // 400. (1800, 1900, 2100). So we just rely on the datetime
+ // functions instead.
+ $nextDate = clone $this->currentDate;
+ $nextDate->modify('+ ' . ($this->interval*$counter) . ' years');
+ } while ($nextDate->format('n')!=2);
+ $this->currentDate = $nextDate;
+
+ return;
+
+ }
+
+ // The easiest form
+ $this->currentDate->modify('+' . $this->interval . ' years');
+ return;
+
+ }
+
+ $currentMonth = $this->currentDate->format('n');
+ $currentYear = $this->currentDate->format('Y');
+ $currentDayOfMonth = $this->currentDate->format('j');
+
+ $advancedToNewMonth = false;
+
+ // If we got a byDay or getMonthDay filter, we must first expand
+ // further.
+ if ($this->byDay || $this->byMonthDay) {
+
+ while(true) {
+
+ $occurrences = $this->getMonthlyOccurrences();
+
+ foreach($occurrences as $occurrence) {
+
+ // The first occurrence that's higher than the current
+ // day of the month wins.
+ // If we advanced to the next month or year, the first
+ // occurrence is always correct.
+ if ($occurrence > $currentDayOfMonth || $advancedToNewMonth) {
+ break 2;
+ }
+
+ }
+
+ // If we made it here, it means we need to advance to
+ // the next month or year.
+ $currentDayOfMonth = 1;
+ $advancedToNewMonth = true;
+ do {
+
+ $currentMonth++;
+ if ($currentMonth>12) {
+ $currentYear+=$this->interval;
+ $currentMonth = 1;
+ }
+ } while (!in_array($currentMonth, $this->byMonth));
+
+ $this->currentDate->setDate($currentYear, $currentMonth, $currentDayOfMonth);
+
+ }
+
+ // If we made it here, it means we got a valid occurrence
+ $this->currentDate->setDate($currentYear, $currentMonth, $occurrence);
+ return;
+
+ } else {
+
+ // These are the 'byMonth' rules, if there are no byDay or
+ // byMonthDay sub-rules.
+ do {
+
+ $currentMonth++;
+ if ($currentMonth>12) {
+ $currentYear+=$this->interval;
+ $currentMonth = 1;
+ }
+ } while (!in_array($currentMonth, $this->byMonth));
+ $this->currentDate->setDate($currentYear, $currentMonth, $currentDayOfMonth);
+
+ return;
+
+ }
+
+ }
+
+ /**
+ * Returns all the occurrences for a monthly frequency with a 'byDay' or
+ * 'byMonthDay' expansion for the current month.
+ *
+ * The returned list is an array of integers with the day of month (1-31).
+ *
+ * @return array
+ */
+ protected function getMonthlyOccurrences() {
+
+ $startDate = clone $this->currentDate;
+
+ $byDayResults = array();
+
+ // Our strategy is to simply go through the byDays, advance the date to
+ // that point and add it to the results.
+ if ($this->byDay) foreach($this->byDay as $day) {
+
+ $dayName = $this->dayNames[$this->dayMap[substr($day,-2)]];
+
+ // Dayname will be something like 'wednesday'. Now we need to find
+ // all wednesdays in this month.
+ $dayHits = array();
+
+ $checkDate = clone $startDate;
+ $checkDate->modify('first day of this month');
+ $checkDate->modify($dayName);
+
+ do {
+ $dayHits[] = $checkDate->format('j');
+ $checkDate->modify('next ' . $dayName);
+ } while ($checkDate->format('n') === $startDate->format('n'));
+
+ // So now we have 'all wednesdays' for month. It is however
+ // possible that the user only really wanted the 1st, 2nd or last
+ // wednesday.
+ if (strlen($day)>2) {
+ $offset = (int)substr($day,0,-2);
+
+ if ($offset>0) {
+ // It is possible that the day does not exist, such as a
+ // 5th or 6th wednesday of the month.
+ if (isset($dayHits[$offset-1])) {
+ $byDayResults[] = $dayHits[$offset-1];
+ }
+ } else {
+
+ // if it was negative we count from the end of the array
+ $byDayResults[] = $dayHits[count($dayHits) + $offset];
+ }
+ } else {
+ // There was no counter (first, second, last wednesdays), so we
+ // just need to add the all to the list).
+ $byDayResults = array_merge($byDayResults, $dayHits);
+
+ }
+
+ }
+
+ $byMonthDayResults = array();
+ if ($this->byMonthDay) foreach($this->byMonthDay as $monthDay) {
+
+ // Removing values that are out of range for this month
+ if ($monthDay > $startDate->format('t') ||
+ $monthDay < 0-$startDate->format('t')) {
+ continue;
+ }
+ if ($monthDay>0) {
+ $byMonthDayResults[] = $monthDay;
+ } else {
+ // Negative values
+ $byMonthDayResults[] = $startDate->format('t') + 1 + $monthDay;
+ }
+ }
+
+ // If there was just byDay or just byMonthDay, they just specify our
+ // (almost) final list. If both were provided, then byDay limits the
+ // list.
+ if ($this->byMonthDay && $this->byDay) {
+ $result = array_intersect($byMonthDayResults, $byDayResults);
+ } elseif ($this->byMonthDay) {
+ $result = $byMonthDayResults;
+ } else {
+ $result = $byDayResults;
+ }
+ $result = array_unique($result);
+ sort($result, SORT_NUMERIC);
+
+ // The last thing that needs checking is the BYSETPOS. If it's set, it
+ // means only certain items in the set survive the filter.
+ if (!$this->bySetPos) {
+ return $result;
+ }
+
+ $filteredResult = array();
+ foreach($this->bySetPos as $setPos) {
+
+ if ($setPos<0) {
+ $setPos = count($result)-($setPos+1);
+ }
+ if (isset($result[$setPos-1])) {
+ $filteredResult[] = $result[$setPos-1];
+ }
+ }
+
+ sort($filteredResult, SORT_NUMERIC);
+ return $filteredResult;
+
+ }
+
+ protected function getHours()
+ {
+ $recurrenceHours = array();
+ foreach($this->byHour as $byHour) {
+ $recurrenceHours[] = $byHour;
+ }
+
+ return $recurrenceHours;
+ }
+
+ protected function getDays()
+ {
+ $recurrenceDays = array();
+ foreach($this->byDay as $byDay) {
+
+ // The day may be preceeded with a positive (+n) or
+ // negative (-n) integer. However, this does not make
+ // sense in 'weekly' so we ignore it here.
+ $recurrenceDays[] = $this->dayMap[substr($byDay,-2)];
+
+ }
+
+ return $recurrenceDays;
+ }
+}
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Splitter/ICalendar.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Splitter/ICalendar.php
new file mode 100644
index 0000000..eb5db80
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Splitter/ICalendar.php
@@ -0,0 +1,114 @@
+children() as $component) {
+ if (!$component instanceof VObject\Component) {
+ continue;
+ }
+
+ // Get all timezones
+ if ($component->name === 'VTIMEZONE') {
+ $this->vtimezones[(string)$component->TZID] = $component;
+ continue;
+ }
+
+ // Get component UID for recurring Events search
+ if($component->UID) {
+ $uid = (string)$component->UID;
+ } else {
+ // Generating a random UID
+ $uid = sha1(microtime()) . '-vobjectimport';
+ }
+
+ // Take care of recurring events
+ if (!array_key_exists($uid, $this->objects)) {
+ $this->objects[$uid] = new VCalendar();
+ }
+
+ $this->objects[$uid]->add(clone $component);
+ }
+
+ }
+
+ /**
+ * Every time getNext() is called, a new object will be parsed, until we
+ * hit the end of the stream.
+ *
+ * When the end is reached, null will be returned.
+ *
+ * @return SabreForRainLoop\VObject\Component|null
+ */
+ public function getNext() {
+
+ if($object=array_shift($this->objects)) {
+
+ // create our baseobject
+ $object->version = '2.0';
+ $object->prodid = '-//Sabre//Sabre VObject ' . VObject\Version::VERSION . '//EN';
+ $object->calscale = 'GREGORIAN';
+
+ // add vtimezone information to obj (if we have it)
+ foreach ($this->vtimezones as $vtimezone) {
+ $object->add($vtimezone);
+ }
+
+ return $object;
+
+ } else {
+
+ return null;
+
+ }
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Splitter/SplitterInterface.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Splitter/SplitterInterface.php
new file mode 100644
index 0000000..116da8a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Splitter/SplitterInterface.php
@@ -0,0 +1,39 @@
+input = $input;
+ $this->parser = new MimeDir($input, $options);
+
+ }
+
+ /**
+ * Every time getNext() is called, a new object will be parsed, until we
+ * hit the end of the stream.
+ *
+ * When the end is reached, null will be returned.
+ *
+ * @return SabreForRainLoop\VObject\Component|null
+ */
+ public function getNext() {
+
+ try {
+ $object = $this->parser->parse();
+ } catch (VObject\EofException $e) {
+ return null;
+ }
+
+ return $object;
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/StringUtil.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/StringUtil.php
new file mode 100644
index 0000000..3901137
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/StringUtil.php
@@ -0,0 +1,61 @@
+'Australia/Darwin',
+ 'AUS Eastern Standard Time'=>'Australia/Sydney',
+ 'Afghanistan Standard Time'=>'Asia/Kabul',
+ 'Alaskan Standard Time'=>'America/Anchorage',
+ 'Arab Standard Time'=>'Asia/Riyadh',
+ 'Arabian Standard Time'=>'Asia/Dubai',
+ 'Arabic Standard Time'=>'Asia/Baghdad',
+ 'Argentina Standard Time'=>'America/Buenos_Aires',
+ 'Armenian Standard Time'=>'Asia/Yerevan',
+ 'Atlantic Standard Time'=>'America/Halifax',
+ 'Azerbaijan Standard Time'=>'Asia/Baku',
+ 'Azores Standard Time'=>'Atlantic/Azores',
+ 'Bangladesh Standard Time'=>'Asia/Dhaka',
+ 'Canada Central Standard Time'=>'America/Regina',
+ 'Cape Verde Standard Time'=>'Atlantic/Cape_Verde',
+ 'Caucasus Standard Time'=>'Asia/Yerevan',
+ 'Cen. Australia Standard Time'=>'Australia/Adelaide',
+ 'Central America Standard Time'=>'America/Guatemala',
+ 'Central Asia Standard Time'=>'Asia/Almaty',
+ 'Central Brazilian Standard Time'=>'America/Cuiaba',
+ 'Central Europe Standard Time'=>'Europe/Budapest',
+ 'Central European Standard Time'=>'Europe/Warsaw',
+ 'Central Pacific Standard Time'=>'Pacific/Guadalcanal',
+ 'Central Standard Time'=>'America/Chicago',
+ 'Central Standard Time (Mexico)'=>'America/Mexico_City',
+ 'China Standard Time'=>'Asia/Shanghai',
+ 'Dateline Standard Time'=>'Etc/GMT+12',
+ 'E. Africa Standard Time'=>'Africa/Nairobi',
+ 'E. Australia Standard Time'=>'Australia/Brisbane',
+ 'E. Europe Standard Time'=>'Europe/Minsk',
+ 'E. South America Standard Time'=>'America/Sao_Paulo',
+ 'Eastern Standard Time'=>'America/New_York',
+ 'Egypt Standard Time'=>'Africa/Cairo',
+ 'Ekaterinburg Standard Time'=>'Asia/Yekaterinburg',
+ 'FLE Standard Time'=>'Europe/Kiev',
+ 'Fiji Standard Time'=>'Pacific/Fiji',
+ 'GMT Standard Time'=>'Europe/London',
+ 'GTB Standard Time'=>'Europe/Istanbul',
+ 'Georgian Standard Time'=>'Asia/Tbilisi',
+ 'Greenland Standard Time'=>'America/Godthab',
+ 'Greenwich Standard Time'=>'Atlantic/Reykjavik',
+ 'Hawaiian Standard Time'=>'Pacific/Honolulu',
+ 'India Standard Time'=>'Asia/Calcutta',
+ 'Iran Standard Time'=>'Asia/Tehran',
+ 'Israel Standard Time'=>'Asia/Jerusalem',
+ 'Jordan Standard Time'=>'Asia/Amman',
+ 'Kamchatka Standard Time'=>'Asia/Kamchatka',
+ 'Korea Standard Time'=>'Asia/Seoul',
+ 'Magadan Standard Time'=>'Asia/Magadan',
+ 'Mauritius Standard Time'=>'Indian/Mauritius',
+ 'Mexico Standard Time'=>'America/Mexico_City',
+ 'Mexico Standard Time 2'=>'America/Chihuahua',
+ 'Mid-Atlantic Standard Time'=>'Etc/GMT-2',
+ 'Middle East Standard Time'=>'Asia/Beirut',
+ 'Montevideo Standard Time'=>'America/Montevideo',
+ 'Morocco Standard Time'=>'Africa/Casablanca',
+ 'Mountain Standard Time'=>'America/Denver',
+ 'Mountain Standard Time (Mexico)'=>'America/Chihuahua',
+ 'Myanmar Standard Time'=>'Asia/Rangoon',
+ 'N. Central Asia Standard Time'=>'Asia/Novosibirsk',
+ 'Namibia Standard Time'=>'Africa/Windhoek',
+ 'Nepal Standard Time'=>'Asia/Katmandu',
+ 'New Zealand Standard Time'=>'Pacific/Auckland',
+ 'Newfoundland Standard Time'=>'America/St_Johns',
+ 'North Asia East Standard Time'=>'Asia/Irkutsk',
+ 'North Asia Standard Time'=>'Asia/Krasnoyarsk',
+ 'Pacific SA Standard Time'=>'America/Santiago',
+ 'Pacific Standard Time'=>'America/Los_Angeles',
+ 'Pacific Standard Time (Mexico)'=>'America/Santa_Isabel',
+ 'Pakistan Standard Time'=>'Asia/Karachi',
+ 'Paraguay Standard Time'=>'America/Asuncion',
+ 'Romance Standard Time'=>'Europe/Paris',
+ 'Russian Standard Time'=>'Europe/Moscow',
+ 'SA Eastern Standard Time'=>'America/Cayenne',
+ 'SA Pacific Standard Time'=>'America/Bogota',
+ 'SA Western Standard Time'=>'America/La_Paz',
+ 'SE Asia Standard Time'=>'Asia/Bangkok',
+ 'Samoa Standard Time'=>'Pacific/Apia',
+ 'Singapore Standard Time'=>'Asia/Singapore',
+ 'South Africa Standard Time'=>'Africa/Johannesburg',
+ 'Sri Lanka Standard Time'=>'Asia/Colombo',
+ 'Syria Standard Time'=>'Asia/Damascus',
+ 'Taipei Standard Time'=>'Asia/Taipei',
+ 'Tasmania Standard Time'=>'Australia/Hobart',
+ 'Tokyo Standard Time'=>'Asia/Tokyo',
+ 'Tonga Standard Time'=>'Pacific/Tongatapu',
+ 'US Eastern Standard Time'=>'America/Indianapolis',
+ 'US Mountain Standard Time'=>'America/Phoenix',
+ 'UTC+12'=>'Etc/GMT-12',
+ 'UTC-02'=>'Etc/GMT+2',
+ 'UTC-11'=>'Etc/GMT+11',
+ 'Ulaanbaatar Standard Time'=>'Asia/Ulaanbaatar',
+ 'Venezuela Standard Time'=>'America/Caracas',
+ 'Vladivostok Standard Time'=>'Asia/Vladivostok',
+ 'W. Australia Standard Time'=>'Australia/Perth',
+ 'W. Central Africa Standard Time'=>'Africa/Lagos',
+ 'W. Europe Standard Time'=>'Europe/Berlin',
+ 'West Asia Standard Time'=>'Asia/Tashkent',
+ 'West Pacific Standard Time'=>'Pacific/Port_Moresby',
+ 'Yakutsk Standard Time'=>'Asia/Yakutsk',
+
+ // Microsoft exchange timezones
+ // Source:
+ // http://msdn.microsoft.com/en-us/library/ms988620%28v=exchg.65%29.aspx
+ //
+ // Correct timezones deduced with help from:
+ // http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
+ 'Universal Coordinated Time' => 'UTC',
+ 'Casablanca, Monrovia' => 'Africa/Casablanca',
+ 'Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London' => 'Europe/Lisbon',
+ 'Greenwich Mean Time; Dublin, Edinburgh, London' => 'Europe/London',
+ 'Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna' => 'Europe/Berlin',
+ 'Belgrade, Pozsony, Budapest, Ljubljana, Prague' => 'Europe/Prague',
+ 'Brussels, Copenhagen, Madrid, Paris' => 'Europe/Paris',
+ 'Paris, Madrid, Brussels, Copenhagen' => 'Europe/Paris',
+ 'Prague, Central Europe' => 'Europe/Prague',
+ 'Sarajevo, Skopje, Sofija, Vilnius, Warsaw, Zagreb' => 'Europe/Sarajevo',
+ 'West Central Africa' => 'Africa/Luanda', // This was a best guess
+ 'Athens, Istanbul, Minsk' => 'Europe/Athens',
+ 'Bucharest' => 'Europe/Bucharest',
+ 'Cairo' => 'Africa/Cairo',
+ 'Harare, Pretoria' => 'Africa/Harare',
+ 'Helsinki, Riga, Tallinn' => 'Europe/Helsinki',
+ 'Israel, Jerusalem Standard Time' => 'Asia/Jerusalem',
+ 'Baghdad' => 'Asia/Baghdad',
+ 'Arab, Kuwait, Riyadh' => 'Asia/Kuwait',
+ 'Moscow, St. Petersburg, Volgograd' => 'Europe/Moscow',
+ 'East Africa, Nairobi' => 'Africa/Nairobi',
+ 'Tehran' => 'Asia/Tehran',
+ 'Abu Dhabi, Muscat' => 'Asia/Muscat', // Best guess
+ 'Baku, Tbilisi, Yerevan' => 'Asia/Baku',
+ 'Kabul' => 'Asia/Kabul',
+ 'Ekaterinburg' => 'Asia/Yekaterinburg',
+ 'Islamabad, Karachi, Tashkent' => 'Asia/Karachi',
+ 'Kolkata, Chennai, Mumbai, New Delhi, India Standard Time' => 'Asia/Calcutta',
+ 'Kathmandu, Nepal' => 'Asia/Kathmandu',
+ 'Almaty, Novosibirsk, North Central Asia' => 'Asia/Almaty',
+ 'Astana, Dhaka' => 'Asia/Dhaka',
+ 'Sri Jayawardenepura, Sri Lanka' => 'Asia/Colombo',
+ 'Rangoon' => 'Asia/Rangoon',
+ 'Bangkok, Hanoi, Jakarta' => 'Asia/Bangkok',
+ 'Krasnoyarsk' => 'Asia/Krasnoyarsk',
+ 'Beijing, Chongqing, Hong Kong SAR, Urumqi' => 'Asia/Shanghai',
+ 'Irkutsk, Ulaan Bataar' => 'Asia/Irkutsk',
+ 'Kuala Lumpur, Singapore' => 'Asia/Singapore',
+ 'Perth, Western Australia' => 'Australia/Perth',
+ 'Taipei' => 'Asia/Taipei',
+ 'Osaka, Sapporo, Tokyo' => 'Asia/Tokyo',
+ 'Seoul, Korea Standard time' => 'Asia/Seoul',
+ 'Yakutsk' => 'Asia/Yakutsk',
+ 'Adelaide, Central Australia' => 'Australia/Adelaide',
+ 'Darwin' => 'Australia/Darwin',
+ 'Brisbane, East Australia' => 'Australia/Brisbane',
+ 'Canberra, Melbourne, Sydney, Hobart (year 2000 only)' => 'Australia/Sydney',
+ 'Guam, Port Moresby' => 'Pacific/Guam',
+ 'Hobart, Tasmania' => 'Australia/Hobart',
+ 'Vladivostok' => 'Asia/Vladivostok',
+ 'Magadan, Solomon Is., New Caledonia' => 'Asia/Magadan',
+ 'Auckland, Wellington' => 'Pacific/Auckland',
+ 'Fiji Islands, Kamchatka, Marshall Is.' => 'Pacific/Fiji',
+ 'Nuku\'alofa, Tonga' => 'Pacific/Tongatapu',
+ 'Azores' => 'Atlantic/Azores',
+ 'Cape Verde Is.' => 'Atlantic/Cape_Verde',
+ 'Mid-Atlantic' => 'America/Noronha',
+ 'Brasilia' => 'America/Sao_Paulo', // Best guess
+ 'Buenos Aires' => 'America/Argentina/Buenos_Aires',
+ 'Greenland' => 'America/Godthab',
+ 'Newfoundland' => 'America/St_Johns',
+ 'Atlantic Time (Canada)' => 'America/Halifax',
+ 'Caracas, La Paz' => 'America/Caracas',
+ 'Santiago' => 'America/Santiago',
+ 'Bogota, Lima, Quito' => 'America/Bogota',
+ 'Eastern Time (US & Canada)' => 'America/New_York',
+ 'Indiana (East)' => 'America/Indiana/Indianapolis',
+ 'Central America' => 'America/Guatemala',
+ 'Central Time (US & Canada)' => 'America/Chicago',
+ 'Mexico City, Tegucigalpa' => 'America/Mexico_City',
+ 'Saskatchewan' => 'America/Edmonton',
+ 'Arizona' => 'America/Phoenix',
+ 'Mountain Time (US & Canada)' => 'America/Denver', // Best guess
+ 'Pacific Time (US & Canada); Tijuana' => 'America/Los_Angeles', // Best guess
+ 'Alaska' => 'America/Anchorage',
+ 'Hawaii' => 'Pacific/Honolulu',
+ 'Midway Island, Samoa' => 'Pacific/Midway',
+ 'Eniwetok, Kwajalein, Dateline Time' => 'Pacific/Kwajalein',
+
+ // The following list are timezone names that could be generated by
+ // Lotus / Domino
+ 'Dateline' => 'Etc/GMT-12',
+ 'Samoa' => 'Pacific/Apia',
+ 'Hawaiian' => 'Pacific/Honolulu',
+ 'Alaskan' => 'America/Anchorage',
+ 'Pacific' => 'America/Los_Angeles',
+ 'Pacific Standard Time' => 'America/Los_Angeles',
+ 'Mexico Standard Time 2' => 'America/Chihuahua',
+ 'Mountain' => 'America/Denver',
+ 'Mountain Standard Time' => 'America/Chihuahua',
+ 'US Mountain' => 'America/Phoenix',
+ 'Canada Central' => 'America/Edmonton',
+ 'Central America' => 'America/Guatemala',
+ 'Central' => 'America/Chicago',
+ 'Central Standard Time' => 'America/Mexico_City',
+ 'Mexico' => 'America/Mexico_City',
+ 'Eastern' => 'America/New_York',
+ 'SA Pacific' => 'America/Bogota',
+ 'US Eastern' => 'America/Indiana/Indianapolis',
+ 'Venezuela' => 'America/Caracas',
+ 'Atlantic' => 'America/Halifax',
+ 'Central Brazilian' => 'America/Manaus',
+ 'Pacific SA' => 'America/Santiago',
+ 'SA Western' => 'America/La_Paz',
+ 'Newfoundland' => 'America/St_Johns',
+ 'Argentina' => 'America/Argentina/Buenos_Aires',
+ 'E. South America' => 'America/Belem',
+ 'Greenland' => 'America/Godthab',
+ 'Montevideo' => 'America/Montevideo',
+ 'SA Eastern' => 'America/Belem',
+ 'Mid-Atlantic' => 'Etc/GMT-2',
+ 'Azores' => 'Atlantic/Azores',
+ 'Cape Verde' => 'Atlantic/Cape_Verde',
+ 'Greenwich' => 'Atlantic/Reykjavik', // No I'm serious.. Greenwich is not GMT.
+ 'Morocco' => 'Africa/Casablanca',
+ 'Central Europe' => 'Europe/Prague',
+ 'Central European' => 'Europe/Sarajevo',
+ 'Romance' => 'Europe/Paris',
+ 'W. Central Africa' => 'Africa/Lagos', // Best guess
+ 'W. Europe' => 'Europe/Amsterdam',
+ 'E. Europe' => 'Europe/Minsk',
+ 'Egypt' => 'Africa/Cairo',
+ 'FLE' => 'Europe/Helsinki',
+ 'GTB' => 'Europe/Athens',
+ 'Israel' => 'Asia/Jerusalem',
+ 'Jordan' => 'Asia/Amman',
+ 'Middle East' => 'Asia/Beirut',
+ 'Namibia' => 'Africa/Windhoek',
+ 'South Africa' => 'Africa/Harare',
+ 'Arab' => 'Asia/Kuwait',
+ 'Arabic' => 'Asia/Baghdad',
+ 'E. Africa' => 'Africa/Nairobi',
+ 'Georgian' => 'Asia/Tbilisi',
+ 'Russian' => 'Europe/Moscow',
+ 'Iran' => 'Asia/Tehran',
+ 'Arabian' => 'Asia/Muscat',
+ 'Armenian' => 'Asia/Yerevan',
+ 'Azerbijan' => 'Asia/Baku',
+ 'Caucasus' => 'Asia/Yerevan',
+ 'Mauritius' => 'Indian/Mauritius',
+ 'Afghanistan' => 'Asia/Kabul',
+ 'Ekaterinburg' => 'Asia/Yekaterinburg',
+ 'Pakistan' => 'Asia/Karachi',
+ 'West Asia' => 'Asia/Tashkent',
+ 'India' => 'Asia/Calcutta',
+ 'Sri Lanka' => 'Asia/Colombo',
+ 'Nepal' => 'Asia/Kathmandu',
+ 'Central Asia' => 'Asia/Dhaka',
+ 'N. Central Asia' => 'Asia/Almaty',
+ 'Myanmar' => 'Asia/Rangoon',
+ 'North Asia' => 'Asia/Krasnoyarsk',
+ 'SE Asia' => 'Asia/Bangkok',
+ 'China' => 'Asia/Shanghai',
+ 'North Asia East' => 'Asia/Irkutsk',
+ 'Singapore' => 'Asia/Singapore',
+ 'Taipei' => 'Asia/Taipei',
+ 'W. Australia' => 'Australia/Perth',
+ 'Korea' => 'Asia/Seoul',
+ 'Tokyo' => 'Asia/Tokyo',
+ 'Yakutsk' => 'Asia/Yakutsk',
+ 'AUS Central' => 'Australia/Darwin',
+ 'Cen. Australia' => 'Australia/Adelaide',
+ 'AUS Eastern' => 'Australia/Sydney',
+ 'E. Australia' => 'Australia/Brisbane',
+ 'Tasmania' => 'Australia/Hobart',
+ 'Vladivostok' => 'Asia/Vladivostok',
+ 'West Pacific' => 'Pacific/Guam',
+ 'Central Pacific' => 'Asia/Magadan',
+ 'Fiji' => 'Pacific/Fiji',
+ 'New Zealand' => 'Pacific/Auckland',
+ 'Tonga' => 'Pacific/Tongatapu',
+ );
+
+ /**
+ * List of microsoft exchange timezone ids.
+ *
+ * Source: http://msdn.microsoft.com/en-us/library/aa563018(loband).aspx
+ */
+ public static $microsoftExchangeMap = array(
+ 0 => 'UTC',
+ 31 => 'Africa/Casablanca',
+
+ // Insanely, id #2 is used for both Europe/Lisbon, and Europe/Sarajevo.
+ // I'm not even kidding.. We handle this special case in the
+ // getTimeZone method.
+ 2 => 'Europe/Lisbon',
+ 1 => 'Europe/London',
+ 4 => 'Europe/Berlin',
+ 6 => 'Europe/Prague',
+ 3 => 'Europe/Paris',
+ 69 => 'Africa/Luanda', // This was a best guess
+ 7 => 'Europe/Athens',
+ 5 => 'Europe/Bucharest',
+ 49 => 'Africa/Cairo',
+ 50 => 'Africa/Harare',
+ 59 => 'Europe/Helsinki',
+ 27 => 'Asia/Jerusalem',
+ 26 => 'Asia/Baghdad',
+ 74 => 'Asia/Kuwait',
+ 51 => 'Europe/Moscow',
+ 56 => 'Africa/Nairobi',
+ 25 => 'Asia/Tehran',
+ 24 => 'Asia/Muscat', // Best guess
+ 54 => 'Asia/Baku',
+ 48 => 'Asia/Kabul',
+ 58 => 'Asia/Yekaterinburg',
+ 47 => 'Asia/Karachi',
+ 23 => 'Asia/Calcutta',
+ 62 => 'Asia/Kathmandu',
+ 46 => 'Asia/Almaty',
+ 71 => 'Asia/Dhaka',
+ 66 => 'Asia/Colombo',
+ 61 => 'Asia/Rangoon',
+ 22 => 'Asia/Bangkok',
+ 64 => 'Asia/Krasnoyarsk',
+ 45 => 'Asia/Shanghai',
+ 63 => 'Asia/Irkutsk',
+ 21 => 'Asia/Singapore',
+ 73 => 'Australia/Perth',
+ 75 => 'Asia/Taipei',
+ 20 => 'Asia/Tokyo',
+ 72 => 'Asia/Seoul',
+ 70 => 'Asia/Yakutsk',
+ 19 => 'Australia/Adelaide',
+ 44 => 'Australia/Darwin',
+ 18 => 'Australia/Brisbane',
+ 76 => 'Australia/Sydney',
+ 43 => 'Pacific/Guam',
+ 42 => 'Australia/Hobart',
+ 68 => 'Asia/Vladivostok',
+ 41 => 'Asia/Magadan',
+ 17 => 'Pacific/Auckland',
+ 40 => 'Pacific/Fiji',
+ 67 => 'Pacific/Tongatapu',
+ 29 => 'Atlantic/Azores',
+ 53 => 'Atlantic/Cape_Verde',
+ 30 => 'America/Noronha',
+ 8 => 'America/Sao_Paulo', // Best guess
+ 32 => 'America/Argentina/Buenos_Aires',
+ 60 => 'America/Godthab',
+ 28 => 'America/St_Johns',
+ 9 => 'America/Halifax',
+ 33 => 'America/Caracas',
+ 65 => 'America/Santiago',
+ 35 => 'America/Bogota',
+ 10 => 'America/New_York',
+ 34 => 'America/Indiana/Indianapolis',
+ 55 => 'America/Guatemala',
+ 11 => 'America/Chicago',
+ 37 => 'America/Mexico_City',
+ 36 => 'America/Edmonton',
+ 38 => 'America/Phoenix',
+ 12 => 'America/Denver', // Best guess
+ 13 => 'America/Los_Angeles', // Best guess
+ 14 => 'America/Anchorage',
+ 15 => 'Pacific/Honolulu',
+ 16 => 'Pacific/Midway',
+ 39 => 'Pacific/Kwajalein',
+ );
+
+ /**
+ * This method will try to find out the correct timezone for an iCalendar
+ * date-time value.
+ *
+ * You must pass the contents of the TZID parameter, as well as the full
+ * calendar.
+ *
+ * If the lookup fails, this method will return the default PHP timezone
+ * (as configured using date_default_timezone_set, or the date.timezone ini
+ * setting).
+ *
+ * Alternatively, if $failIfUncertain is set to true, it will throw an
+ * exception if we cannot accurately determine the timezone.
+ *
+ * @param string $tzid
+ * @param SabreForRainLoop\VObject\Component $vcalendar
+ * @return DateTimeZone
+ */
+ static public function getTimeZone($tzid, Component $vcalendar = null, $failIfUncertain = false) {
+
+ // First we will just see if the tzid is a support timezone identifier.
+ try {
+ return new \DateTimeZone($tzid);
+ } catch (\Exception $e) {
+ }
+
+ // Next, we check if the tzid is somewhere in our tzid map.
+ if (isset(self::$map[$tzid])) {
+ return new \DateTimeZone(self::$map[$tzid]);
+ }
+
+ // Maybe the author was hyper-lazy and just included an offset. We
+ // support it, but we aren't happy about it.
+ if (preg_match('/^GMT(\+|-)([0-9]{4})$/', $tzid, $matches)) {
+ return new \DateTimeZone('Etc/GMT' . $matches[1] . ltrim(substr($matches[2],0,2),'0'));
+ }
+
+ if ($vcalendar) {
+
+ // If that didn't work, we will scan VTIMEZONE objects
+ foreach($vcalendar->select('VTIMEZONE') as $vtimezone) {
+
+ if ((string)$vtimezone->TZID === $tzid) {
+
+ // Some clients add 'X-LIC-LOCATION' with the olson name.
+ if (isset($vtimezone->{'X-LIC-LOCATION'})) {
+
+ $lic = (string)$vtimezone->{'X-LIC-LOCATION'};
+
+ // Libical generators may specify strings like
+ // "SystemV/EST5EDT". For those we must remove the
+ // SystemV part.
+ if (substr($lic,0,8)==='SystemV/') {
+ $lic = substr($lic,8);
+ }
+
+ try {
+ return new \DateTimeZone($lic);
+ } catch (\Exception $e) {
+ }
+
+ }
+ // Microsoft may add a magic number, which we also have an
+ // answer for.
+ if (isset($vtimezone->{'X-MICROSOFT-CDO-TZID'})) {
+ $cdoId = (int)$vtimezone->{'X-MICROSOFT-CDO-TZID'}->getValue();
+
+ // 2 can mean both Europe/Lisbon and Europe/Sarajevo.
+ if ($cdoId===2 && strpos((string)$vtimezone->TZID, 'Sarajevo')!==false) {
+ return new \DateTimeZone('Europe/Sarajevo');
+ }
+
+ if (isset(self::$microsoftExchangeMap[$cdoId])) {
+ return new \DateTimeZone(self::$microsoftExchangeMap[$cdoId]);
+ }
+ }
+
+ }
+
+ }
+
+ }
+
+ if ($failIfUncertain) {
+ throw new \InvalidArgumentException('We were unable to determine the correct PHP timezone for tzid: ' . $tzid);
+ }
+
+ // If we got all the way here, we default to UTC.
+ return new \DateTimeZone(date_default_timezone_get());
+
+ }
+
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/VCardConverter.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/VCardConverter.php
new file mode 100644
index 0000000..4b5d6d1
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/VCardConverter.php
@@ -0,0 +1,382 @@
+getDocumentType();
+ if ($inputVersion===$targetVersion) {
+ return clone $input;
+ }
+
+ if (!in_array($inputVersion, array(Document::VCARD21, Document::VCARD30, Document::VCARD40))) {
+ throw new \InvalidArgumentException('Only vCard 2.1, 3.0 and 4.0 are supported for the input data');
+ }
+ if (!in_array($targetVersion, array(Document::VCARD30, Document::VCARD40))) {
+ throw new \InvalidArgumentException('You can only use vCard 3.0 or 4.0 for the target version');
+ }
+
+ $newVersion = $targetVersion===Document::VCARD40?'4.0':'3.0';
+
+ $output = new Component\VCard(array(
+ 'VERSION' => $newVersion,
+ ));
+
+ foreach($input->children as $property) {
+
+ $this->convertProperty($input, $output, $property, $targetVersion);
+
+ }
+
+ return $output;
+
+ }
+
+ /**
+ * Handles conversion of a single property.
+ *
+ * @param Component\VCard $input
+ * @param Component\VCard $output
+ * @param Property $property
+ * @param int $targetVersion
+ * @return void
+ */
+ protected function convertProperty(Component\VCard $input, Component\VCard $output, Property $property, $targetVersion) {
+
+ // Skipping these, those are automatically added.
+ if (in_array($property->name, array('VERSION', 'PRODID'))) {
+ return;
+ }
+
+ $parameters = $property->parameters();
+
+ $valueType = null;
+ if (isset($parameters['VALUE'])) {
+ $valueType = $parameters['VALUE']->getValue();
+ unset($parameters['VALUE']);
+ }
+ if (!$valueType) {
+ $valueType = $property->getValueType();
+ }
+
+ $newProperty = null;
+
+ if ($targetVersion===Document::VCARD30) {
+
+ if ($property instanceof Property\Uri && in_array($property->name, array('PHOTO','LOGO','SOUND'))) {
+
+ $newProperty = $this->convertUriToBinary($output, $property, $parameters);
+
+ } elseif ($property->name === 'KIND') {
+
+ switch(strtolower($property->getValue())) {
+ case 'org' :
+ // OS X addressbook property.
+ $newProperty = $output->createProperty('X-ABSHOWAS','COMPANY');
+ break;
+ case 'individual' :
+ // Individual is implied, so we can just skip it.
+ return;
+
+ case 'group' :
+ // OS X addressbook property
+ $newProperty = $output->createProperty('X-ADDRESSBOOKSERVER-KIND','GROUP');
+ break;
+ }
+
+
+ }
+
+ } elseif ($targetVersion===Document::VCARD40) {
+
+ // These properties were removed in vCard 4.0
+ if (in_array($property->name, array('NAME', 'MAILER', 'LABEL', 'CLASS'))) {
+ return;
+ }
+
+ if ($property instanceOf Property\Binary) {
+
+ $newProperty = $this->convertBinaryToUri($output, $property, $parameters);
+
+ } else {
+ switch($property->name) {
+ case 'X-ABSHOWAS' :
+ if (strtoupper($property->getValue()) === 'COMPANY') {
+ $newProperty = $output->createProperty('KIND','org');
+ }
+ break;
+ case 'X-ADDRESSBOOKSERVER-KIND' :
+ if (strtoupper($property->getValue()) === 'GROUP') {
+ $newProperty = $output->createProperty('KIND','group');
+ }
+ break;
+ }
+
+ }
+
+ }
+
+
+ if (is_null($newProperty)) {
+
+ $newProperty = $output->createProperty(
+ $property->name,
+ $property->getParts(),
+ array(), // no parameters yet
+ $valueType
+ );
+
+ }
+
+ // set property group
+ $newProperty->group = $property->group;
+
+ if ($targetVersion===Document::VCARD40) {
+ $this->convertParameters40($newProperty, $parameters);
+ } else {
+ $this->convertParameters30($newProperty, $parameters);
+ }
+
+ // Lastly, we need to see if there's a need for a VALUE parameter.
+ //
+ // We can do that by instantating a empty property with that name, and
+ // seeing if the default valueType is identical to the current one.
+ $tempProperty = $output->createProperty($newProperty->name);
+ if ($tempProperty->getValueType() !== $newProperty->getValueType()) {
+ $newProperty['VALUE'] = $newProperty->getValueType();
+ }
+
+ $output->add($newProperty);
+
+
+ }
+
+ /**
+ * Converts a BINARY property to a URI property.
+ *
+ * vCard 4.0 no longer supports BINARY properties.
+ *
+ * @param Component\VCard $output
+ * @param Property\Uri $property The input property.
+ * @param $parameters List of parameters that will eventually be added to
+ * the new property.
+ * @return Property\Uri
+ */
+ protected function convertBinaryToUri(Component\VCard $output, Property\Binary $property, array &$parameters) {
+
+ $newProperty = $output->createProperty(
+ $property->name,
+ null, // no value
+ array(), // no parameters yet
+ 'URI' // Forcing the BINARY type
+ );
+
+ $mimeType = 'application/octet-stream';
+
+ // See if we can find a better mimetype.
+ if (isset($parameters['TYPE'])) {
+
+ $newTypes = array();
+ foreach($parameters['TYPE']->getParts() as $typePart) {
+ if (in_array(
+ strtoupper($typePart),
+ array('JPEG','PNG','GIF')
+ )) {
+ $mimeType = 'image/' . strtolower($typePart);
+ } else {
+ $newTypes[] = $typePart;
+ }
+ }
+
+ // If there were any parameters we're not converting to a
+ // mime-type, we need to keep them.
+ if ($newTypes) {
+ $parameters['TYPE']->setParts($newTypes);
+ } else {
+ unset($parameters['TYPE']);
+ }
+
+ }
+
+ $newProperty->setValue('data:' . $mimeType . ';base64,' . base64_encode($property->getValue()));
+
+ return $newProperty;
+
+ }
+
+ /**
+ * Converts a URI property to a BINARY property.
+ *
+ * In vCard 4.0 attachments are encoded as data: uri. Even though these may
+ * be valid in vCard 3.0 as well, we should convert those to BINARY if
+ * possible, to improve compatibility.
+ *
+ * @param Component\VCard $output
+ * @param Property\Uri $property The input property.
+ * @param $parameters List of parameters that will eventually be added to
+ * the new property.
+ * @return Property\Binary|null
+ */
+ protected function convertUriToBinary(Component\VCard $output, Property\Uri $property, array &$parameters) {
+
+ $value = $property->getValue();
+
+ // Only converting data: uris
+ if (substr($value, 0, 5)!=='data:') {
+ return;
+ }
+
+ $newProperty = $output->createProperty(
+ $property->name,
+ null, // no value
+ array(), // no parameters yet
+ 'BINARY'
+ );
+
+ $mimeType = substr($value, 5, strpos($value, ',')-5);
+ if (strpos($mimeType, ';')) {
+ $mimeType = substr($mimeType,0,strpos($mimeType, ';'));
+ $newProperty->setValue(base64_decode(substr($value, strpos($value,',')+1)));
+ } else {
+ $newProperty->setValue(substr($value, strpos($value,',')+1));
+ }
+ unset($value);
+
+ $newProperty['ENCODING'] = 'b';
+ switch($mimeType) {
+
+ case 'image/jpeg' :
+ $newProperty['TYPE'] = 'JPEG';
+ break;
+ case 'image/png' :
+ $newProperty['TYPE'] = 'PNG';
+ break;
+ case 'image/gif' :
+ $newProperty['TYPE'] = 'GIF';
+ break;
+
+ }
+
+
+ return $newProperty;
+
+ }
+
+ /**
+ * Adds parameters to a new property for vCard 4.0
+ *
+ * @param Property $newProperty
+ * @param array $parameters
+ * @return void
+ */
+ protected function convertParameters40(Property $newProperty, array $parameters) {
+
+ // Adding all parameters.
+ foreach($parameters as $param) {
+
+ // vCard 2.1 allowed parameters with no name
+ if ($param->noName) $param->noName = false;
+
+ switch($param->name) {
+
+ // We need to see if there's any TYPE=PREF, because in vCard 4
+ // that's now PREF=1.
+ case 'TYPE' :
+ foreach($param->getParts() as $paramPart) {
+
+ if (strtoupper($paramPart)==='PREF') {
+ $newProperty->add('PREF','1');
+ } else {
+ $newProperty->add($param->name, $paramPart);
+ }
+
+ }
+ break;
+ // These no longer exist in vCard 4
+ case 'ENCODING' :
+ case 'CHARSET' :
+ break;
+
+ default :
+ $newProperty->add($param->name, $param->getParts());
+ break;
+
+ }
+
+ }
+
+ }
+
+ /**
+ * Adds parameters to a new property for vCard 3.0
+ *
+ * @param Property $newProperty
+ * @param array $parameters
+ * @return void
+ */
+ protected function convertParameters30(Property $newProperty, array $parameters) {
+
+ // Adding all parameters.
+ foreach($parameters as $param) {
+
+ // vCard 2.1 allowed parameters with no name
+ if ($param->noName) $param->noName = false;
+
+ switch($param->name) {
+
+ case 'ENCODING' :
+ // This value only existed in vCard 2.1, and should be
+ // removed for anything else.
+ if (strtoupper($param->getValue())!=='QUOTED-PRINTABLE') {
+ $newProperty->add($param->name, $param->getParts());
+ }
+ break;
+
+ /*
+ * Converting PREF=1 to TYPE=PREF.
+ *
+ * Any other PREF numbers we'll drop.
+ */
+ case 'PREF' :
+ if ($param->getValue()=='1') {
+ $newProperty->add('TYPE','PREF');
+ }
+ break;
+
+ default :
+ $newProperty->add($param->name, $param->getParts());
+ break;
+
+ }
+
+ }
+
+ }
+}
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Version.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Version.php
new file mode 100644
index 0000000..7628363
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/SabreForRainLoop/VObject/Version.php
@@ -0,0 +1,19 @@
+ blocks within the HTML due to popular demand.
+Added several new pseudo-selectors (first-child, last-child, nth-child, and nth-of-type).
+
+2011-12-22
+Fixed a bug that was overwriting existing inline styles from the original HTML... Thanks Sagi L.!
+
+2011-10-26
+Added an option to allow you to output emogrified code without extended characters being turned into HTML entities.
+Moved static references to class attributes so they can be manipulated.
+Added the ability to clear out the (formerly) static cache when CSS is reloaded.
+
+2011-10-13
+Fully fixed a bug introduced in 2011-06-08 where selectors at the beginning of the CSS would be parsed incorrectly... Thanks Thomas A.!
+
+2011-08-03
+Fixed an error where an empty selector at the beginning of the CSS would cause a parse error on the next selector... Thanks Alexei T.!
+
+2011-06-08
+Fixed an error where CSS @media types weren't being parsed correctly... Thanks Will W.!
+
+2011-04-08
+Fixed errors in CSS->XPath conversion for adjacent sibling selectors and id/class combinations... Thanks Bob V.!
+
+2010-09-03
+Added checks to invisible node removal to ensure that we don't try to remove non-existent child nodes of parents that have already been deleted
+
+2010-07-26
+Fixed bug where '0' values were getting discarded because of php's empty() function... Thanks Scott!
+
+2010-06-16
+Added static caching for less processing overhead in situations where multiple emogrification takes place
+
+2010-05-18
+Fixed bug where full url filenames with protocols wouldn't get split improperly when we explode on ':'... Thanks Mark!
+Added two new attribute selectors
+
+2009-11-04
+Explicitly declared static functions static to get rid of E_STRICT notices.
+
+2009-10-29
+Fixed so that selectors appearing later in the CSS will have precedence over identical selectors appearing earlier.
+
+2009-08-17
+Fixed CSS selector processing so that selectors are processed by precedence/specificity, and not just in order.
+
+2009-08-13
+Added support for subset class values (e.g. "p.class1.class2"). Added better protection for bad css attributes.
+Fixed support for HTML entities.
+
+2009-06-03
+Normalize existing CSS (style) attributes in the HTML before we process the CSS.
+Made it so that the display:none stripper doesn't require a trailing semi-colon.
+
+2008-03-02
+Added licensing terms under the MIT License; Only remove unprocessable HTML tags if they exist in the array
+
+2008-10-20
+Fixed bug with bad variable name... Thanks Thomas!
+
+2008-08-18
+Added lines instructing DOMDocument to attempt to normalize HTML before processing
+
+2008-08-10
+Fixed CSS comment stripping regex to add PCRE_DOTALL (changed from '/\/\*.*\*\//U' to '/\/\*.*\*\//sU')
diff --git a/rainloop/rainloop/v/1.10.0.103/app/libraries/emogrifier/Emogrifier.php b/rainloop/rainloop/v/1.10.0.103/app/libraries/emogrifier/Emogrifier.php
new file mode 100644
index 0000000..57774bf
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/libraries/emogrifier/Emogrifier.php
@@ -0,0 +1,981 @@
+
+ */
+class Emogrifier
+{
+ /**
+ * @var string
+ */
+ const ENCODING = 'UTF-8';
+
+ /**
+ * @var int
+ */
+ const CACHE_KEY_CSS = 0;
+
+ /**
+ * @var int
+ */
+ const CACHE_KEY_SELECTOR = 1;
+
+ /**
+ * @var int
+ */
+ const CACHE_KEY_XPATH = 2;
+
+ /**
+ * @var int
+ */
+ const CACHE_KEY_CSS_DECLARATION_BLOCK = 3;
+
+ /**
+ * for calculating nth-of-type and nth-child selectors
+ *
+ * @var int
+ */
+ const INDEX = 0;
+
+ /**
+ * for calculating nth-of-type and nth-child selectors
+ *
+ * @var int
+ */
+ const MULTIPLIER = 1;
+
+ /**
+ * @var string
+ */
+ const ID_ATTRIBUTE_MATCHER = '/(\\w+)?\\#([\\w\\-]+)/';
+
+ /**
+ * @var string
+ */
+ const CLASS_ATTRIBUTE_MATCHER = '/(\\w+|[\\*\\]])?((\\.[\\w\\-]+)+)/';
+
+ /**
+ * @var string
+ */
+ private $html = '';
+
+ /**
+ * @var string
+ */
+ private $css = '';
+
+ /**
+ * @var string[]
+ */
+ private $unprocessableHtmlTags = array('wbr');
+
+ /**
+ * @var array[]
+ */
+ private $caches = array(
+ self::CACHE_KEY_CSS => array(),
+ self::CACHE_KEY_SELECTOR => array(),
+ self::CACHE_KEY_XPATH => array(),
+ self::CACHE_KEY_CSS_DECLARATION_BLOCK => array(),
+ );
+
+ /**
+ * the visited nodes with the XPath paths as array keys
+ *
+ * @var \DOMNode[]
+ */
+ private $visitedNodes = array();
+
+ /**
+ * the styles to apply to the nodes with the XPath paths as array keys for the outer array
+ * and the attribute names/values as key/value pairs for the inner array
+ *
+ * @var array[]
+ */
+ private $styleAttributesForNodes = array();
+
+ /**
+ * Determines whether the "style" attributes of tags in the the HTML passed to this class should be preserved.
+ * If set to false, the value of the style attributes will be discarded.
+ *
+ * @var bool
+ */
+ private $isInlineStyleAttributesParsingEnabled = true;
+
+ /**
+ * Determines whether the
+
+
+
+
+
+
+ {{ErrorDesc}}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Error.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Error.html
new file mode 100644
index 0000000..50d5719
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Error.html
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+ {{ErrorTitle}}
+
+
+
+
+
+
+
+ {{ErrorDesc}}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Index.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Index.html
new file mode 100644
index 0000000..c6221c6
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Index.html
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{BaseAppFaviconPngLinkTag}}{{BaseAppFaviconTouchLinkTag}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ An Error occurred,
+
+ please refresh the page and try again.
+
+
+
+
+
+
+
+
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Themes/template.less b/rainloop/rainloop/v/1.10.0.103/app/templates/Themes/template.less
new file mode 100644
index 0000000..2961b3b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Themes/template.less
@@ -0,0 +1,212 @@
+
+// mixins +++
+.thm-linear-gradient-mixin(@start, @end) when (iscolor(@start)) and (iscolor(@end)) {
+ background-color: mix(@start, @end, 60%) !important;
+ background-image: -moz-linear-gradient(top, @start, @end) !important; // FF 3.6+
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@start), to(@end)) !important; // Safari 4+, Chrome 2+
+ background-image: -webkit-linear-gradient(top, @start, @end) !important; // Safari 5.1+, Chrome 10+
+ background-image: -o-linear-gradient(top, @start, @end !important); // Opera 11.10
+ background-image: linear-gradient(to bottom, @start, @end) !important; // Standard, IE10
+ background-repeat: repeat-x !important;
+ filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@start),argb(@end))) !important; // IE9 and down
+}
+
+.thm-border-radius(@radius) when (ispixel(@radius)) {
+ -webkit-border-radius: @radius !important;
+ -moz-border-radius: @radius !important;
+ border-radius: @radius !important;
+}
+
+.thm-box-shadow(@shadow) {
+ -webkit-box-shadow: @shadow !important;
+ -moz-box-shadow: @shadow !important;
+ box-shadow: @shadow !important;
+}
+.thm-body-background-image(@value) when (isstring(@value)) {
+ background-image: url("@{base}@{value}") !important;
+}
+.thm-body-background-image(@value) when not (isstring(@value)) {
+ background-image: @value !important;
+}
+.thm-rgba-background-color(@simple, @rgba) when (@rgba = false) {
+ background-color: @simple !important;
+}
+.thm-rgba-background-color(@simple, @rgba) when not (@rgba = false) {
+ background-color: @simple !important;
+ background-color: @rgba !important;
+}
+// --- mixins
+
+.thm-body {
+ color: @main-color;
+ background-color: @main-background-color;
+ background-size: @main-background-size;
+ .thm-body-background-image(@main-background-image);
+}
+
+.thm-loading {
+ color: @loading-color !important;
+ text-shadow: @loading-text-shadow !important;
+
+ .e-spinner .e-bounce {
+ background-color: @loading-color !important;
+ }
+}
+
+.thm-login-desc .desc {
+ color: @loading-color !important;
+ text-shadow: @loading-text-shadow !important;
+}
+
+.thm-login {
+ border: @login-border !important;
+ .thm-rgba-background-color(@login-background-color, @login-rgba-background-color);
+ .thm-linear-gradient-mixin(@login-gradient-start, @login-gradient-end);
+ .thm-border-radius(@login-border-radius);
+ .thm-box-shadow(@login-box-shadow);
+}
+
+.thm-login-text {
+ color: @login-color !important;
+
+ .legend, .e-checkbox-icon, .g-ui-link, .social-button, .language-button {
+ color: @login-color !important;
+ }
+}
+
+.thm-powered, .thm-mobile-switcher {
+ color: @powered-color;
+ a {
+ color: @powered-color;
+ &:hover {
+ color: lighten(@powered-color, 20%);
+ }
+ }
+}
+
+.thm-languages {
+ color: @languages-color;
+ .flag-name {
+ color: @languages-color;
+ border-color: @languages-color;
+ }
+}
+
+.g-ui-menu {
+ color: @dropdown-menu-color !important;
+ background-color: @dropdown-menu-background-color !important;
+}
+
+.g-ui-menu .e-item > .e-link {
+ color: @dropdown-menu-color !important;
+ background-color: @dropdown-menu-background-color !important;
+
+ > i {
+ color: @dropdown-menu-color !important;
+ }
+}
+
+.g-ui-menu .e-item.selected > .e-link {
+ background-color: @dropdown-menu-selected-background-color !important;
+}
+
+.g-ui-menu .e-item > .e-link:hover, .g-ui-menu .e-item > .e-link:focus {
+ color: @dropdown-menu-hover-color !important;
+ background-color: @dropdown-menu-hover-background-color !important;
+
+ > i {
+ color: @dropdown-menu-hover-color !important;
+ }
+}
+
+.g-ui-menu .e-item.disabled > .e-link, .g-ui-menu .e-item.disabled > .e-link:hover {
+ color: @dropdown-menu-disabled-color !important;
+ background-color: @dropdown-menu-background-color !important;
+
+ > i {
+ color: @dropdown-menu-disabled-color !important;
+ }
+}
+
+.thm-message-list-top-toolbar, .thm-message-list-bottom-toolbar {
+ .thm-rgba-background-color(@message-list-toolbar-background-color, @message-list-toolbar-rgba-background-color);
+ .thm-linear-gradient-mixin(@message-list-toolbar-gradient-start, @message-list-toolbar-gradient-end);
+}
+
+.thm-folders .e-link {
+
+ color: @folders-disabled-color !important;
+
+ &.selectable {
+ color: @folders-color !important;
+ }
+
+ &.selectable:hover {
+ color: @folders-hover-color !important;
+ .thm-rgba-background-color(@folders-hover-background-color, @folders-hover-rgba-background-color);
+ }
+
+ &.selectable.selected {
+ color: @folders-selected-color !important;
+ .thm-rgba-background-color(@folders-selected-background-color, @folders-selected-rgba-background-color);
+ }
+
+ &.focused {
+ color: @folders-focused-color !important;
+ .thm-rgba-background-color(@folders-focused-background-color, @folders-focused-rgba-background-color);
+ }
+
+ &.selectable.droppableHover {
+ color: @folders-drop-color !important;
+ .thm-rgba-background-color(@folders-drop-background-color, @folders-drop-rgba-background-color);
+ }
+}
+
+.thm-settings-menu .e-item {
+
+ .e-link {
+ color: @settings-menu-disabled-color !important;
+ }
+
+ &.selectable .e-link {
+ color: @settings-menu-color !important;
+ }
+
+ &.selectable:hover .e-link {
+ .thm-rgba-background-color(@settings-menu-hover-background-color, @settings-menu-hover-rgba-background-color);
+ color: @settings-menu-hover-color !important;
+ }
+
+ &.selectable.selected .e-link {
+ .thm-rgba-background-color(@settings-menu-selected-background-color, @settings-menu-selected-rgba-background-color);
+ color: @settings-menu-selected-color !important;
+ }
+}
+
+.thm-message-view-background-color {
+ .thm-rgba-background-color(@message-background-color, @message-rgba-background-color);
+}
+
+
+html.no-css {
+
+ .thm-body {
+ color: #333;
+ background-color: #aaa;
+ background-image: none;
+ }
+
+ .thm-loading {
+ color: #333 !important;
+ text-shadow: none !important;
+
+ .e-spinner .e-bounce {
+ display: none !important;
+ }
+ }
+
+ .thm-login-desc .desc {
+ color: #333 !important;
+ text-shadow: none !important;
+ }
+}
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Themes/values.less b/rainloop/rainloop/v/1.10.0.103/app/templates/Themes/values.less
new file mode 100644
index 0000000..27b38d7
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Themes/values.less
@@ -0,0 +1,66 @@
+
+// MAIN
+@main-color: #333;
+@main-background-color: #e3e3e3;
+@main-background-image: none; // "images/background.png"
+@main-background-size: inherit;
+
+// LOADING
+@loading-color: #000; // #ddd
+@loading-text-shadow: none; // 0px 1px 0px rgba(0, 0, 0, 0.5);
+
+// LOGIN
+@login-color: #555;
+@login-background-color: #eee;
+@login-rgba-background-color: false; // rgba(0,0,0,0.7)
+@login-box-shadow: none; // 0px 2px 10px rgba(0,0,0,0.5)
+@login-border: 1px solid #ccc;
+@login-border-radius: 7px;
+@login-gradient-start: none; // #f4f4f4
+@login-gradient-end: none; // #dfdfdf
+@powered-color: #333;
+@languages-color: #333;
+
+// MENU
+@dropdown-menu-color: #333;
+@dropdown-menu-background-color: #fff;
+@dropdown-menu-hover-background-color: #444;
+@dropdown-menu-hover-color: #eee;
+@dropdown-menu-disabled-color: #999;
+@dropdown-menu-selected-background-color: #eee;
+
+// FOLDERS
+@folders-color: #333;
+@folders-disabled-color: #666;
+@folders-selected-color: #eee;
+@folders-selected-background-color: #333;
+@folders-selected-rgba-background-color: false;
+@folders-focused-color: #eee;
+@folders-focused-background-color: #333;
+@folders-focused-rgba-background-color: false;
+@folders-hover-color: #eee;
+@folders-hover-background-color: #333;
+@folders-hover-rgba-background-color: false;
+@folders-drop-color: #eee;
+@folders-drop-background-color: #333;
+@folders-drop-rgba-background-color: false;
+
+// SETTINGS
+@settings-menu-color: #333;
+@settings-menu-disabled-color: #666;
+@settings-menu-selected-color: #eee;
+@settings-menu-selected-background-color: #333;
+@settings-menu-selected-rgba-background-color: false;
+@settings-menu-hover-color: #eee;
+@settings-menu-hover-background-color: #333;
+@settings-menu-hover-rgba-background-color: false;
+
+// MESSAGE LIST
+@message-list-toolbar-background-color: #eee;
+@message-list-toolbar-rgba-background-color: false;
+@message-list-toolbar-gradient-start: none; // #f4f4f4
+@message-list-toolbar-gradient-end: none; // #dfdfdf
+
+// MESSAGE
+@message-background-color: #fff;
+@message-rgba-background-color: false;
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminLogin.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminLogin.html
new file mode 100644
index 0000000..98afbc7
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminLogin.html
@@ -0,0 +1,46 @@
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminMenu.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminMenu.html
new file mode 100644
index 0000000..673634b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminMenu.html
@@ -0,0 +1,24 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminPane.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminPane.html
new file mode 100644
index 0000000..ffdc996
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminPane.html
@@ -0,0 +1,28 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsAbout.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsAbout.html
new file mode 100644
index 0000000..d4586d3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsAbout.html
@@ -0,0 +1,87 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsBranding.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsBranding.html
new file mode 100644
index 0000000..8f6c903
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsBranding.html
@@ -0,0 +1,250 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsContacts.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsContacts.html
new file mode 100644
index 0000000..f97cabd
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsContacts.html
@@ -0,0 +1,115 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsDomainListItem.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsDomainListItem.html
new file mode 100644
index 0000000..85e6163
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsDomainListItem.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsDomains.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsDomains.html
new file mode 100644
index 0000000..4e94b74
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsDomains.html
@@ -0,0 +1,24 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsGeneral.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsGeneral.html
new file mode 100644
index 0000000..a4a9050
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsGeneral.html
@@ -0,0 +1,166 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsLicensing.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsLicensing.html
new file mode 100644
index 0000000..d46aa52
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsLicensing.html
@@ -0,0 +1,87 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsLogin.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsLogin.html
new file mode 100644
index 0000000..918b5e9
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsLogin.html
@@ -0,0 +1,35 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPackages.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPackages.html
new file mode 100644
index 0000000..0c3aec3
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPackages.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+ ×
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPackagesListItem.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPackagesListItem.html
new file mode 100644
index 0000000..bce55dd
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPackagesListItem.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPackagesTable.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPackagesTable.html
new file mode 100644
index 0000000..72d3cee
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPackagesTable.html
@@ -0,0 +1,9 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPluginListItem.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPluginListItem.html
new file mode 100644
index 0000000..a83b1a4
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPluginListItem.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPluginProperty.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPluginProperty.html
new file mode 100644
index 0000000..f245ecf
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPluginProperty.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPlugins.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPlugins.html
new file mode 100644
index 0000000..08a895b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsPlugins.html
@@ -0,0 +1,41 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsSecurity.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsSecurity.html
new file mode 100644
index 0000000..8132e57
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsSecurity.html
@@ -0,0 +1,122 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsSocial.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsSocial.html
new file mode 100644
index 0000000..96bcb65
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/AdminSettingsSocial.html
@@ -0,0 +1,194 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/PopupsActivate.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/PopupsActivate.html
new file mode 100644
index 0000000..a50fe6d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/PopupsActivate.html
@@ -0,0 +1,50 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/PopupsDomain.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/PopupsDomain.html
new file mode 100644
index 0000000..56ed5dd
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/PopupsDomain.html
@@ -0,0 +1,271 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/PopupsPlugin.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/PopupsPlugin.html
new file mode 100644
index 0000000..58c4594
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Admin/PopupsPlugin.html
@@ -0,0 +1,41 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Common/Pagenator.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Common/Pagenator.html
new file mode 100644
index 0000000..7609a97
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Common/Pagenator.html
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Common/PopupsAsk.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Common/PopupsAsk.html
new file mode 100644
index 0000000..4054b3b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Common/PopupsAsk.html
@@ -0,0 +1,26 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html
new file mode 100644
index 0000000..dc3579c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Common/PopupsKeyboardShortcutsHelp.html
@@ -0,0 +1,90 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Common/PopupsLanguages.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Common/PopupsLanguages.html
new file mode 100644
index 0000000..4e365ef
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Common/PopupsLanguages.html
@@ -0,0 +1,23 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Common/PopupsWelcomePage.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Common/PopupsWelcomePage.html
new file mode 100644
index 0000000..a9f2a43
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Common/PopupsWelcomePage.html
@@ -0,0 +1,22 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/Checkbox.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/Checkbox.html
new file mode 100644
index 0000000..d710e0f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/Checkbox.html
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/CheckboxClassic.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/CheckboxClassic.html
new file mode 100644
index 0000000..b275485
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/CheckboxClassic.html
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/CheckboxMaterialDesign.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/CheckboxMaterialDesign.html
new file mode 100644
index 0000000..cbd3dcc
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/CheckboxMaterialDesign.html
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/Input.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/Input.html
new file mode 100644
index 0000000..12215d1
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/Input.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/Radio.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/Radio.html
new file mode 100644
index 0000000..4a1e0d0
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/Radio.html
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/SaveTrigger.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/SaveTrigger.html
new file mode 100644
index 0000000..44c2f1c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/SaveTrigger.html
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/Select.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/Select.html
new file mode 100644
index 0000000..5d65327
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/Select.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/TextArea.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/TextArea.html
new file mode 100644
index 0000000..3565e30
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/Components/TextArea.html
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/About.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/About.html
new file mode 100644
index 0000000..9c3cbce
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/About.html
@@ -0,0 +1,6 @@
+
+
RainLoop Webmail
+
+
( )
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/ComposeAttachment.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/ComposeAttachment.html
new file mode 100644
index 0000000..15ac471
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/ComposeAttachment.html
@@ -0,0 +1,19 @@
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/Login.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/Login.html
new file mode 100644
index 0000000..4a11cbb
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/Login.html
@@ -0,0 +1,147 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/LoginWelcome.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/LoginWelcome.html
new file mode 100644
index 0000000..8c233c9
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/LoginWelcome.html
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailFolderList.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailFolderList.html
new file mode 100644
index 0000000..9809d98
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailFolderList.html
@@ -0,0 +1,38 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailFolderListItem.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailFolderListItem.html
new file mode 100644
index 0000000..7ae0e60
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailFolderListItem.html
@@ -0,0 +1,12 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailFolderListSystemItem.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailFolderListSystemItem.html
new file mode 100644
index 0000000..f26adba
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailFolderListSystemItem.html
@@ -0,0 +1,12 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailMessageList.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailMessageList.html
new file mode 100644
index 0000000..a345015
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailMessageList.html
@@ -0,0 +1,208 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ . . .
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailMessageListItem.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailMessageListItem.html
new file mode 100644
index 0000000..a83231b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailMessageListItem.html
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ !
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailMessageListItemNoPreviewPane.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailMessageListItemNoPreviewPane.html
new file mode 100644
index 0000000..e16ec90
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailMessageListItemNoPreviewPane.html
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ !
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailMessageView.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailMessageView.html
new file mode 100644
index 0000000..b5fb4b9
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/MailMessageView.html
@@ -0,0 +1,421 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ . . .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ×
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PhotoSwipe.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PhotoSwipe.html
new file mode 100644
index 0000000..f256ed7
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PhotoSwipe.html
@@ -0,0 +1,33 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsAccount.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsAccount.html
new file mode 100644
index 0000000..02f4970
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsAccount.html
@@ -0,0 +1,50 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsAddOpenPgpKey.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsAddOpenPgpKey.html
new file mode 100644
index 0000000..e2b0374
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsAddOpenPgpKey.html
@@ -0,0 +1,26 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsAdvancedSearch.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsAdvancedSearch.html
new file mode 100644
index 0000000..48cac4c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsAdvancedSearch.html
@@ -0,0 +1,107 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsCompose.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsCompose.html
new file mode 100644
index 0000000..7e23a94
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsCompose.html
@@ -0,0 +1,218 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsComposeOpenPgp.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsComposeOpenPgp.html
new file mode 100644
index 0000000..49c65a5
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsComposeOpenPgp.html
@@ -0,0 +1,119 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsContacts.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsContacts.html
new file mode 100644
index 0000000..72b080f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsContacts.html
@@ -0,0 +1,276 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsFilter.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsFilter.html
new file mode 100644
index 0000000..b82169a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsFilter.html
@@ -0,0 +1,64 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsFolderClear.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsFolderClear.html
new file mode 100644
index 0000000..ee3d4c0
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsFolderClear.html
@@ -0,0 +1,34 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsFolderCreate.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsFolderCreate.html
new file mode 100644
index 0000000..82b86e1
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsFolderCreate.html
@@ -0,0 +1,42 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsFolderSystem.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsFolderSystem.html
new file mode 100644
index 0000000..265b2a7
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsFolderSystem.html
@@ -0,0 +1,63 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsIdentity.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsIdentity.html
new file mode 100644
index 0000000..731bcca
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsIdentity.html
@@ -0,0 +1,99 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsMessageOpenPgp.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsMessageOpenPgp.html
new file mode 100644
index 0000000..41b5b2e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsMessageOpenPgp.html
@@ -0,0 +1,54 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsNewOpenPgpKey.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsNewOpenPgpKey.html
new file mode 100644
index 0000000..916de9f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsNewOpenPgpKey.html
@@ -0,0 +1,53 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsTemplate.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsTemplate.html
new file mode 100644
index 0000000..fdfc11b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsTemplate.html
@@ -0,0 +1,44 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsTwoFactorConfiguration.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsTwoFactorConfiguration.html
new file mode 100644
index 0000000..b3cbb6c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsTwoFactorConfiguration.html
@@ -0,0 +1,106 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsTwoFactorTest.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsTwoFactorTest.html
new file mode 100644
index 0000000..92cc80b
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsTwoFactorTest.html
@@ -0,0 +1,34 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsViewOpenPgpKey.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsViewOpenPgpKey.html
new file mode 100644
index 0000000..c3673a8
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsViewOpenPgpKey.html
@@ -0,0 +1,31 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsWindowSimpleMessage.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsWindowSimpleMessage.html
new file mode 100644
index 0000000..6849d27
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/PopupsWindowSimpleMessage.html
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsAccounts.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsAccounts.html
new file mode 100644
index 0000000..5c33118
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsAccounts.html
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ( )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsChangePassword.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsChangePassword.html
new file mode 100644
index 0000000..810e3c4
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsChangePassword.html
@@ -0,0 +1,48 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsContacts.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsContacts.html
new file mode 100644
index 0000000..7ace99a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsContacts.html
@@ -0,0 +1,64 @@
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsCustom.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsCustom.html
new file mode 100644
index 0000000..8d135e5
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsCustom.html
@@ -0,0 +1,3 @@
+
+ CUSTOM
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFilters.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFilters.html
new file mode 100644
index 0000000..6f2454c
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFilters.html
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionDiscard.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionDiscard.html
new file mode 100644
index 0000000..e69de29
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionForward.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionForward.html
new file mode 100644
index 0000000..e9da576
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionForward.html
@@ -0,0 +1,24 @@
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionMoveToFolder.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionMoveToFolder.html
new file mode 100644
index 0000000..0f32a1a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionMoveToFolder.html
@@ -0,0 +1,17 @@
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionNone.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionNone.html
new file mode 100644
index 0000000..e69de29
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionReject.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionReject.html
new file mode 100644
index 0000000..fbfaef0
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionReject.html
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionVacation.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionVacation.html
new file mode 100644
index 0000000..0e12a70
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersActionVacation.html
@@ -0,0 +1,45 @@
+
+
+
+
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersConditionDefault.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersConditionDefault.html
new file mode 100644
index 0000000..7bf8c16
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersConditionDefault.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersConditionMore.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersConditionMore.html
new file mode 100644
index 0000000..61ac82e
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersConditionMore.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersConditionSize.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersConditionSize.html
new file mode 100644
index 0000000..0830dc8
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFiltersConditionSize.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFolderItem.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFolderItem.html
new file mode 100644
index 0000000..4c80e0f
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFolderItem.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFolders.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFolders.html
new file mode 100644
index 0000000..5b18f0d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsFolders.html
@@ -0,0 +1,45 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsGeneral.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsGeneral.html
new file mode 100644
index 0000000..28d917a
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsGeneral.html
@@ -0,0 +1,158 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsMenu.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsMenu.html
new file mode 100644
index 0000000..aa4f5b2
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsMenu.html
@@ -0,0 +1,28 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsOpenPGP.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsOpenPGP.html
new file mode 100644
index 0000000..b525a34
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsOpenPGP.html
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ( )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsPane.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsPane.html
new file mode 100644
index 0000000..3fdc7d7
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsPane.html
@@ -0,0 +1,28 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsSecurity.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsSecurity.html
new file mode 100644
index 0000000..feccf50
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsSecurity.html
@@ -0,0 +1,34 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsSocial.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsSocial.html
new file mode 100644
index 0000000..be95614
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsSocial.html
@@ -0,0 +1,101 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsTemplates.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsTemplates.html
new file mode 100644
index 0000000..fdf385d
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsTemplates.html
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsThemes.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsThemes.html
new file mode 100644
index 0000000..cc86478
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SettingsThemes.html
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SystemDropDown.html b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SystemDropDown.html
new file mode 100644
index 0000000..69e9a24
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/app/templates/Views/User/SystemDropDown.html
@@ -0,0 +1,102 @@
+
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/check.php b/rainloop/rainloop/v/1.10.0.103/check.php
new file mode 100644
index 0000000..6deb2bd
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/check.php
@@ -0,0 +1,42 @@
+ function_exists('curl_init'),
+ 'iconv' => function_exists('iconv'),
+ 'json' => function_exists('json_decode'),
+ 'DateTime' => class_exists('DateTime') && class_exists('DateTimeZone'),
+ 'libxml' => function_exists('libxml_use_internal_errors'),
+ 'dom' => class_exists('DOMDocument'),
+ 'Zlib' => function_exists('gzopen') || function_exists('gzopen64'),
+ 'PCRE' => function_exists('preg_replace'),
+ 'SPL' => function_exists('spl_autoload_register')
+ );
+
+ if (version_compare(PHP_VERSION, '5.3.0', '<'))
+ {
+ echo '';
+ echo '[301] Your PHP version ('.PHP_VERSION.') is lower than the minimal required 5.3.0!';
+ echo '
';
+ exit(301);
+ }
+
+ if (in_array(false, $aRequirements))
+ {
+ echo '';
+ echo '[302] The following PHP extensions are not available in your PHP configuration!';
+ echo '
';
+
+ foreach ($aRequirements as $sKey => $bValue)
+ {
+ if (!$bValue)
+ {
+ echo ''.$sKey.' ';
+ }
+ }
+
+ echo ' ';
+ exit(302);
+ }
+ }
diff --git a/rainloop/rainloop/v/1.10.0.103/include.php b/rainloop/rainloop/v/1.10.0.103/include.php
new file mode 100644
index 0000000..c33adf6
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/include.php
@@ -0,0 +1,230 @@
+\nOptions -Indexes\n");
+
+ if (function_exists('date_default_timezone_set'))
+ {
+ date_default_timezone_set('UTC');
+ }
+
+ $sSite = strtolower(trim(empty($_SERVER['HTTP_HOST']) ? (empty($_SERVER['SERVER_NAME']) ? '' : $_SERVER['SERVER_NAME']) : $_SERVER['HTTP_HOST']));
+ $sSite = 'www.' === substr($sSite, 0, 4) ? substr($sSite, 4) : $sSite;
+ $sSite = preg_replace('/^.+@/', '', preg_replace('/:[\d]+$/', '', $sSite));
+ $sSite = in_array($sSite, array('localhost', '127.0.0.1', '::1', '::1/128', '0:0:0:0:0:0:0:1')) ? 'localhost' : trim($sSite);
+ $sSite = 0 === strlen($sSite) ? 'localhost' : $sSite;
+
+ define('APP_SITE', $sSite);
+ unset($sSite);
+
+ define('APP_DEFAULT_PRIVATE_DATA_NAME', '_default_');
+
+ $sPrivateDataFolderInternalName = @file_exists(APP_INDEX_ROOT_PATH.'MULTIPLY') ? APP_SITE : '';
+ define('APP_PRIVATE_DATA_NAME', 0 === strlen($sPrivateDataFolderInternalName) ? APP_DEFAULT_PRIVATE_DATA_NAME : $sPrivateDataFolderInternalName);
+ define('APP_MULTIPLY', 0 < strlen($sPrivateDataFolderInternalName) && APP_DEFAULT_PRIVATE_DATA_NAME !== APP_PRIVATE_DATA_NAME);
+
+ define('APP_DUMMY', '********');
+ define('APP_DEV_VERSION', '0.0.0');
+ define('APP_GOOGLE_ACCESS_TOKEN_PREFIX', ':GAT:');
+ define('APP_WEB_SITE', 'http://www.rainloop.net/');
+ define('APP_API_PATH', 'http://api.rainloop.net/');
+ define('APP_STATUS_PATH', 'http://status.rainloop.net/');
+ define('APP_REPOSITORY_PATH', 'http://repository.rainloop.net/v1/');
+ define('APP_REPO_CORE_FILE', 'http://repository.rainloop.net/v2/core.{{channel}}.json');
+
+ $sCustomDataPath = '';
+ $sCustomConfiguration = '';
+
+ if (file_exists(APP_INDEX_ROOT_PATH.'include.php'))
+ {
+ include_once APP_INDEX_ROOT_PATH.'include.php';
+ }
+
+ $sCustomDataPath = function_exists('__get_custom_data_full_path') ? rtrim(trim(__get_custom_data_full_path()), '\\/') : '';
+ define('APP_DATA_FOLDER_PATH', 0 === strlen($sCustomDataPath) ? APP_INDEX_ROOT_PATH.'data/' : $sCustomDataPath.'/');
+ unset($sCustomDataPath);
+
+ $sCustomConfiguration = function_exists('__get_additional_configuration_name') ? trim(__get_additional_configuration_name()) : '';
+ define('APP_ADDITIONAL_CONFIGURATION_NAME', $sCustomConfiguration);
+ unset($sCustomConfiguration);
+
+ define('APP_DATA_FOLDER_PATH_UNIX', str_replace('\\', '/', APP_DATA_FOLDER_PATH));
+
+ $sSalt = @file_get_contents(APP_DATA_FOLDER_PATH.'SALT.php');
+ $sData = file_exists(APP_DATA_FOLDER_PATH.'DATA.php') ? @file_get_contents(APP_DATA_FOLDER_PATH.'DATA.php') : '';
+ $sInstalled = @file_get_contents(APP_DATA_FOLDER_PATH.'INSTALLED');
+
+ // installation checking data folder
+ if (APP_VERSION !== $sInstalled)
+ {
+ include APP_VERSION_ROOT_PATH.'check.php';
+
+ $sCheckName = 'delete_if_you_see_it_after_install';
+ $sCheckFolder = APP_DATA_FOLDER_PATH.$sCheckName;
+ $sCheckFilePath = APP_DATA_FOLDER_PATH.$sCheckName.'/'.$sCheckName.'.file';
+
+ @unlink($sCheckFilePath);
+ @rmdir($sCheckFolder);
+
+ if (!@is_dir(APP_DATA_FOLDER_PATH))
+ {
+ @mkdir(APP_DATA_FOLDER_PATH, 0755);
+ }
+ else
+ {
+ @chmod(APP_DATA_FOLDER_PATH, 0755);
+ }
+
+ $sTest = '';
+ switch (true)
+ {
+ case !@is_dir(APP_DATA_FOLDER_PATH):
+ $sTest = 'is_dir';
+ break;
+ case !@is_readable(APP_DATA_FOLDER_PATH):
+ $sTest = 'is_readable';
+ break;
+ case !@is_writable(APP_DATA_FOLDER_PATH):
+ $sTest = 'is_writable';
+ break;
+ case !@mkdir($sCheckFolder, 0755):
+ $sTest = 'mkdir';
+ break;
+ case false === @file_put_contents($sCheckFilePath, time()):
+ $sTest = 'file_put_contents';
+ break;
+ case !@unlink($sCheckFilePath):
+ $sTest = 'unlink';
+ break;
+ case !@rmdir($sCheckFolder):
+ $sTest = 'rmdir';
+ break;
+ }
+
+ if (!empty($sTest))
+ {
+ echo '[202] Data folder permissions error ['.$sTest.']';
+ exit(202);
+ }
+
+ unset($sCheckName, $sCheckFilePath, $sCheckFolder, $sTest);
+ }
+
+ if (false === $sSalt)
+ {
+ // random salt
+ $sSalt = '<'.'?php //'
+ .md5(microtime(true).rand(1000, 5000))
+ .md5(microtime(true).rand(5000, 9999))
+ .md5(microtime(true).rand(1000, 5000));
+
+ @file_put_contents(APP_DATA_FOLDER_PATH.'SALT.php', $sSalt);
+ }
+
+ define('APP_SALT', md5($sSalt.APP_PRIVATE_DATA_NAME.$sSalt));
+ define('APP_PRIVATE_DATA', APP_DATA_FOLDER_PATH.'_data_'.($sData ? md5($sData) : '').'/'.APP_PRIVATE_DATA_NAME.'/');
+
+ define('APP_PLUGINS_PATH', APP_PRIVATE_DATA.'plugins/');
+
+ if (APP_VERSION !== $sInstalled || (APP_MULTIPLY && !@is_dir(APP_PRIVATE_DATA)))
+ {
+ define('APP_INSTALLED_START', true);
+ define('APP_INSTALLED_VERSION', $sInstalled);
+
+ @file_put_contents(APP_DATA_FOLDER_PATH.'INSTALLED', APP_VERSION);
+ @file_put_contents(APP_DATA_FOLDER_PATH.'index.html', 'Forbidden');
+ @file_put_contents(APP_DATA_FOLDER_PATH.'index.php', 'Forbidden');
+ @file_put_contents(APP_DATA_FOLDER_PATH.'.htaccess', APP_DEFAULT_DENY_ALL_HTACCESS);
+
+ if (!@is_dir(APP_PRIVATE_DATA))
+ {
+ @mkdir(APP_PRIVATE_DATA, 0755, true);
+ }
+
+ foreach (array('logs', 'cache', 'configs', 'plugins', 'storage') as $sName)
+ {
+ if (!@is_dir(APP_PRIVATE_DATA.$sName))
+ {
+ @mkdir(APP_PRIVATE_DATA.$sName, 0755, true);
+ }
+ }
+
+ if (!@file_exists(APP_PRIVATE_DATA.'domains/disabled'))
+ {
+ if (!@is_dir(APP_PRIVATE_DATA.'domains'))
+ {
+ @mkdir(APP_PRIVATE_DATA.'domains', 0755);
+ }
+
+ if (@is_dir(APP_PRIVATE_DATA.'domains'))
+ {
+ $sFile = $sNewFile = $sNewFileName = '';
+ $aFiles = @glob(APP_VERSION_ROOT_PATH.'app/domains/*');
+
+ if (is_array($aFiles) && 0 < \count($aFiles))
+ {
+ foreach ($aFiles as $sFile)
+ {
+ if (@is_file($sFile))
+ {
+ $sNewFileName = basename($sFile);
+ if ('default.ini.dist' !== $sNewFileName)
+ {
+ $sNewFile = APP_PRIVATE_DATA.'domains/'.$sNewFileName;
+ if (!@file_exists($sNewFile))
+ {
+ @copy($sFile, $sNewFile);
+ }
+ }
+ }
+ }
+ }
+
+// $sClearedSiteName = preg_replace('/^(www|demo|rainloop|webmail|email|mail|imap|imap4|smtp|pop|pop3)\./i', '', trim(APP_SITE));
+// if (!empty($sClearedSiteName) && @file_exists(APP_VERSION_ROOT_PATH.'app/domains/default.ini.dist') &&
+// !@file_exists(APP_PRIVATE_DATA.'domains/'.$sClearedSiteName.'.ini'))
+// {
+// $sConfigTemplate = @file_get_contents(APP_VERSION_ROOT_PATH.'app/domains/default.ini.dist');
+// if (!empty($sConfigTemplate))
+// {
+// @file_put_contents(APP_PRIVATE_DATA.'domains/'.$sClearedSiteName.'.ini', strtr($sConfigTemplate, array(
+// 'IMAP_HOST' => 'localhost' !== $sClearedSiteName? 'imap.'.$sClearedSiteName : $sClearedSiteName,
+// 'IMAP_PORT' => '993',
+// 'SMTP_HOST' => 'localhost' !== $sClearedSiteName? 'smtp.'.$sClearedSiteName : $sClearedSiteName,
+// 'SMTP_PORT' => '465'
+// )));
+// }
+//
+// unset($sConfigTemplate);
+// }
+
+ unset($aFiles, $sFile, $sNewFileName, $sNewFile);
+ }
+ }
+ }
+
+ unset($sSalt, $sData, $sInstalled, $sPrivateDataFolderInternalName);
+ }
+
+ include APP_VERSION_ROOT_PATH.'app/handle.php';
+
+ if (defined('RAINLOOP_EXIT_ON_END') && RAINLOOP_EXIT_ON_END)
+ {
+ exit(0);
+ }
+ }
diff --git a/rainloop/rainloop/v/1.10.0.103/index.php b/rainloop/rainloop/v/1.10.0.103/index.php
new file mode 100644
index 0000000..e69de29
diff --git a/rainloop/rainloop/v/1.10.0.103/index.php.root b/rainloop/rainloop/v/1.10.0.103/index.php.root
new file mode 100644
index 0000000..5f77db1
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/index.php.root
@@ -0,0 +1,18 @@
+g.getListenerIndex(d)){g=g.listeners;f||(f=this);isNaN(k)&&(k=10);var z=this;q.fn=d;q.priority=k;for(var A=g.length-1;0<=A;A--)if(g[A].priority<=k)return g.splice(A+1,0,q),{removeListener:t};g.unshift(q)}return{removeListener:t}},
+once:function(){var a=Array.prototype.slice.call(arguments),b=a[1];a[1]=function(a){a.removeListener();return b.apply(this,arguments)};return this.on.apply(this,a)},capture:function(){CKEDITOR.event.useCapture=1;var a=this.on.apply(this,arguments);CKEDITOR.event.useCapture=0;return a},fire:function(){var a=0,b=function(){a=1},f=0,h=function(){f=1};return function(k,q,t){var g=d(this)[k];k=a;var z=f;a=f=0;if(g){var A=g.listeners;if(A.length)for(var A=A.slice(0),v,C=0;Cdocument.documentMode),mobile:-1c||b.quirks);b.gecko&&(d=a.match(/rv:([\d\.]+)/))&&(d=d[1].split("."),c=1E4*d[0]+100*(d[1]||0)+1*(d[2]||0));b.air&&(c=parseFloat(a.match(/ adobeair\/(\d+)/)[1]));
+b.webkit&&(c=parseFloat(a.match(/ applewebkit\/(\d+)/)[1]));b.version=c;b.isCompatible=!(b.ie&&7>c)&&!(b.gecko&&4E4>c)&&!(b.webkit&&534>c);b.hidpi=2<=window.devicePixelRatio;b.needsBrFiller=b.gecko||b.webkit||b.ie&&10c;b.cssClass="cke_browser_"+(b.ie?"ie":b.gecko?"gecko":b.webkit?"webkit":"unknown");b.quirks&&(b.cssClass+=" cke_browser_quirks");b.ie&&(b.cssClass+=" cke_browser_ie"+(b.quirks?"6 cke_browser_iequirks":b.version));b.air&&(b.cssClass+=" cke_browser_air");
+b.iOS&&(b.cssClass+=" cke_browser_ios");b.hidpi&&(b.cssClass+=" cke_hidpi");return b}());
+"unloaded"==CKEDITOR.status&&function(){CKEDITOR.event.implementOn(CKEDITOR);CKEDITOR.loadFullCore=function(){if("basic_ready"!=CKEDITOR.status)CKEDITOR.loadFullCore._load=1;else{delete CKEDITOR.loadFullCore;var a=document.createElement("script");a.type="text/javascript";a.src=CKEDITOR.basePath+"ckeditor.js";document.getElementsByTagName("head")[0].appendChild(a)}};CKEDITOR.loadFullCoreTimeout=0;CKEDITOR.add=function(a){(this._.pending||(this._.pending=[])).push(a)};(function(){CKEDITOR.domReady(function(){var a=
+CKEDITOR.loadFullCore,d=CKEDITOR.loadFullCoreTimeout;a&&(CKEDITOR.status="basic_ready",a&&a._load?a():d&&setTimeout(function(){CKEDITOR.loadFullCore&&CKEDITOR.loadFullCore()},1E3*d))})})();CKEDITOR.status="basic_loaded"}();"use strict";CKEDITOR.VERBOSITY_WARN=1;CKEDITOR.VERBOSITY_ERROR=2;CKEDITOR.verbosity=CKEDITOR.VERBOSITY_WARN|CKEDITOR.VERBOSITY_ERROR;CKEDITOR.warn=function(a,d){CKEDITOR.verbosity&CKEDITOR.VERBOSITY_WARN&&CKEDITOR.fire("log",{type:"warn",errorCode:a,additionalData:d})};
+CKEDITOR.error=function(a,d){CKEDITOR.verbosity&CKEDITOR.VERBOSITY_ERROR&&CKEDITOR.fire("log",{type:"error",errorCode:a,additionalData:d})};CKEDITOR.on("log",function(a){if(window.console&&window.console.log){var d=console[a.data.type]?a.data.type:"log",b=a.data.errorCode;if(a=a.data.additionalData)console[d]("[CKEDITOR] "+b,a);else console[d]("[CKEDITOR] "+b);console[d]("[CKEDITOR] For more information go to http://docs.ckeditor.com/#!/guide/dev_errors-section-"+b)}},null,null,999);
+CKEDITOR.dom={};
+(function(){var a=[],d=CKEDITOR.env.gecko?"-moz-":CKEDITOR.env.webkit?"-webkit-":CKEDITOR.env.ie?"-ms-":"",b=/&/g,c=/>/g,e=/|\s) /g,
+function(a,b){return b+"\x26nbsp;"}).replace(/ (?=<)/g,"\x26nbsp;")},getNextNumber:function(){var a=0;return function(){return++a}}(),getNextId:function(){return"cke_"+this.getNextNumber()},getUniqueId:function(){for(var a="e",b=0;8>b;b++)a+=Math.floor(65536*(1+Math.random())).toString(16).substring(1);return a},override:function(a,b){var c=b(a);c.prototype=a.prototype;return c},setTimeout:function(a,b,c,k,d){d||(d=window);c||(c=d);return d.setTimeout(function(){k?a.apply(c,[].concat(k)):a.apply(c)},
+b||0)},trim:function(){var a=/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g;return function(b){return b.replace(a,"")}}(),ltrim:function(){var a=/^[ \t\n\r]+/g;return function(b){return b.replace(a,"")}}(),rtrim:function(){var a=/[ \t\n\r]+$/g;return function(b){return b.replace(a,"")}}(),indexOf:function(a,b){if("function"==typeof b)for(var c=0,k=a.length;cb;b++)a[b]=("0"+parseInt(a[b],10).toString(16)).slice(-2);
+return"#"+a.join("")})},parseCssText:function(a,b,c){var k={};c&&(c=new CKEDITOR.dom.element("span"),c.setAttribute("style",a),a=CKEDITOR.tools.convertRgbToHex(c.getAttribute("style")||""));if(!a||";"==a)return k;a.replace(/"/g,'"').replace(/\s*([^:;\s]+)\s*:\s*([^;]+)\s*(?=;|$)/g,function(a,c,d){b&&(c=c.toLowerCase(),"font-family"==c&&(d=d.toLowerCase().replace(/["']/g,"").replace(/\s*,\s*/g,",")),d=CKEDITOR.tools.trim(d));k[c]=d});return k},writeCssText:function(a,b){var c,k=[];for(c in a)k.push(c+
+":"+a[c]);b&&k.sort();return k.join("; ")},objectCompare:function(a,b,c){var k;if(!a&&!b)return!0;if(!a||!b)return!1;for(k in a)if(a[k]!=b[k])return!1;if(!c)for(k in b)if(a[k]!=b[k])return!1;return!0},objectKeys:function(a){var b=[],c;for(c in a)b.push(c);return b},convertArrayToObject:function(a,b){var c={};1==arguments.length&&(b=!0);for(var k=0,d=a.length;kCKEDITOR.env.version&&(this.type==CKEDITOR.NODE_ELEMENT||this.type==CKEDITOR.NODE_DOCUMENT_FRAGMENT)&&c(e);return e},hasPrevious:function(){return!!this.$.previousSibling},hasNext:function(){return!!this.$.nextSibling},insertAfter:function(a){a.$.parentNode.insertBefore(this.$,a.$.nextSibling);return a},insertBefore:function(a){a.$.parentNode.insertBefore(this.$,
+a.$);return a},insertBeforeMe:function(a){this.$.parentNode.insertBefore(a.$,this.$);return a},getAddress:function(a){for(var d=[],b=this.getDocument().$.documentElement,c=this.$;c&&c!=b;){var e=c.parentNode;e&&d.unshift(this.getIndex.call({$:c},a));c=e}return d},getDocument:function(){return new CKEDITOR.dom.document(this.$.ownerDocument||this.$.parentNode.ownerDocument)},getIndex:function(a){function d(a,b){var c=b?a.nextSibling:a.previousSibling;return c&&c.nodeType==CKEDITOR.NODE_TEXT?c.nodeValue?
+c:d(c,b):null}var b=this.$,c=-1,e;if(!this.$.parentNode||a&&b.nodeType==CKEDITOR.NODE_TEXT&&!b.nodeValue&&!d(b)&&!d(b,!0))return-1;do if(!a||b==this.$||b.nodeType!=CKEDITOR.NODE_TEXT||!e&&b.nodeValue)c++,e=b.nodeType==CKEDITOR.NODE_TEXT;while(b=b.previousSibling);return c},getNextSourceNode:function(a,d,b){if(b&&!b.call){var c=b;b=function(a){return!a.equals(c)}}a=!a&&this.getFirst&&this.getFirst();var e;if(!a){if(this.type==CKEDITOR.NODE_ELEMENT&&b&&!1===b(this,!0))return null;a=this.getNext()}for(;!a&&
+(e=(e||this).getParent());){if(b&&!1===b(e,!0))return null;a=e.getNext()}return!a||b&&!1===b(a)?null:d&&d!=a.type?a.getNextSourceNode(!1,d,b):a},getPreviousSourceNode:function(a,d,b){if(b&&!b.call){var c=b;b=function(a){return!a.equals(c)}}a=!a&&this.getLast&&this.getLast();var e;if(!a){if(this.type==CKEDITOR.NODE_ELEMENT&&b&&!1===b(this,!0))return null;a=this.getPrevious()}for(;!a&&(e=(e||this).getParent());){if(b&&!1===b(e,!0))return null;a=e.getPrevious()}return!a||b&&!1===b(a)?null:d&&a.type!=
+d?a.getPreviousSourceNode(!1,d,b):a},getPrevious:function(a){var d=this.$,b;do b=(d=d.previousSibling)&&10!=d.nodeType&&new CKEDITOR.dom.node(d);while(b&&a&&!a(b));return b},getNext:function(a){var d=this.$,b;do b=(d=d.nextSibling)&&new CKEDITOR.dom.node(d);while(b&&a&&!a(b));return b},getParent:function(a){var d=this.$.parentNode;return d&&(d.nodeType==CKEDITOR.NODE_ELEMENT||a&&d.nodeType==CKEDITOR.NODE_DOCUMENT_FRAGMENT)?new CKEDITOR.dom.node(d):null},getParents:function(a){var d=this,b=[];do b[a?
+"push":"unshift"](d);while(d=d.getParent());return b},getCommonAncestor:function(a){if(a.equals(this))return this;if(a.contains&&a.contains(this))return a;var d=this.contains?this:this.getParent();do if(d.contains(a))return d;while(d=d.getParent());return null},getPosition:function(a){var d=this.$,b=a.$;if(d.compareDocumentPosition)return d.compareDocumentPosition(b);if(d==b)return CKEDITOR.POSITION_IDENTICAL;if(this.type==CKEDITOR.NODE_ELEMENT&&a.type==CKEDITOR.NODE_ELEMENT){if(d.contains){if(d.contains(b))return CKEDITOR.POSITION_CONTAINS+
+CKEDITOR.POSITION_PRECEDING;if(b.contains(d))return CKEDITOR.POSITION_IS_CONTAINED+CKEDITOR.POSITION_FOLLOWING}if("sourceIndex"in d)return 0>d.sourceIndex||0>b.sourceIndex?CKEDITOR.POSITION_DISCONNECTED:d.sourceIndex=document.documentMode||!d||(a=d+":"+a);return new CKEDITOR.dom.nodeList(this.$.getElementsByTagName(a))},getHead:function(){var a=this.$.getElementsByTagName("head")[0];
+return a=a?new CKEDITOR.dom.element(a):this.getDocumentElement().append(new CKEDITOR.dom.element("head"),!0)},getBody:function(){return new CKEDITOR.dom.element(this.$.body)},getDocumentElement:function(){return new CKEDITOR.dom.element(this.$.documentElement)},getWindow:function(){return new CKEDITOR.dom.window(this.$.parentWindow||this.$.defaultView)},write:function(a){this.$.open("text/html","replace");CKEDITOR.env.ie&&(a=a.replace(/(?:^\s*]*?>)|^/i,'$\x26\n\x3cscript data-cke-temp\x3d"1"\x3e('+
+CKEDITOR.tools.fixDomain+")();\x3c/script\x3e"));this.$.write(a);this.$.close()},find:function(a){return new CKEDITOR.dom.nodeList(this.$.querySelectorAll(a))},findOne:function(a){return(a=this.$.querySelector(a))?new CKEDITOR.dom.element(a):null},_getHtml5ShivFrag:function(){var a=this.getCustomData("html5ShivFrag");a||(a=this.$.createDocumentFragment(),CKEDITOR.tools.enableHtml5Elements(a,!0),this.setCustomData("html5ShivFrag",a));return a}});CKEDITOR.dom.nodeList=function(a){this.$=a};
+CKEDITOR.dom.nodeList.prototype={count:function(){return this.$.length},getItem:function(a){return 0>a||a>=this.$.length?null:(a=this.$[a])?new CKEDITOR.dom.node(a):null}};CKEDITOR.dom.element=function(a,d){"string"==typeof a&&(a=(d?d.$:document).createElement(a));CKEDITOR.dom.domObject.call(this,a)};CKEDITOR.dom.element.get=function(a){return(a="string"==typeof a?document.getElementById(a)||document.getElementsByName(a)[0]:a)&&(a.$?a:new CKEDITOR.dom.element(a))};CKEDITOR.dom.element.prototype=new CKEDITOR.dom.node;
+CKEDITOR.dom.element.createFromHtml=function(a,d){var b=new CKEDITOR.dom.element("div",d);b.setHtml(a);return b.getFirst().remove()};CKEDITOR.dom.element.setMarker=function(a,d,b,c){var e=d.getCustomData("list_marker_id")||d.setCustomData("list_marker_id",CKEDITOR.tools.getNextNumber()).getCustomData("list_marker_id"),f=d.getCustomData("list_marker_names")||d.setCustomData("list_marker_names",{}).getCustomData("list_marker_names");a[e]=d;f[b]=1;return d.setCustomData(b,c)};
+CKEDITOR.dom.element.clearAllMarkers=function(a){for(var d in a)CKEDITOR.dom.element.clearMarkers(a,a[d],1)};CKEDITOR.dom.element.clearMarkers=function(a,d,b){var c=d.getCustomData("list_marker_names"),e=d.getCustomData("list_marker_id"),f;for(f in c)d.removeCustomData(f);d.removeCustomData("list_marker_names");b&&(d.removeCustomData("list_marker_id"),delete a[e])};
+(function(){function a(a,b){return-1<(" "+a+" ").replace(f," ").indexOf(" "+b+" ")}function d(a){var b=!0;a.$.id||(a.$.id="cke_tmp_"+CKEDITOR.tools.getNextNumber(),b=!1);return function(){b||a.removeAttribute("id")}}function b(a,b){return"#"+a.$.id+" "+b.split(/,\s*/).join(", #"+a.$.id+" ")}function c(a){for(var b=0,c=0,g=h[a].length;cCKEDITOR.env.version?this.$.text+=a:this.append(new CKEDITOR.dom.text(a))},
+appendBogus:function(a){if(a||CKEDITOR.env.needsBrFiller){for(a=this.getLast();a&&a.type==CKEDITOR.NODE_TEXT&&!CKEDITOR.tools.rtrim(a.getText());)a=a.getPrevious();a&&a.is&&a.is("br")||(a=this.getDocument().createElement("br"),CKEDITOR.env.gecko&&a.setAttribute("type","_moz"),this.append(a))}},breakParent:function(a,b){var c=new CKEDITOR.dom.range(this.getDocument());c.setStartAfter(this);c.setEndAfter(a);var g=c.extractContents(!1,b||!1);c.insertNode(this.remove());g.insertAfterNode(this)},contains:document.compareDocumentPosition?
+function(a){return!!(this.$.compareDocumentPosition(a.$)&16)}:function(a){var b=this.$;return a.type!=CKEDITOR.NODE_ELEMENT?b.contains(a.getParent().$):b!=a.$&&b.contains(a.$)},focus:function(){function a(){try{this.$.focus()}catch(b){}}return function(b){b?CKEDITOR.tools.setTimeout(a,100,this):a.call(this)}}(),getHtml:function(){var a=this.$.innerHTML;return CKEDITOR.env.ie?a.replace(/<\?[^>]*>/g,""):a},getOuterHtml:function(){if(this.$.outerHTML)return this.$.outerHTML.replace(/<\?[^>]*>/,"");var a=
+this.$.ownerDocument.createElement("div");a.appendChild(this.$.cloneNode(!0));return a.innerHTML},getClientRect:function(){var a=CKEDITOR.tools.extend({},this.$.getBoundingClientRect());!a.width&&(a.width=a.right-a.left);!a.height&&(a.height=a.bottom-a.top);return a},setHtml:CKEDITOR.env.ie&&9>CKEDITOR.env.version?function(a){try{var b=this.$;if(this.getParent())return b.innerHTML=a;var c=this.getDocument()._getHtml5ShivFrag();c.appendChild(b);b.innerHTML=a;c.removeChild(b);return a}catch(g){this.$.innerHTML=
+"";b=new CKEDITOR.dom.element("body",this.getDocument());b.$.innerHTML=a;for(b=b.getChildren();b.count();)this.append(b.getItem(0));return a}}:function(a){return this.$.innerHTML=a},setText:function(){var a=document.createElement("p");a.innerHTML="x";a=a.textContent;return function(b){this.$[a?"textContent":"innerText"]=b}}(),getAttribute:function(){var a=function(a){return this.$.getAttribute(a,2)};return CKEDITOR.env.ie&&(CKEDITOR.env.ie7Compat||CKEDITOR.env.quirks)?function(a){switch(a){case "class":a=
+"className";break;case "http-equiv":a="httpEquiv";break;case "name":return this.$.name;case "tabindex":return a=this.$.getAttribute(a,2),0!==a&&0===this.$.tabIndex&&(a=null),a;case "checked":return a=this.$.attributes.getNamedItem(a),(a.specified?a.nodeValue:this.$.checked)?"checked":null;case "hspace":case "value":return this.$[a];case "style":return this.$.style.cssText;case "contenteditable":case "contentEditable":return this.$.attributes.getNamedItem("contentEditable").specified?this.$.getAttribute("contentEditable"):
+null}return this.$.getAttribute(a,2)}:a}(),getChildren:function(){return new CKEDITOR.dom.nodeList(this.$.childNodes)},getComputedStyle:document.defaultView&&document.defaultView.getComputedStyle?function(a){var b=this.getWindow().$.getComputedStyle(this.$,null);return b?b.getPropertyValue(a):""}:function(a){return this.$.currentStyle[CKEDITOR.tools.cssStyleToDomStyle(a)]},getDtd:function(){var a=CKEDITOR.dtd[this.getName()];this.getDtd=function(){return a};return a},getElementsByTag:CKEDITOR.dom.document.prototype.getElementsByTag,
+getTabIndex:function(){var a=this.$.tabIndex;return 0!==a||CKEDITOR.dtd.$tabIndex[this.getName()]||0===parseInt(this.getAttribute("tabindex"),10)?a:-1},getText:function(){return this.$.textContent||this.$.innerText||""},getWindow:function(){return this.getDocument().getWindow()},getId:function(){return this.$.id||null},getNameAtt:function(){return this.$.name||null},getName:function(){var a=this.$.nodeName.toLowerCase();if(CKEDITOR.env.ie&&8>=document.documentMode){var b=this.$.scopeName;"HTML"!=
+b&&(a=b.toLowerCase()+":"+a)}this.getName=function(){return a};return this.getName()},getValue:function(){return this.$.value},getFirst:function(a){var b=this.$.firstChild;(b=b&&new CKEDITOR.dom.node(b))&&a&&!a(b)&&(b=b.getNext(a));return b},getLast:function(a){var b=this.$.lastChild;(b=b&&new CKEDITOR.dom.node(b))&&a&&!a(b)&&(b=b.getPrevious(a));return b},getStyle:function(a){return this.$.style[CKEDITOR.tools.cssStyleToDomStyle(a)]},is:function(){var a=this.getName();if("object"==typeof arguments[0])return!!arguments[0][a];
+for(var b=0;bCKEDITOR.env.version&&this.is("a")){var c=this.getParent();
+c.type==CKEDITOR.NODE_ELEMENT&&(c=c.clone(),c.setHtml(b),b=c.getHtml(),c.setHtml(a),a=c.getHtml())}return b==a},isVisible:function(){var a=(this.$.offsetHeight||this.$.offsetWidth)&&"hidden"!=this.getComputedStyle("visibility"),b,c;a&&CKEDITOR.env.webkit&&(b=this.getWindow(),!b.equals(CKEDITOR.document.getWindow())&&(c=b.$.frameElement)&&(a=(new CKEDITOR.dom.element(c)).isVisible()));return!!a},isEmptyInlineRemoveable:function(){if(!CKEDITOR.dtd.$removeEmpty[this.getName()])return!1;for(var a=this.getChildren(),
+b=0,c=a.count();bCKEDITOR.env.version?function(b){return"name"==b?!!this.$.name:a.call(this,b)}:a:function(a){return!!this.$.attributes.getNamedItem(a)}}(),hide:function(){this.setStyle("display","none")},moveChildren:function(a,b){var c=this.$;a=a.$;if(c!=a){var g;if(b)for(;g=c.lastChild;)a.insertBefore(c.removeChild(g),a.firstChild);else for(;g=c.firstChild;)a.appendChild(c.removeChild(g))}},mergeSiblings:function(){function a(b,c,g){if(c&&c.type==CKEDITOR.NODE_ELEMENT){for(var d=[];c.data("cke-bookmark")||c.isEmptyInlineRemoveable();)if(d.push(c),
+c=g?c.getNext():c.getPrevious(),!c||c.type!=CKEDITOR.NODE_ELEMENT)return;if(b.isIdentical(c)){for(var k=g?b.getLast():b.getFirst();d.length;)d.shift().move(b,!g);c.moveChildren(b,!g);c.remove();k&&k.type==CKEDITOR.NODE_ELEMENT&&k.mergeSiblings()}}}return function(b){if(!1===b||CKEDITOR.dtd.$removeEmpty[this.getName()]||this.is("a"))a(this,this.getNext(),!0),a(this,this.getPrevious())}}(),show:function(){this.setStyles({display:"",visibility:""})},setAttribute:function(){var a=function(a,b){this.$.setAttribute(a,
+b);return this};return CKEDITOR.env.ie&&(CKEDITOR.env.ie7Compat||CKEDITOR.env.quirks)?function(b,c){"class"==b?this.$.className=c:"style"==b?this.$.style.cssText=c:"tabindex"==b?this.$.tabIndex=c:"checked"==b?this.$.checked=c:"contenteditable"==b?a.call(this,"contentEditable",c):a.apply(this,arguments);return this}:CKEDITOR.env.ie8Compat&&CKEDITOR.env.secure?function(b,c){if("src"==b&&c.match(/^http:\/\//))try{a.apply(this,arguments)}catch(g){}else a.apply(this,arguments);return this}:a}(),setAttributes:function(a){for(var b in a)this.setAttribute(b,
+a[b]);return this},setValue:function(a){this.$.value=a;return this},removeAttribute:function(){var a=function(a){this.$.removeAttribute(a)};return CKEDITOR.env.ie&&(CKEDITOR.env.ie7Compat||CKEDITOR.env.quirks)?function(a){"class"==a?a="className":"tabindex"==a?a="tabIndex":"contenteditable"==a&&(a="contentEditable");this.$.removeAttribute(a)}:a}(),removeAttributes:function(a){if(CKEDITOR.tools.isArray(a))for(var b=0;bCKEDITOR.env.version?(a=Math.round(100*a),this.setStyle("filter",100<=a?"":"progid:DXImageTransform.Microsoft.Alpha(opacity\x3d"+a+")")):this.setStyle("opacity",a)},unselectable:function(){this.setStyles(CKEDITOR.tools.cssVendorPrefix("user-select","none"));if(CKEDITOR.env.ie){this.setAttribute("unselectable",
+"on");for(var a,b=this.getElementsByTag("*"),c=0,g=b.count();cv||0v?v:d);c&&(0>e||0e?e:g,0)},setState:function(a,b,c){b=b||"cke";switch(a){case CKEDITOR.TRISTATE_ON:this.addClass(b+"_on");this.removeClass(b+"_off");this.removeClass(b+"_disabled");c&&this.setAttribute("aria-pressed",!0);c&&this.removeAttribute("aria-disabled");break;case CKEDITOR.TRISTATE_DISABLED:this.addClass(b+
+"_disabled");this.removeClass(b+"_off");this.removeClass(b+"_on");c&&this.setAttribute("aria-disabled",!0);c&&this.removeAttribute("aria-pressed");break;default:this.addClass(b+"_off"),this.removeClass(b+"_on"),this.removeClass(b+"_disabled"),c&&this.removeAttribute("aria-pressed"),c&&this.removeAttribute("aria-disabled")}},getFrameDocument:function(){var a=this.$;try{a.contentWindow.document}catch(b){a.src=a.src}return a&&new CKEDITOR.dom.document(a.contentWindow.document)},copyAttributes:function(a,
+b){var c=this.$.attributes;b=b||{};for(var g=0;g=m.getChildCount()?(m=m.getChild(r-1),B=!0):m=m.getChild(r):t=B=!0;p.type==CKEDITOR.NODE_TEXT?l?q=!0:p.split(D):0fa)for(;W;)W=n(W,O,!0);O=L}l||h()}}function b(){var a=!1,b=CKEDITOR.dom.walker.whitespaces(),
+c=CKEDITOR.dom.walker.bookmark(!0),d=CKEDITOR.dom.walker.bogus();return function(e){return c(e)||b(e)?!0:d(e)&&!a?a=!0:e.type==CKEDITOR.NODE_TEXT&&(e.hasAscendant("pre")||CKEDITOR.tools.trim(e.getText()).length)||e.type==CKEDITOR.NODE_ELEMENT&&!e.is(f)?!1:!0}}function c(a){var b=CKEDITOR.dom.walker.whitespaces(),c=CKEDITOR.dom.walker.bookmark(1);return function(d){return c(d)||b(d)?!0:!a&&h(d)||d.type==CKEDITOR.NODE_ELEMENT&&d.is(CKEDITOR.dtd.$removeEmpty)}}function e(a){return function(){var b;return this[a?
+"getPreviousNode":"getNextNode"](function(a){!b&&t(a)&&(b=a);return q(a)&&!(h(a)&&a.equals(b))})}}var f={abbr:1,acronym:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,"var":1},h=CKEDITOR.dom.walker.bogus(),k=/^[\t\r\n ]*(?: |\xa0)$/,q=CKEDITOR.dom.walker.editable(),t=CKEDITOR.dom.walker.ignored(!0);CKEDITOR.dom.range.prototype={clone:function(){var a=new CKEDITOR.dom.range(this.root);a._setStartContainer(this.startContainer);
+a.startOffset=this.startOffset;a._setEndContainer(this.endContainer);a.endOffset=this.endOffset;a.collapsed=this.collapsed;return a},collapse:function(a){a?(this._setEndContainer(this.startContainer),this.endOffset=this.startOffset):(this._setStartContainer(this.endContainer),this.startOffset=this.endOffset);this.collapsed=!0},cloneContents:function(a){var b=new CKEDITOR.dom.documentFragment(this.document);this.collapsed||d(this,2,b,!1,"undefined"==typeof a?!0:a);return b},deleteContents:function(a){this.collapsed||
+d(this,0,null,a)},extractContents:function(a,b){var c=new CKEDITOR.dom.documentFragment(this.document);this.collapsed||d(this,1,c,a,"undefined"==typeof b?!0:b);return c},createBookmark:function(a){var b,c,d,e,n=this.collapsed;b=this.document.createElement("span");b.data("cke-bookmark",1);b.setStyle("display","none");b.setHtml("\x26nbsp;");a&&(d="cke_bm_"+CKEDITOR.tools.getNextNumber(),b.setAttribute("id",d+(n?"C":"S")));n||(c=b.clone(),c.setHtml("\x26nbsp;"),a&&c.setAttribute("id",d+"E"),e=this.clone(),
+e.collapse(),e.insertNode(c));e=this.clone();e.collapse(!0);e.insertNode(b);c?(this.setStartAfter(b),this.setEndBefore(c)):this.moveToPosition(b,CKEDITOR.POSITION_AFTER_END);return{startNode:a?d+(n?"C":"S"):b,endNode:a?d+"E":c,serializable:a,collapsed:n}},createBookmark2:function(){function a(c){var g=c.container,d=c.offset,e;e=g;var f=d;e=e.type!=CKEDITOR.NODE_ELEMENT||0===f||f==e.getChildCount()?0:e.getChild(f-1).type==CKEDITOR.NODE_TEXT&&e.getChild(f).type==CKEDITOR.NODE_TEXT;e&&(g=g.getChild(d-
+1),d=g.getLength());g.type==CKEDITOR.NODE_ELEMENT&&1c)a=a.getChild(c);else if(1>e)a=a.getPreviousSourceNode();else{for(a=a.$;a.lastChild;)a=a.lastChild;a=new CKEDITOR.dom.node(a);a=a.getNextSourceNode()||a}if(b.type==CKEDITOR.NODE_ELEMENT)if(e=
+b.getChildCount(),e>d)b=b.getChild(d).getPreviousSourceNode(!0);else if(1>e)b=b.getPreviousSourceNode();else{for(b=b.$;b.lastChild;)b=b.lastChild;b=new CKEDITOR.dom.node(b)}a.getPosition(b)&CKEDITOR.POSITION_FOLLOWING&&(a=b);return{startNode:a,endNode:b}},getCommonAncestor:function(a,b){var c=this.startContainer,d=this.endContainer,c=c.equals(d)?a&&c.type==CKEDITOR.NODE_ELEMENT&&this.startOffset==this.endOffset-1?c.getChild(this.startOffset):c:c.getCommonAncestor(d);return b&&!c.is?c.getParent():
+c},optimize:function(){var a=this.startContainer,b=this.startOffset;a.type!=CKEDITOR.NODE_ELEMENT&&(b?b>=a.getLength()&&this.setStartAfter(a):this.setStartBefore(a));a=this.endContainer;b=this.endOffset;a.type!=CKEDITOR.NODE_ELEMENT&&(b?b>=a.getLength()&&this.setEndAfter(a):this.setEndBefore(a))},optimizeBookmark:function(){var a=this.startContainer,b=this.endContainer;a.is&&a.is("span")&&a.data("cke-bookmark")&&this.setStartAt(a,CKEDITOR.POSITION_BEFORE_START);b&&b.is&&b.is("span")&&b.data("cke-bookmark")&&
+this.setEndAt(b,CKEDITOR.POSITION_AFTER_END)},trim:function(a,b){var c=this.startContainer,d=this.startOffset,e=this.collapsed;if((!a||e)&&c&&c.type==CKEDITOR.NODE_TEXT){if(d)if(d>=c.getLength())d=c.getIndex()+1,c=c.getParent();else{var n=c.split(d),d=c.getIndex()+1,c=c.getParent();this.startContainer.equals(this.endContainer)?this.setEnd(n,this.endOffset-this.startOffset):c.equals(this.endContainer)&&(this.endOffset+=1)}else d=c.getIndex(),c=c.getParent();this.setStart(c,d);if(e){this.collapse(!0);
+return}}c=this.endContainer;d=this.endOffset;b||e||!c||c.type!=CKEDITOR.NODE_TEXT||(d?(d>=c.getLength()||c.split(d),d=c.getIndex()+1):d=c.getIndex(),c=c.getParent(),this.setEnd(c,d))},enlarge:function(a,b){function c(a){return a&&a.type==CKEDITOR.NODE_ELEMENT&&a.hasAttribute("contenteditable")?null:a}var d=new RegExp(/[^\s\ufeff]/);switch(a){case CKEDITOR.ENLARGE_INLINE:var e=1;case CKEDITOR.ENLARGE_ELEMENT:var n=function(a,b){var c=new CKEDITOR.dom.range(h);c.setStart(a,b);c.setEndAt(h,CKEDITOR.POSITION_BEFORE_END);
+var c=new CKEDITOR.dom.walker(c),g;for(c.guard=function(a){return!(a.type==CKEDITOR.NODE_ELEMENT&&a.isBlockBoundary())};g=c.next();){if(g.type!=CKEDITOR.NODE_TEXT)return!1;G=g!=a?g.getText():g.substring(b);if(d.test(G))return!1}return!0};if(this.collapsed)break;var f=this.getCommonAncestor(),h=this.root,k,u,l,p,m,D=!1,r,G;r=this.startContainer;var B=this.startOffset;r.type==CKEDITOR.NODE_TEXT?(B&&(r=!CKEDITOR.tools.trim(r.substring(0,B)).length&&r,D=!!r),r&&((p=r.getPrevious())||(l=r.getParent()))):
+(B&&(p=r.getChild(B-1)||r.getLast()),p||(l=r));for(l=c(l);l||p;){if(l&&!p){!m&&l.equals(f)&&(m=!0);if(e?l.isBlockBoundary():!h.contains(l))break;D&&"inline"==l.getComputedStyle("display")||(D=!1,m?k=l:this.setStartBefore(l));p=l.getPrevious()}for(;p;)if(r=!1,p.type==CKEDITOR.NODE_COMMENT)p=p.getPrevious();else{if(p.type==CKEDITOR.NODE_TEXT)G=p.getText(),d.test(G)&&(p=null),r=/[\s\ufeff]$/.test(G);else if((p.$.offsetWidth>(CKEDITOR.env.webkit?1:0)||b&&p.is("br"))&&!p.data("cke-bookmark"))if(D&&CKEDITOR.dtd.$removeEmpty[p.getName()]){G=
+p.getText();if(d.test(G))p=null;else for(var B=p.$.getElementsByTagName("*"),t=0,q;q=B[t++];)if(!CKEDITOR.dtd.$removeEmpty[q.nodeName.toLowerCase()]){p=null;break}p&&(r=!!G.length)}else p=null;r&&(D?m?k=l:l&&this.setStartBefore(l):D=!0);if(p){r=p.getPrevious();if(!l&&!r){l=p;p=null;break}p=r}else l=null}l&&(l=c(l.getParent()))}r=this.endContainer;B=this.endOffset;l=p=null;m=D=!1;r.type==CKEDITOR.NODE_TEXT?CKEDITOR.tools.trim(r.substring(B)).length?D=!0:(D=!r.getLength(),B==r.getLength()?(p=r.getNext())||
+(l=r.getParent()):n(r,B)&&(l=r.getParent())):(p=r.getChild(B))||(l=r);for(;l||p;){if(l&&!p){!m&&l.equals(f)&&(m=!0);if(e?l.isBlockBoundary():!h.contains(l))break;D&&"inline"==l.getComputedStyle("display")||(D=!1,m?u=l:l&&this.setEndAfter(l));p=l.getNext()}for(;p;){r=!1;if(p.type==CKEDITOR.NODE_TEXT)G=p.getText(),n(p,0)||(p=null),r=/^[\s\ufeff]/.test(G);else if(p.type==CKEDITOR.NODE_ELEMENT){if((0=e.getLength()?d.setStartAfter(e):(d.setStartBefore(e),k=
+0):d.setStartBefore(e));n&&n.type==CKEDITOR.NODE_TEXT&&(h?h>=n.getLength()?d.setEndAfter(n):(d.setEndAfter(n),u=0):d.setEndBefore(n));var d=new CKEDITOR.dom.walker(d),l=CKEDITOR.dom.walker.bookmark();d.evaluator=function(b){return b.type==(a==CKEDITOR.SHRINK_ELEMENT?CKEDITOR.NODE_ELEMENT:CKEDITOR.NODE_TEXT)};var p;d.guard=function(b,d){if(l(b))return!0;if(a==CKEDITOR.SHRINK_ELEMENT&&b.type==CKEDITOR.NODE_TEXT||d&&b.equals(p)||!1===c&&b.type==CKEDITOR.NODE_ELEMENT&&b.isBlockBoundary()||b.type==CKEDITOR.NODE_ELEMENT&&
+b.hasAttribute("contenteditable"))return!1;d||b.type!=CKEDITOR.NODE_ELEMENT||(p=b);return!0};k&&(e=d[a==CKEDITOR.SHRINK_ELEMENT?"lastForward":"next"]())&&this.setStartAt(e,b?CKEDITOR.POSITION_AFTER_START:CKEDITOR.POSITION_BEFORE_START);u&&(d.reset(),(d=d[a==CKEDITOR.SHRINK_ELEMENT?"lastBackward":"previous"]())&&this.setEndAt(d,b?CKEDITOR.POSITION_BEFORE_END:CKEDITOR.POSITION_AFTER_END));return!(!k&&!u)}},insertNode:function(a){this.optimizeBookmark();this.trim(!1,!0);var b=this.startContainer,c=b.getChild(this.startOffset);
+c?a.insertBefore(c):b.append(a);a.getParent()&&a.getParent().equals(this.endContainer)&&this.endOffset++;this.setStartBefore(a)},moveToPosition:function(a,b){this.setStartAt(a,b);this.collapse(!0)},moveToRange:function(a){this.setStart(a.startContainer,a.startOffset);this.setEnd(a.endContainer,a.endOffset)},selectNodeContents:function(a){this.setStart(a,0);this.setEnd(a,a.type==CKEDITOR.NODE_TEXT?a.getLength():a.getChildCount())},setStart:function(b,c){b.type==CKEDITOR.NODE_ELEMENT&&CKEDITOR.dtd.$empty[b.getName()]&&
+(c=b.getIndex(),b=b.getParent());this._setStartContainer(b);this.startOffset=c;this.endContainer||(this._setEndContainer(b),this.endOffset=c);a(this)},setEnd:function(b,c){b.type==CKEDITOR.NODE_ELEMENT&&CKEDITOR.dtd.$empty[b.getName()]&&(c=b.getIndex()+1,b=b.getParent());this._setEndContainer(b);this.endOffset=c;this.startContainer||(this._setStartContainer(b),this.startOffset=c);a(this)},setStartAfter:function(a){this.setStart(a.getParent(),a.getIndex()+1)},setStartBefore:function(a){this.setStart(a.getParent(),
+a.getIndex())},setEndAfter:function(a){this.setEnd(a.getParent(),a.getIndex()+1)},setEndBefore:function(a){this.setEnd(a.getParent(),a.getIndex())},setStartAt:function(b,c){switch(c){case CKEDITOR.POSITION_AFTER_START:this.setStart(b,0);break;case CKEDITOR.POSITION_BEFORE_END:b.type==CKEDITOR.NODE_TEXT?this.setStart(b,b.getLength()):this.setStart(b,b.getChildCount());break;case CKEDITOR.POSITION_BEFORE_START:this.setStartBefore(b);break;case CKEDITOR.POSITION_AFTER_END:this.setStartAfter(b)}a(this)},
+setEndAt:function(b,c){switch(c){case CKEDITOR.POSITION_AFTER_START:this.setEnd(b,0);break;case CKEDITOR.POSITION_BEFORE_END:b.type==CKEDITOR.NODE_TEXT?this.setEnd(b,b.getLength()):this.setEnd(b,b.getChildCount());break;case CKEDITOR.POSITION_BEFORE_START:this.setEndBefore(b);break;case CKEDITOR.POSITION_AFTER_END:this.setEndAfter(b)}a(this)},fixBlock:function(a,b){var c=this.createBookmark(),d=this.document.createElement(b);this.collapse(a);this.enlarge(CKEDITOR.ENLARGE_BLOCK_CONTENTS);this.extractContents().appendTo(d);
+d.trim();this.insertNode(d);var e=d.getBogus();e&&e.remove();d.appendBogus();this.moveToBookmark(c);return d},splitBlock:function(a,b){var c=new CKEDITOR.dom.elementPath(this.startContainer,this.root),d=new CKEDITOR.dom.elementPath(this.endContainer,this.root),e=c.block,n=d.block,f=null;if(!c.blockLimit.equals(d.blockLimit))return null;"br"!=a&&(e||(e=this.fixBlock(!0,a),n=(new CKEDITOR.dom.elementPath(this.endContainer,this.root)).block),n||(n=this.fixBlock(!1,a)));c=e&&this.checkStartOfBlock();
+d=n&&this.checkEndOfBlock();this.deleteContents();e&&e.equals(n)&&(d?(f=new CKEDITOR.dom.elementPath(this.startContainer,this.root),this.moveToPosition(n,CKEDITOR.POSITION_AFTER_END),n=null):c?(f=new CKEDITOR.dom.elementPath(this.startContainer,this.root),this.moveToPosition(e,CKEDITOR.POSITION_BEFORE_START),e=null):(n=this.splitElement(e,b||!1),e.is("ul","ol")||e.appendBogus()));return{previousBlock:e,nextBlock:n,wasStartOfBlock:c,wasEndOfBlock:d,elementPath:f}},splitElement:function(a,b){if(!this.collapsed)return null;
+this.setEndAt(a,CKEDITOR.POSITION_BEFORE_END);var c=this.extractContents(!1,b||!1),d=a.clone(!1,b||!1);c.appendTo(d);d.insertAfter(a);this.moveToPosition(a,CKEDITOR.POSITION_AFTER_END);return d},removeEmptyBlocksAtEnd:function(){function a(d){return function(a){return b(a)||c(a)||a.type==CKEDITOR.NODE_ELEMENT&&a.isEmptyInlineRemoveable()||d.is("table")&&a.is("caption")?!1:!0}}var b=CKEDITOR.dom.walker.whitespaces(),c=CKEDITOR.dom.walker.bookmark(!1);return function(b){for(var c=this.createBookmark(),
+d=this[b?"endPath":"startPath"](),e=d.block||d.blockLimit,f;e&&!e.equals(d.root)&&!e.getFirst(a(e));)f=e.getParent(),this[b?"setEndAt":"setStartAt"](e,CKEDITOR.POSITION_AFTER_END),e.remove(1),e=f;this.moveToBookmark(c)}}(),startPath:function(){return new CKEDITOR.dom.elementPath(this.startContainer,this.root)},endPath:function(){return new CKEDITOR.dom.elementPath(this.endContainer,this.root)},checkBoundaryOfElement:function(a,b){var d=b==CKEDITOR.START,e=this.clone();e.collapse(d);e[d?"setStartAt":
+"setEndAt"](a,d?CKEDITOR.POSITION_AFTER_START:CKEDITOR.POSITION_BEFORE_END);e=new CKEDITOR.dom.walker(e);e.evaluator=c(d);return e[d?"checkBackward":"checkForward"]()},checkStartOfBlock:function(){var a=this.startContainer,c=this.startOffset;CKEDITOR.env.ie&&c&&a.type==CKEDITOR.NODE_TEXT&&(a=CKEDITOR.tools.ltrim(a.substring(0,c)),k.test(a)&&this.trim(0,1));this.trim();a=new CKEDITOR.dom.elementPath(this.startContainer,this.root);c=this.clone();c.collapse(!0);c.setStartAt(a.block||a.blockLimit,CKEDITOR.POSITION_AFTER_START);
+a=new CKEDITOR.dom.walker(c);a.evaluator=b();return a.checkBackward()},checkEndOfBlock:function(){var a=this.endContainer,c=this.endOffset;CKEDITOR.env.ie&&a.type==CKEDITOR.NODE_TEXT&&(a=CKEDITOR.tools.rtrim(a.substring(c)),k.test(a)&&this.trim(1,0));this.trim();a=new CKEDITOR.dom.elementPath(this.endContainer,this.root);c=this.clone();c.collapse(!1);c.setEndAt(a.block||a.blockLimit,CKEDITOR.POSITION_BEFORE_END);a=new CKEDITOR.dom.walker(c);a.evaluator=b();return a.checkForward()},getPreviousNode:function(a,
+b,c){var d=this.clone();d.collapse(1);d.setStartAt(c||this.root,CKEDITOR.POSITION_AFTER_START);c=new CKEDITOR.dom.walker(d);c.evaluator=a;c.guard=b;return c.previous()},getNextNode:function(a,b,c){var d=this.clone();d.collapse();d.setEndAt(c||this.root,CKEDITOR.POSITION_BEFORE_END);c=new CKEDITOR.dom.walker(d);c.evaluator=a;c.guard=b;return c.next()},checkReadOnly:function(){function a(b,c){for(;b;){if(b.type==CKEDITOR.NODE_ELEMENT){if("false"==b.getAttribute("contentEditable")&&!b.data("cke-editable"))return 0;
+if(b.is("html")||"true"==b.getAttribute("contentEditable")&&(b.contains(c)||b.equals(c)))break}b=b.getParent()}return 1}return function(){var b=this.startContainer,c=this.endContainer;return!(a(b,c)&&a(c,b))}}(),moveToElementEditablePosition:function(a,b){if(a.type==CKEDITOR.NODE_ELEMENT&&!a.isEditable(!1))return this.moveToPosition(a,b?CKEDITOR.POSITION_AFTER_END:CKEDITOR.POSITION_BEFORE_START),!0;for(var c=0;a;){if(a.type==CKEDITOR.NODE_TEXT){b&&this.endContainer&&this.checkEndOfBlock()&&k.test(a.getText())?
+this.moveToPosition(a,CKEDITOR.POSITION_BEFORE_START):this.moveToPosition(a,b?CKEDITOR.POSITION_AFTER_END:CKEDITOR.POSITION_BEFORE_START);c=1;break}if(a.type==CKEDITOR.NODE_ELEMENT)if(a.isEditable())this.moveToPosition(a,b?CKEDITOR.POSITION_BEFORE_END:CKEDITOR.POSITION_AFTER_START),c=1;else if(b&&a.is("br")&&this.endContainer&&this.checkEndOfBlock())this.moveToPosition(a,CKEDITOR.POSITION_BEFORE_START);else if("false"==a.getAttribute("contenteditable")&&a.is(CKEDITOR.dtd.$block))return this.setStartBefore(a),
+this.setEndAfter(a),!0;var d=a,e=c,n=void 0;d.type==CKEDITOR.NODE_ELEMENT&&d.isEditable(!1)&&(n=d[b?"getLast":"getFirst"](t));e||n||(n=d[b?"getPrevious":"getNext"](t));a=n}return!!c},moveToClosestEditablePosition:function(a,b){var c,d=0,e,n,f=[CKEDITOR.POSITION_AFTER_END,CKEDITOR.POSITION_BEFORE_START];a?(c=new CKEDITOR.dom.range(this.root),c.moveToPosition(a,f[b?0:1])):c=this.clone();if(a&&!a.is(CKEDITOR.dtd.$block))d=1;else if(e=c[b?"getNextEditableNode":"getPreviousEditableNode"]())d=1,(n=e.type==
+CKEDITOR.NODE_ELEMENT)&&e.is(CKEDITOR.dtd.$block)&&"false"==e.getAttribute("contenteditable")?(c.setStartAt(e,CKEDITOR.POSITION_BEFORE_START),c.setEndAt(e,CKEDITOR.POSITION_AFTER_END)):!CKEDITOR.env.needsBrFiller&&n&&e.is(CKEDITOR.dom.walker.validEmptyBlockContainers)?(c.setEnd(e,0),c.collapse()):c.moveToPosition(e,f[b?1:0]);d&&this.moveToRange(c);return!!d},moveToElementEditStart:function(a){return this.moveToElementEditablePosition(a)},moveToElementEditEnd:function(a){return this.moveToElementEditablePosition(a,
+!0)},getEnclosedNode:function(){var a=this.clone();a.optimize();if(a.startContainer.type!=CKEDITOR.NODE_ELEMENT||a.endContainer.type!=CKEDITOR.NODE_ELEMENT)return null;var a=new CKEDITOR.dom.walker(a),b=CKEDITOR.dom.walker.bookmark(!1,!0),c=CKEDITOR.dom.walker.whitespaces(!0);a.evaluator=function(a){return c(a)&&b(a)};var d=a.next();a.reset();return d&&d.equals(a.previous())?d:null},getTouchedStartNode:function(){var a=this.startContainer;return this.collapsed||a.type!=CKEDITOR.NODE_ELEMENT?a:a.getChild(this.startOffset)||
+a},getTouchedEndNode:function(){var a=this.endContainer;return this.collapsed||a.type!=CKEDITOR.NODE_ELEMENT?a:a.getChild(this.endOffset-1)||a},getNextEditableNode:e(),getPreviousEditableNode:e(1),scrollIntoView:function(){var a=new CKEDITOR.dom.element.createFromHtml("\x3cspan\x3e\x26nbsp;\x3c/span\x3e",this.document),b,c,d,e=this.clone();e.optimize();(d=e.startContainer.type==CKEDITOR.NODE_TEXT)?(c=e.startContainer.getText(),b=e.startContainer.split(e.startOffset),a.insertAfter(e.startContainer)):
+e.insertNode(a);a.scrollIntoView();d&&(e.startContainer.setText(c),b.remove());a.remove()},_setStartContainer:function(a){this.startContainer=a},_setEndContainer:function(a){this.endContainer=a}}})();CKEDITOR.POSITION_AFTER_START=1;CKEDITOR.POSITION_BEFORE_END=2;CKEDITOR.POSITION_BEFORE_START=3;CKEDITOR.POSITION_AFTER_END=4;CKEDITOR.ENLARGE_ELEMENT=1;CKEDITOR.ENLARGE_BLOCK_CONTENTS=2;CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS=3;CKEDITOR.ENLARGE_INLINE=4;CKEDITOR.START=1;CKEDITOR.END=2;
+CKEDITOR.SHRINK_ELEMENT=1;CKEDITOR.SHRINK_TEXT=2;"use strict";
+(function(){function a(a){1>arguments.length||(this.range=a,this.forceBrBreak=0,this.enlargeBr=1,this.enforceRealBlocks=0,this._||(this._={}))}function d(a){var b=[];a.forEach(function(a){if("true"==a.getAttribute("contenteditable"))return b.push(a),!1},CKEDITOR.NODE_ELEMENT,!0);return b}function b(a,c,e,f){a:{null==f&&(f=d(e));for(var h;h=f.shift();)if(h.getDtd().p){f={element:h,remaining:f};break a}f=null}if(!f)return 0;if((h=CKEDITOR.filter.instances[f.element.data("cke-filter")])&&!h.check(c))return b(a,
+c,e,f.remaining);c=new CKEDITOR.dom.range(f.element);c.selectNodeContents(f.element);c=c.createIterator();c.enlargeBr=a.enlargeBr;c.enforceRealBlocks=a.enforceRealBlocks;c.activeFilter=c.filter=h;a._.nestedEditable={element:f.element,container:e,remaining:f.remaining,iterator:c};return 1}function c(a,b,c){if(!b)return!1;a=a.clone();a.collapse(!c);return a.checkBoundaryOfElement(b,c?CKEDITOR.START:CKEDITOR.END)}var e=/^[\r\n\t ]+$/,f=CKEDITOR.dom.walker.bookmark(!1,!0),h=CKEDITOR.dom.walker.whitespaces(!0),
+k=function(a){return f(a)&&h(a)},q={dd:1,dt:1,li:1};a.prototype={getNextParagraph:function(a){var d,h,A,v,C;a=a||"p";if(this._.nestedEditable){if(d=this._.nestedEditable.iterator.getNextParagraph(a))return this.activeFilter=this._.nestedEditable.iterator.activeFilter,d;this.activeFilter=this.filter;if(b(this,a,this._.nestedEditable.container,this._.nestedEditable.remaining))return this.activeFilter=this._.nestedEditable.iterator.activeFilter,this._.nestedEditable.iterator.getNextParagraph(a);this._.nestedEditable=
+null}if(!this.range.root.getDtd()[a])return null;if(!this._.started){var n=this.range.clone();h=n.startPath();var y=n.endPath(),F=!n.collapsed&&c(n,h.block),w=!n.collapsed&&c(n,y.block,1);n.shrink(CKEDITOR.SHRINK_ELEMENT,!0);F&&n.setStartAt(h.block,CKEDITOR.POSITION_BEFORE_END);w&&n.setEndAt(y.block,CKEDITOR.POSITION_AFTER_START);h=n.endContainer.hasAscendant("pre",!0)||n.startContainer.hasAscendant("pre",!0);n.enlarge(this.forceBrBreak&&!h||!this.enlargeBr?CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS:CKEDITOR.ENLARGE_BLOCK_CONTENTS);
+n.collapsed||(h=new CKEDITOR.dom.walker(n.clone()),y=CKEDITOR.dom.walker.bookmark(!0,!0),h.evaluator=y,this._.nextNode=h.next(),h=new CKEDITOR.dom.walker(n.clone()),h.evaluator=y,h=h.previous(),this._.lastNode=h.getNextSourceNode(!0,null,n.root),this._.lastNode&&this._.lastNode.type==CKEDITOR.NODE_TEXT&&!CKEDITOR.tools.trim(this._.lastNode.getText())&&this._.lastNode.getParent().isBlockBoundary()&&(y=this.range.clone(),y.moveToPosition(this._.lastNode,CKEDITOR.POSITION_AFTER_END),y.checkEndOfBlock()&&
+(y=new CKEDITOR.dom.elementPath(y.endContainer,y.root),this._.lastNode=(y.block||y.blockLimit).getNextSourceNode(!0))),this._.lastNode&&n.root.contains(this._.lastNode)||(this._.lastNode=this._.docEndMarker=n.document.createText(""),this._.lastNode.insertAfter(h)),n=null);this._.started=1;h=n}y=this._.nextNode;n=this._.lastNode;for(this._.nextNode=null;y;){var F=0,w=y.hasAscendant("pre"),u=y.type!=CKEDITOR.NODE_ELEMENT,l=0;if(u)y.type==CKEDITOR.NODE_TEXT&&e.test(y.getText())&&(u=0);else{var p=y.getName();
+if(CKEDITOR.dtd.$block[p]&&"false"==y.getAttribute("contenteditable")){d=y;b(this,a,d);break}else if(y.isBlockBoundary(this.forceBrBreak&&!w&&{br:1})){if("br"==p)u=1;else if(!h&&!y.getChildCount()&&"hr"!=p){d=y;A=y.equals(n);break}h&&(h.setEndAt(y,CKEDITOR.POSITION_BEFORE_START),"br"!=p&&(this._.nextNode=y));F=1}else{if(y.getFirst()){h||(h=this.range.clone(),h.setStartAt(y,CKEDITOR.POSITION_BEFORE_START));y=y.getFirst();continue}u=1}}u&&!h&&(h=this.range.clone(),h.setStartAt(y,CKEDITOR.POSITION_BEFORE_START));
+A=(!F||u)&&y.equals(n);if(h&&!F)for(;!y.getNext(k)&&!A;){p=y.getParent();if(p.isBlockBoundary(this.forceBrBreak&&!w&&{br:1})){F=1;u=0;A||p.equals(n);h.setEndAt(p,CKEDITOR.POSITION_BEFORE_END);break}y=p;u=1;A=y.equals(n);l=1}u&&h.setEndAt(y,CKEDITOR.POSITION_AFTER_END);y=this._getNextSourceNode(y,l,n);if((A=!y)||F&&h)break}if(!d){if(!h)return this._.docEndMarker&&this._.docEndMarker.remove(),this._.nextNode=null;d=new CKEDITOR.dom.elementPath(h.startContainer,h.root);y=d.blockLimit;F={div:1,th:1,td:1};
+d=d.block;!d&&y&&!this.enforceRealBlocks&&F[y.getName()]&&h.checkStartOfBlock()&&h.checkEndOfBlock()&&!y.equals(h.root)?d=y:!d||this.enforceRealBlocks&&d.is(q)?(d=this.range.document.createElement(a),h.extractContents().appendTo(d),d.trim(),h.insertNode(d),v=C=!0):"li"!=d.getName()?h.checkStartOfBlock()&&h.checkEndOfBlock()||(d=d.clone(!1),h.extractContents().appendTo(d),d.trim(),C=h.splitBlock(),v=!C.wasStartOfBlock,C=!C.wasEndOfBlock,h.insertNode(d)):A||(this._.nextNode=d.equals(n)?null:this._getNextSourceNode(h.getBoundaryNodes().endNode,
+1,n))}v&&(v=d.getPrevious())&&v.type==CKEDITOR.NODE_ELEMENT&&("br"==v.getName()?v.remove():v.getLast()&&"br"==v.getLast().$.nodeName.toLowerCase()&&v.getLast().remove());C&&(v=d.getLast())&&v.type==CKEDITOR.NODE_ELEMENT&&"br"==v.getName()&&(!CKEDITOR.env.needsBrFiller||v.getPrevious(f)||v.getNext(f))&&v.remove();this._.nextNode||(this._.nextNode=A||d.equals(n)||!n?null:this._getNextSourceNode(d,1,n));return d},_getNextSourceNode:function(a,b,c){function d(a){return!(a.equals(c)||a.equals(e))}var e=
+this.range.root;for(a=a.getNextSourceNode(b,null,d);!f(a);)a=a.getNextSourceNode(b,null,d);return a}};CKEDITOR.dom.range.prototype.createIterator=function(){return new a(this)}})();
+CKEDITOR.command=function(a,d){this.uiItems=[];this.exec=function(b){if(this.state==CKEDITOR.TRISTATE_DISABLED||!this.checkAllowed())return!1;this.editorFocus&&a.focus();return!1===this.fire("exec")?!0:!1!==d.exec.call(this,a,b)};this.refresh=function(a,b){if(!this.readOnly&&a.readOnly)return!0;if(this.context&&!b.isContextFor(this.context)||!this.checkAllowed(!0))return this.disable(),!0;this.startDisabled||this.enable();this.modes&&!this.modes[a.mode]&&this.disable();return!1===this.fire("refresh",
+{editor:a,path:b})?!0:d.refresh&&!1!==d.refresh.apply(this,arguments)};var b;this.checkAllowed=function(c){return c||"boolean"!=typeof b?b=a.activeFilter.checkFeature(this):b};CKEDITOR.tools.extend(this,d,{modes:{wysiwyg:1},editorFocus:1,contextSensitive:!!d.context,state:CKEDITOR.TRISTATE_DISABLED});CKEDITOR.event.call(this)};
+CKEDITOR.command.prototype={enable:function(){this.state==CKEDITOR.TRISTATE_DISABLED&&this.checkAllowed()&&this.setState(this.preserveState&&"undefined"!=typeof this.previousState?this.previousState:CKEDITOR.TRISTATE_OFF)},disable:function(){this.setState(CKEDITOR.TRISTATE_DISABLED)},setState:function(a){if(this.state==a||a!=CKEDITOR.TRISTATE_DISABLED&&!this.checkAllowed())return!1;this.previousState=this.state;this.state=a;this.fire("state");return!0},toggleState:function(){this.state==CKEDITOR.TRISTATE_OFF?
+this.setState(CKEDITOR.TRISTATE_ON):this.state==CKEDITOR.TRISTATE_ON&&this.setState(CKEDITOR.TRISTATE_OFF)}};CKEDITOR.event.implementOn(CKEDITOR.command.prototype);CKEDITOR.ENTER_P=1;CKEDITOR.ENTER_BR=2;CKEDITOR.ENTER_DIV=3;
+CKEDITOR.config={customConfig:"config.js",autoUpdateElement:!0,language:"",defaultLanguage:"en",contentsLangDirection:"",enterMode:CKEDITOR.ENTER_P,forceEnterMode:!1,shiftEnterMode:CKEDITOR.ENTER_BR,docType:"\x3c!DOCTYPE html\x3e",bodyId:"",bodyClass:"",fullPage:!1,height:200,extraPlugins:"",removePlugins:"",protectedSource:[],tabIndex:0,width:"",baseFloatZIndex:1E4,blockedKeystrokes:[CKEDITOR.CTRL+66,CKEDITOR.CTRL+73,CKEDITOR.CTRL+85]};
+(function(){function a(a,b,c,d,l){var e,p;a=[];for(e in b){p=b[e];p="boolean"==typeof p?{}:"function"==typeof p?{match:p}:J(p);"$"!=e.charAt(0)&&(p.elements=e);c&&(p.featureName=c.toLowerCase());var m=p;m.elements=h(m.elements,/\s+/)||null;m.propertiesOnly=m.propertiesOnly||!0===m.elements;var r=/\s*,\s*/,n=void 0;for(n in S){m[n]=h(m[n],r)||null;var E=m,u=x[n],f=h(m[x[n]],r),D=m[n],g=[],G=!0,K=void 0;f?G=!1:f={};for(K in D)"!"==K.charAt(0)&&(K=K.slice(1),g.push(K),f[K]=!0,G=!1);for(;K=g.pop();)D[K]=
+D["!"+K],delete D["!"+K];E[u]=(G?!1:f)||null}m.match=m.match||null;d.push(p);a.push(p)}b=l.elements;l=l.generic;var k;c=0;for(d=a.length;c=--k&&(f&&CKEDITOR.document.getDocumentElement().removeStyle("cursor"),g(b))},A=function(b,c){a[b]=1;var e=d[b];delete d[b];for(var f=0;fCKEDITOR.env.version?f.$.onreadystatechange=function(){if("loaded"==f.$.readyState||"complete"==f.$.readyState)f.$.onreadystatechange=null,A(b,!0)}:(f.$.onload=function(){setTimeout(function(){A(b,!0)},0)},f.$.onerror=function(){A(b,!1)}));f.appendTo(CKEDITOR.document.getHead())}}};f&&CKEDITOR.document.getDocumentElement().setStyle("cursor","wait");for(var C=0;C]+)>)|(?:!--([\S|\s]*?)--\x3e)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))/g}};
+(function(){var a=/([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g,d={checked:1,compact:1,declare:1,defer:1,disabled:1,ismap:1,multiple:1,nohref:1,noresize:1,noshade:1,nowrap:1,readonly:1,selected:1};CKEDITOR.htmlParser.prototype={onTagOpen:function(){},onTagClose:function(){},onText:function(){},onCDATA:function(){},onComment:function(){},parse:function(b){for(var c,e,f=0,h;c=this._.htmlPartsRegex.exec(b);){e=c.index;if(e>f)if(f=b.substring(f,e),h)h.push(f);else this.onText(f);
+f=this._.htmlPartsRegex.lastIndex;if(e=c[1])if(e=e.toLowerCase(),h&&CKEDITOR.dtd.$cdata[e]&&(this.onCDATA(h.join("")),h=null),!h){this.onTagClose(e);continue}if(h)h.push(c[0]);else if(e=c[3]){if(e=e.toLowerCase(),!/="/.test(e)){var k={},q,t=c[4];c=!!c[5];if(t)for(;q=a.exec(t);){var g=q[1].toLowerCase();q=q[2]||q[3]||q[4]||"";k[g]=!q&&d[g]?g:CKEDITOR.tools.htmlDecodeAttr(q)}this.onTagOpen(e,k,c);!h&&CKEDITOR.dtd.$cdata[e]&&(h=[])}}else if(e=c[2])this.onComment(e)}if(b.length>f)this.onText(b.substring(f,
+b.length))}}})();
+CKEDITOR.htmlParser.basicWriter=CKEDITOR.tools.createClass({$:function(){this._={output:[]}},proto:{openTag:function(a){this._.output.push("\x3c",a)},openTagClose:function(a,d){d?this._.output.push(" /\x3e"):this._.output.push("\x3e")},attribute:function(a,d){"string"==typeof d&&(d=CKEDITOR.tools.htmlEncodeAttr(d));this._.output.push(" ",a,'\x3d"',d,'"')},closeTag:function(a){this._.output.push("\x3c/",a,"\x3e")},text:function(a){this._.output.push(a)},comment:function(a){this._.output.push("\x3c!--",a,
+"--\x3e")},write:function(a){this._.output.push(a)},reset:function(){this._.output=[];this._.indent=!1},getHtml:function(a){var d=this._.output.join("");a&&this.reset();return d}}});"use strict";
+(function(){CKEDITOR.htmlParser.node=function(){};CKEDITOR.htmlParser.node.prototype={remove:function(){var a=this.parent.children,d=CKEDITOR.tools.indexOf(a,this),b=this.previous,c=this.next;b&&(b.next=c);c&&(c.previous=b);a.splice(d,1);this.parent=null},replaceWith:function(a){var d=this.parent.children,b=CKEDITOR.tools.indexOf(d,this),c=a.previous=this.previous,e=a.next=this.next;c&&(c.next=a);e&&(e.previous=a);d[b]=a;a.parent=this.parent;this.parent=null},insertAfter:function(a){var d=a.parent.children,
+b=CKEDITOR.tools.indexOf(d,a),c=a.next;d.splice(b+1,0,this);this.next=a.next;this.previous=a;a.next=this;c&&(c.previous=this);this.parent=a.parent},insertBefore:function(a){var d=a.parent.children,b=CKEDITOR.tools.indexOf(d,a);d.splice(b,0,this);this.next=a;(this.previous=a.previous)&&(a.previous.next=this);a.previous=this;this.parent=a.parent},getAscendant:function(a){var d="function"==typeof a?a:"string"==typeof a?function(b){return b.name==a}:function(b){return b.name in a},b=this.parent;for(;b&&
+b.type==CKEDITOR.NODE_ELEMENT;){if(d(b))return b;b=b.parent}return null},wrapWith:function(a){this.replaceWith(a);a.add(this);return a},getIndex:function(){return CKEDITOR.tools.indexOf(this.parent.children,this)},getFilterContext:function(a){return a||{}}}})();"use strict";CKEDITOR.htmlParser.comment=function(a){this.value=a;this._={isBlockLike:!1}};
+CKEDITOR.htmlParser.comment.prototype=CKEDITOR.tools.extend(new CKEDITOR.htmlParser.node,{type:CKEDITOR.NODE_COMMENT,filter:function(a,d){var b=this.value;if(!(b=a.onComment(d,b,this)))return this.remove(),!1;if("string"!=typeof b)return this.replaceWith(b),!1;this.value=b;return!0},writeHtml:function(a,d){d&&this.filter(d);a.comment(this.value)}});"use strict";
+(function(){CKEDITOR.htmlParser.text=function(a){this.value=a;this._={isBlockLike:!1}};CKEDITOR.htmlParser.text.prototype=CKEDITOR.tools.extend(new CKEDITOR.htmlParser.node,{type:CKEDITOR.NODE_TEXT,filter:function(a,d){if(!(this.value=a.onText(d,this.value,this)))return this.remove(),!1},writeHtml:function(a,d){d&&this.filter(d);a.text(this.value)}})})();"use strict";
+(function(){CKEDITOR.htmlParser.cdata=function(a){this.value=a};CKEDITOR.htmlParser.cdata.prototype=CKEDITOR.tools.extend(new CKEDITOR.htmlParser.node,{type:CKEDITOR.NODE_TEXT,filter:function(){},writeHtml:function(a){a.write(this.value)}})})();"use strict";CKEDITOR.htmlParser.fragment=function(){this.children=[];this.parent=null;this._={isBlockLike:!0,hasInlineStarted:!1}};
+(function(){function a(a){return a.attributes["data-cke-survive"]?!1:"a"==a.name&&a.attributes.href||CKEDITOR.dtd.$removeEmpty[a.name]}var d=CKEDITOR.tools.extend({table:1,ul:1,ol:1,dl:1},CKEDITOR.dtd.table,CKEDITOR.dtd.ul,CKEDITOR.dtd.ol,CKEDITOR.dtd.dl),b={ol:1,ul:1},c=CKEDITOR.tools.extend({},{html:1},CKEDITOR.dtd.html,CKEDITOR.dtd.body,CKEDITOR.dtd.head,{style:1,script:1}),e={ul:"li",ol:"li",dl:"dd",table:"tbody",tbody:"tr",thead:"tr",tfoot:"tr",tr:"td"};CKEDITOR.htmlParser.fragment.fromHtml=
+function(f,h,k){function q(a){var b;if(0h;h++)if(f=d[h]){f=f.exec(a,c,this);if(!1===f)return null;if(f&&f!=c)return this.onNode(a,f);if(c.parent&&!c.name)break}return c},
+onNode:function(a,c){var d=c.type;return d==CKEDITOR.NODE_ELEMENT?this.onElement(a,c):d==CKEDITOR.NODE_TEXT?new CKEDITOR.htmlParser.text(this.onText(a,c.value)):d==CKEDITOR.NODE_COMMENT?new CKEDITOR.htmlParser.comment(this.onComment(a,c.value)):null},onAttribute:function(a,c,d,f){return(d=this.attributesRules[d])?d.exec(a,f,c,this):f}}});CKEDITOR.htmlParser.filterRulesGroup=a;a.prototype={add:function(a,c,d){this.rules.splice(this.findIndex(c),0,{value:a,priority:c,options:d})},addMany:function(a,
+c,d){for(var f=[this.findIndex(c),0],h=0,k=a.length;h /g,"\x26gt;")+"\x3c/textarea\x3e");return"\x3ccke:encoded\x3e"+encodeURIComponent(a)+"\x3c/cke:encoded\x3e"})}function z(a){return a.replace(S,function(a,b){return decodeURIComponent(b)})}function A(a){return a.replace(/\x3c!--(?!{cke_protected})[\s\S]+?--\x3e/g,
+function(a){return"\x3c!--"+F+"{C}"+encodeURIComponent(a).replace(/--/g,"%2D%2D")+"--\x3e"})}function v(a){return a.replace(/\x3c!--\{cke_protected\}\{C\}([\s\S]+?)--\x3e/g,function(a,b){return decodeURIComponent(b)})}function C(a,b){var c=b._.dataStore;return a.replace(/\x3c!--\{cke_protected\}([\s\S]+?)--\x3e/g,function(a,b){return decodeURIComponent(b)}).replace(/\{cke_protected_(\d+)\}/g,function(a,b){return c&&c[b]||""})}function n(a,b){var c=[],d=b.config.protectedSource,e=b._.dataStore||(b._.dataStore=
+{id:1}),l=/<\!--\{cke_temp(comment)?\}(\d*?)--\x3e/g,d=[/');
+
+ if (script) {
+ params.element.text('');
+ params.element.replaceWith((0, _common.$)(script).text(params.component.templateNodes[0] && params.component.templateNodes[0].nodeValue ? params.component.templateNodes[0].nodeValue : ''));
+ } else {
+ params.element.remove();
+ }
+ }
+ return _this;
+ }
+
+ return ScriptComponent;
+ }(_Abstract.AbstractComponent);
+
+ module.exports = (0, _Abstract.componentExportHelper)(ScriptComponent, 'ScriptComponent');
+
+/***/ },
+/* 73 */
+/*!**********************************!*\
+ !*** ./dev/Component/Select.jsx ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Translator = __webpack_require__(/*! Common/Translator */ 6);
+
+ var _Translator2 = _interopRequireDefault(_Translator);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ var _AbstractInput2 = __webpack_require__(/*! Component/AbstractInput */ 37);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var SelectComponent = function (_AbstractInput) {
+ _inherits(SelectComponent, _AbstractInput);
+
+ /**
+ * @param {Object} params
+ */
+
+ function SelectComponent(params) {
+ _classCallCheck(this, SelectComponent);
+
+ var _this = _possibleConstructorReturn(this, _AbstractInput.call(this, params));
+
+ _this.options = params.options || '';
+
+ _this.optionsText = params.optionsText || null;
+ _this.optionsValue = params.optionsValue || null;
+ _this.optionsCaption = params.optionsCaption || null;
+
+ if (_this.optionsCaption) {
+ _this.optionsCaption = _Translator2.default.i18n(_this.optionsCaption);
+ }
+
+ _this.defautOptionsAfterRender = _Utils2.default.defautOptionsAfterRender;
+ return _this;
+ }
+
+ return SelectComponent;
+ }(_AbstractInput2.AbstractInput);
+
+ module.exports = (0, _Abstract.componentExportHelper)(SelectComponent, 'SelectComponent');
+
+/***/ },
+/* 74 */
+/*!************************************!*\
+ !*** ./dev/Component/TextArea.jsx ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ var _AbstractInput2 = __webpack_require__(/*! Component/AbstractInput */ 37);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var TextAreaComponent = function (_AbstractInput) {
+ _inherits(TextAreaComponent, _AbstractInput);
+
+ /**
+ * @param {Object} params
+ */
+
+ function TextAreaComponent(params) {
+ _classCallCheck(this, TextAreaComponent);
+
+ var _this = _possibleConstructorReturn(this, _AbstractInput.call(this, params));
+
+ _this.rows = params.rows || 5;
+ _this.spellcheck = _Utils2.default.isUnd(params.spellcheck) ? false : !!params.spellcheck;
+ return _this;
+ }
+
+ return TextAreaComponent;
+ }(_AbstractInput2.AbstractInput);
+
+ module.exports = (0, _Abstract.componentExportHelper)(TextAreaComponent, 'TextAreaComponent');
+
+/***/ },
+/* 75 */
+/*!************************************!*\
+ !*** ./dev/Knoin/AbstractBoot.jsx ***!
+ \************************************/
+/***/ function(module, exports) {
+
+ "use strict";
+
+ exports.__esModule = true;
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var AbstractBoot = function () {
+ function AbstractBoot() {
+ _classCallCheck(this, AbstractBoot);
+ }
+
+ AbstractBoot.prototype.bootstart = function bootstart() {
+ // eslint-disable-line no-empty
+ };
+
+ return AbstractBoot;
+ }();
+
+ exports.AbstractBoot = AbstractBoot;
+ exports.default = AbstractBoot;
+
+/***/ },
+/* 76 */
+/*!************************************!*\
+ !*** ./dev/Stores/AbstractApp.jsx ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.AbstractAppStore = undefined;
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ var _Globals2 = _interopRequireDefault(_Globals);
+
+ var _Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var AbstractAppStore = function () {
+ function AbstractAppStore() {
+ _classCallCheck(this, AbstractAppStore);
+
+ this.allowLanguagesOnSettings = _ko2.default.observable(true);
+ this.allowLanguagesOnLogin = _ko2.default.observable(true);
+
+ this.interfaceAnimation = _ko2.default.observable(true);
+
+ this.interfaceAnimation.subscribe(function (bValue) {
+ var bAnim = _Globals2.default.bMobileDevice || !bValue;
+ _Globals2.default.$html.toggleClass('rl-anim', !bAnim).toggleClass('no-rl-anim', bAnim);
+ });
+
+ this.interfaceAnimation.valueHasMutated();
+
+ this.prem = _ko2.default.observable(false);
+ this.community = _ko2.default.observable(true);
+ }
+
+ AbstractAppStore.prototype.populate = function populate() {
+ this.allowLanguagesOnLogin(!!_Settings2.default.settingsGet('AllowLanguagesOnLogin'));
+ this.allowLanguagesOnSettings(!!_Settings2.default.settingsGet('AllowLanguagesOnSettings'));
+
+ this.interfaceAnimation(!!_Settings2.default.settingsGet('InterfaceAnimation'));
+
+ this.prem(!!_Settings2.default.settingsGet('PremType'));
+ this.community(!!_Settings2.default.settingsGet('Community'));
+ };
+
+ return AbstractAppStore;
+ }();
+
+ exports.AbstractAppStore = AbstractAppStore;
+ exports.default = AbstractAppStore;
+
+/***/ },
+/* 77 */
+/*!***************************!*\
+ !*** ./dev/bootstrap.jsx ***!
+ \***************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ exports.default = function (App) {
+
+ var window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Plugins = __webpack_require__(/*! Common/Plugins */ 23),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+ EmailModel = __webpack_require__(/*! Model/Email */ 30);
+
+ Globals.__APP__ = App;
+
+ Globals.$win.keydown(Utils.kill_CtrlA_CtrlS).unload(function () {
+ Globals.bUnload = true;
+ });
+
+ Globals.$html.addClass(Globals.bMobileDevice ? 'mobile' : 'no-mobile').on('click.dropdown.data-api', function () {
+ Utils.detectDropdownVisibility();
+ });
+
+ // export
+ /* eslint dot-notation: 0 */
+ window['rl'] = window['rl'] || {};
+ window['rl']['i18n'] = _.bind(Translator.i18n, Translator);
+
+ window['rl']['addHook'] = _.bind(Plugins.addHook, Plugins);
+ window['rl']['settingsGet'] = _.bind(Plugins.mainSettingsGet, Plugins);
+ window['rl']['createCommand'] = Utils.createCommand;
+
+ window['rl']['addSettingsViewModel'] = _.bind(Plugins.addSettingsViewModel, Plugins);
+
+ window['rl']['pluginRemoteRequest'] = _.bind(Plugins.remoteRequest, Plugins);
+ window['rl']['pluginSettingsGet'] = _.bind(Plugins.settingsGet, Plugins);
+
+ window['rl']['EmailModel'] = EmailModel;
+ window['rl']['Enums'] = Enums;
+
+ window['__APP_BOOT'] = function (fCall) {
+
+ $(_.delay(function () {
+
+ if (!$('#rl-check').is(':visible')) {
+ Globals.$html.addClass('no-css');
+ }
+
+ $('#rl-check').remove();
+
+ if (window['rainloopTEMPLATES'] && window['rainloopTEMPLATES'][0]) {
+ $('#rl-templates').html(window['rainloopTEMPLATES'][0]);
+
+ _.delay(function () {
+
+ App.bootstart();
+
+ Globals.$html.removeClass('no-js rl-booted-trigger').addClass('rl-booted');
+ }, 10);
+ } else {
+ fCall(false);
+ }
+
+ window['__APP_BOOT'] = null;
+ }, 10));
+ };
+ };
+
+/***/ },
+/* 78 */
+/*!************************************!*\
+ !*** external "window.Autolinker" ***!
+ \************************************/
+/***/ function(module, exports) {
+
+ module.exports = window.Autolinker;
+
+/***/ },
+/* 79 */
+/*!***********************************!*\
+ !*** external "window.JSEncrypt" ***!
+ \***********************************/
+/***/ function(module, exports) {
+
+ module.exports = window.JSEncrypt;
+
+/***/ },
+/* 80 */,
+/* 81 */
+/*!********************************!*\
+ !*** external "window.hasher" ***!
+ \********************************/
+/***/ function(module, exports) {
+
+ module.exports = window.hasher;
+
+/***/ },
+/* 82 */
+/*!********************************!*\
+ !*** external "window.moment" ***!
+ \********************************/
+/***/ function(module, exports) {
+
+ module.exports = window.moment;
+
+/***/ },
+/* 83 */
+/*!********************************************!*\
+ !*** external "window.rainloopProgressJs" ***!
+ \********************************************/
+/***/ function(module, exports) {
+
+ module.exports = window.rainloopProgressJs;
+
+/***/ },
+/* 84 */
+/*!*****************************!*\
+ !*** external "window.ssm" ***!
+ \*****************************/
+/***/ function(module, exports) {
+
+ module.exports = window.ssm;
+
+/***/ },
+/* 85 */,
+/* 86 */,
+/* 87 */,
+/* 88 */,
+/* 89 */
+/*!**********************************!*\
+ !*** ./dev/Stores/Admin/Core.js ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2)
+ ;
+
+ /**
+ * @constructor
+ */
+ function CoreAdminStore()
+ {
+ this.coreReal = ko.observable(true);
+ this.coreChannel = ko.observable('stable');
+ this.coreType = ko.observable('stable');
+ this.coreUpdatable = ko.observable(true);
+ this.coreAccess = ko.observable(true);
+ this.coreWarning = ko.observable(false);
+ this.coreChecking = ko.observable(false).extend({'throttle': 100});
+ this.coreUpdating = ko.observable(false).extend({'throttle': 100});
+ this.coreVersion = ko.observable('');
+ this.coreRemoteVersion = ko.observable('');
+ this.coreRemoteRelease = ko.observable('');
+ this.coreVersionCompare = ko.observable(-2);
+ }
+
+ module.exports = new CoreAdminStore();
+
+ }());
+
+
+/***/ },
+/* 90 */,
+/* 91 */,
+/* 92 */,
+/* 93 */
+/*!**********************************!*\
+ !*** ./dev/View/Popup/Domain.js ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ CapaAdminStore = __webpack_require__(/*! Stores/Admin/Capa */ 50),
+
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function DomainPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsDomain');
+
+ this.edit = ko.observable(false);
+ this.saving = ko.observable(false);
+ this.savingError = ko.observable('');
+ this.page = ko.observable('main');
+ this.sieveSettings = ko.observable(false);
+
+ this.testing = ko.observable(false);
+ this.testingDone = ko.observable(false);
+ this.testingImapError = ko.observable(false);
+ this.testingSieveError = ko.observable(false);
+ this.testingSmtpError = ko.observable(false);
+ this.testingImapErrorDesc = ko.observable('');
+ this.testingSieveErrorDesc = ko.observable('');
+ this.testingSmtpErrorDesc = ko.observable('');
+
+ this.testingImapError.subscribe(function (bValue) {
+ if (!bValue)
+ {
+ this.testingImapErrorDesc('');
+ }
+ }, this);
+
+ this.testingSieveError.subscribe(function (bValue) {
+ if (!bValue)
+ {
+ this.testingSieveErrorDesc('');
+ }
+ }, this);
+
+ this.testingSmtpError.subscribe(function (bValue) {
+ if (!bValue)
+ {
+ this.testingSmtpErrorDesc('');
+ }
+ }, this);
+
+ this.imapServerFocus = ko.observable(false);
+ this.sieveServerFocus = ko.observable(false);
+ this.smtpServerFocus = ko.observable(false);
+
+ this.name = ko.observable('');
+ this.name.focused = ko.observable(false);
+
+ this.imapServer = ko.observable('');
+ this.imapPort = ko.observable('' + Consts.IMAP_DEFAULT_PORT);
+ this.imapSecure = ko.observable(Enums.ServerSecure.None);
+ this.imapShortLogin = ko.observable(false);
+ this.useSieve = ko.observable(false);
+ this.sieveAllowRaw = ko.observable(false);
+ this.sieveServer = ko.observable('');
+ this.sievePort = ko.observable('' + Consts.SIEVE_DEFAULT_PORT);
+ this.sieveSecure = ko.observable(Enums.ServerSecure.None);
+ this.smtpServer = ko.observable('');
+ this.smtpPort = ko.observable('' + Consts.SMTP_DEFAULT_PORT);
+ this.smtpSecure = ko.observable(Enums.ServerSecure.None);
+ this.smtpShortLogin = ko.observable(false);
+ this.smtpAuth = ko.observable(true);
+ this.smtpPhpMail = ko.observable(false);
+ this.whiteList = ko.observable('');
+
+ this.enableSmartPorts = ko.observable(false);
+
+ this.allowSieve = ko.computed(function () {
+ return CapaAdminStore.filters() && CapaAdminStore.sieve();
+ }, this);
+
+ this.headerText = ko.computed(function () {
+ var sName = this.name();
+ return this.edit() ? Translator.i18n('POPUPS_DOMAIN/TITLE_EDIT_DOMAIN', {'NAME': sName}) :
+ ('' === sName ? Translator.i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN') :
+ Translator.i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN_WITH_NAME', {'NAME': sName}));
+ }, this);
+
+ this.domainDesc = ko.computed(function () {
+ var sName = this.name();
+ return !this.edit() && sName ? Translator.i18n('POPUPS_DOMAIN/NEW_DOMAIN_DESC', {'NAME': '*@' + sName}) : '';
+ }, this);
+
+ this.domainIsComputed = ko.computed(function () {
+
+ var
+ bPhpMail = this.smtpPhpMail(),
+ bAllowSieve = this.allowSieve(),
+ bUseSieve = this.useSieve()
+ ;
+
+ return '' !== this.name() &&
+ '' !== this.imapServer() &&
+ '' !== this.imapPort() &&
+ (bAllowSieve && bUseSieve ? ('' !== this.sieveServer() && '' !== this.sievePort()) : true) &&
+ (('' !== this.smtpServer() && '' !== this.smtpPort()) || bPhpMail);
+
+ }, this);
+
+ this.canBeTested = ko.computed(function () {
+ return !this.testing() && this.domainIsComputed();
+ }, this);
+
+ this.canBeSaved = ko.computed(function () {
+ return !this.saving() && this.domainIsComputed();
+ }, this);
+
+ this.createOrAddCommand = Utils.createCommand(this, function () {
+ this.saving(true);
+ Remote.createOrUpdateDomain(
+ _.bind(this.onDomainCreateOrSaveResponse, this),
+ !this.edit(),
+ this.name(),
+
+ this.imapServer(),
+ Utils.pInt(this.imapPort()),
+ this.imapSecure(),
+ this.imapShortLogin(),
+
+ this.useSieve(),
+ this.sieveAllowRaw(),
+ this.sieveServer(),
+ Utils.pInt(this.sievePort()),
+ this.sieveSecure(),
+
+ this.smtpServer(),
+ Utils.pInt(this.smtpPort()),
+ this.smtpSecure(),
+ this.smtpShortLogin(),
+ this.smtpAuth(),
+ this.smtpPhpMail(),
+
+ this.whiteList()
+ );
+ }, this.canBeSaved);
+
+ this.testConnectionCommand = Utils.createCommand(this, function () {
+
+ this.page('main');
+
+ this.testingDone(false);
+ this.testingImapError(false);
+ this.testingSieveError(false);
+ this.testingSmtpError(false);
+ this.testing(true);
+
+ Remote.testConnectionForDomain(
+ _.bind(this.onTestConnectionResponse, this),
+ this.name(),
+
+ this.imapServer(),
+ Utils.pInt(this.imapPort()),
+ this.imapSecure(),
+
+ this.useSieve(),
+ this.sieveServer(),
+ Utils.pInt(this.sievePort()),
+ this.sieveSecure(),
+
+ this.smtpServer(),
+ Utils.pInt(this.smtpPort()),
+ this.smtpSecure(),
+ this.smtpAuth(),
+ this.smtpPhpMail()
+ );
+ }, this.canBeTested);
+
+ this.whiteListCommand = Utils.createCommand(this, function () {
+ this.page('white-list');
+ });
+
+ this.backCommand = Utils.createCommand(this, function () {
+ this.page('main');
+ });
+
+ this.sieveCommand = Utils.createCommand(this, function () {
+ this.sieveSettings(!this.sieveSettings());
+ this.clearTesting();
+ });
+
+ this.page.subscribe(function () {
+ this.sieveSettings(false);
+ }, this);
+
+ // smart form improvements
+ this.imapServerFocus.subscribe(function (bValue) {
+ if (bValue && '' !== this.name() && '' === this.imapServer())
+ {
+ this.imapServer(this.name().replace(/[.]?[*][.]?/g, ''));
+ }
+ }, this);
+
+ this.sieveServerFocus.subscribe(function (bValue) {
+ if (bValue && '' !== this.imapServer() && '' === this.sieveServer())
+ {
+ this.sieveServer(this.imapServer());
+ }
+ }, this);
+
+ this.smtpServerFocus.subscribe(function (bValue) {
+ if (bValue && '' !== this.imapServer() && '' === this.smtpServer())
+ {
+ this.smtpServer(this.imapServer().replace(/imap/ig, 'smtp'));
+ }
+ }, this);
+
+ this.imapSecure.subscribe(function (sValue) {
+ if (this.enableSmartPorts())
+ {
+ var iPort = Utils.pInt(this.imapPort());
+ sValue = Utils.pString(sValue);
+ switch (sValue)
+ {
+ case '0':
+ if (993 === iPort)
+ {
+ this.imapPort('143');
+ }
+ break;
+ case '1':
+ if (143 === iPort)
+ {
+ this.imapPort('993');
+ }
+ break;
+ }
+ }
+ }, this);
+
+ this.smtpSecure.subscribe(function (sValue) {
+ if (this.enableSmartPorts())
+ {
+ var iPort = Utils.pInt(this.smtpPort());
+ sValue = Utils.pString(sValue);
+ switch (sValue)
+ {
+ case '0':
+ if (465 === iPort || 587 === iPort)
+ {
+ this.smtpPort('25');
+ }
+ break;
+ case '1':
+ if (25 === iPort || 587 === iPort)
+ {
+ this.smtpPort('465');
+ }
+ break;
+ case '2':
+ if (25 === iPort || 465 === iPort)
+ {
+ this.smtpPort('587');
+ }
+ break;
+ }
+ }
+ }, this);
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/Domain', 'PopupsDomainViewModel'], DomainPopupView);
+ _.extend(DomainPopupView.prototype, AbstractView.prototype);
+
+ DomainPopupView.prototype.onTestConnectionResponse = function (sResult, oData)
+ {
+ this.testing(false);
+ if (Enums.StorageResultType.Success === sResult && oData.Result)
+ {
+ var
+ bImap = false,
+ bSieve = false
+ ;
+
+ this.testingDone(true);
+ this.testingImapError(true !== oData.Result.Imap);
+ this.testingSieveError(true !== oData.Result.Sieve);
+ this.testingSmtpError(true !== oData.Result.Smtp);
+
+ if (this.testingImapError() && oData.Result.Imap)
+ {
+ bImap = true;
+ this.testingImapErrorDesc('');
+ this.testingImapErrorDesc(oData.Result.Imap);
+ }
+
+ if (this.testingSieveError() && oData.Result.Sieve)
+ {
+ bSieve = true;
+ this.testingSieveErrorDesc('');
+ this.testingSieveErrorDesc(oData.Result.Sieve);
+ }
+
+ if (this.testingSmtpError() && oData.Result.Smtp)
+ {
+ this.testingSmtpErrorDesc('');
+ this.testingSmtpErrorDesc(oData.Result.Smtp);
+ }
+
+ if (this.sieveSettings())
+ {
+ if (!bSieve && bImap)
+ {
+ this.sieveSettings(false);
+ }
+ }
+ else
+ {
+ if (bSieve && !bImap)
+ {
+ this.sieveSettings(true);
+ }
+ }
+ }
+ else
+ {
+ this.testingImapError(true);
+ this.testingSieveError(true);
+ this.testingSmtpError(true);
+ this.sieveSettings(false);
+ }
+ };
+
+ DomainPopupView.prototype.onDomainCreateOrSaveResponse = function (sResult, oData)
+ {
+ this.saving(false);
+ if (Enums.StorageResultType.Success === sResult && oData)
+ {
+ if (oData.Result)
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.reloadDomainList();
+ this.closeCommand();
+ }
+ else if (Enums.Notification.DomainAlreadyExists === oData.ErrorCode)
+ {
+ this.savingError(Translator.i18n('ERRORS/DOMAIN_ALREADY_EXISTS'));
+ }
+ }
+ else
+ {
+ this.savingError(Translator.i18n('ERRORS/UNKNOWN_ERROR'));
+ }
+ };
+
+ DomainPopupView.prototype.clearTesting = function ()
+ {
+ this.testing(false);
+ this.testingDone(false);
+ this.testingImapError(false);
+ this.testingSieveError(false);
+ this.testingSmtpError(false);
+ };
+
+ DomainPopupView.prototype.onHide = function ()
+ {
+ this.page('main');
+ this.sieveSettings(false);
+ };
+
+
+ DomainPopupView.prototype.onShow = function (oDomain)
+ {
+ this.saving(false);
+
+ this.page('main');
+ this.sieveSettings(false);
+
+ this.clearTesting();
+
+ this.clearForm();
+ if (oDomain)
+ {
+ this.enableSmartPorts(false);
+
+ this.edit(true);
+
+ this.name(Utils.trim(oDomain.Name));
+ this.imapServer(Utils.trim(oDomain.IncHost));
+ this.imapPort('' + Utils.pInt(oDomain.IncPort));
+ this.imapSecure(Utils.trim(oDomain.IncSecure));
+ this.imapShortLogin(!!oDomain.IncShortLogin);
+ this.useSieve(!!oDomain.UseSieve);
+ this.sieveAllowRaw(!!oDomain.SieveAllowRaw);
+ this.sieveServer(Utils.trim(oDomain.SieveHost));
+ this.sievePort('' + Utils.pInt(oDomain.SievePort));
+ this.sieveSecure(Utils.trim(oDomain.SieveSecure));
+ this.smtpServer(Utils.trim(oDomain.OutHost));
+ this.smtpPort('' + Utils.pInt(oDomain.OutPort));
+ this.smtpSecure(Utils.trim(oDomain.OutSecure));
+ this.smtpShortLogin(!!oDomain.OutShortLogin);
+ this.smtpAuth(!!oDomain.OutAuth);
+ this.smtpPhpMail(!!oDomain.OutUsePhpMail);
+ this.whiteList(Utils.trim(oDomain.WhiteList));
+
+ this.enableSmartPorts(true);
+ }
+ };
+
+ DomainPopupView.prototype.onShowWithDelay = function ()
+ {
+ if ('' === this.name() && !Globals.bMobile)
+ {
+ this.name.focused(true);
+ }
+ };
+
+ DomainPopupView.prototype.clearForm = function ()
+ {
+ this.edit(false);
+
+ this.page('main');
+ this.sieveSettings(false);
+
+ this.enableSmartPorts(false);
+
+ this.savingError('');
+
+ this.name('');
+ this.name.focused(false);
+
+ this.imapServer('');
+ this.imapPort('' + Consts.IMAP_DEFAULT_PORT);
+ this.imapSecure(Enums.ServerSecure.None);
+ this.imapShortLogin(false);
+
+ this.useSieve(false);
+ this.sieveAllowRaw(false);
+ this.sieveServer('');
+ this.sievePort('' + Consts.SIEVE_DEFAULT_PORT);
+ this.sieveSecure(Enums.ServerSecure.None);
+
+ this.smtpServer('');
+ this.smtpPort('' + Consts.SMTP_DEFAULT_PORT);
+ this.smtpSecure(Enums.ServerSecure.None);
+ this.smtpShortLogin(false);
+ this.smtpAuth(true);
+ this.smtpPhpMail(false);
+
+ this.whiteList('');
+ this.enableSmartPorts(true);
+ };
+
+ module.exports = DomainPopupView;
+
+ }());
+
+/***/ },
+/* 94 */,
+/* 95 */,
+/* 96 */,
+/* 97 */,
+/* 98 */,
+/* 99 */,
+/* 100 */,
+/* 101 */,
+/* 102 */,
+/* 103 */,
+/* 104 */,
+/* 105 */,
+/* 106 */,
+/* 107 */,
+/* 108 */,
+/* 109 */,
+/* 110 */,
+/* 111 */,
+/* 112 */,
+/* 113 */
+/*!***********************************!*\
+ !*** ./dev/Screen/Admin/Login.js ***!
+ \***********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ AbstractScreen = __webpack_require__(/*! Knoin/AbstractScreen */ 39)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractScreen
+ */
+ function LoginAdminScreen()
+ {
+ AbstractScreen.call(this, 'login', [
+ __webpack_require__(/*! View/Admin/Login */ 140)
+ ]);
+ }
+
+ _.extend(LoginAdminScreen.prototype, AbstractScreen.prototype);
+
+ LoginAdminScreen.prototype.onShow = function ()
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.setWindowTitle('');
+ };
+
+ module.exports = LoginAdminScreen;
+
+ }());
+
+/***/ },
+/* 114 */
+/*!**************************************!*\
+ !*** ./dev/Screen/Admin/Settings.js ***!
+ \**************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+
+ Plugins = __webpack_require__(/*! Common/Plugins */ 23),
+
+ AbstractSettings = __webpack_require__(/*! Screen/AbstractSettings */ 56)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractSettings
+ */
+ function SettingsAdminScreen()
+ {
+ AbstractSettings.call(this, [
+ __webpack_require__(/*! View/Admin/Settings/Menu */ 141),
+ __webpack_require__(/*! View/Admin/Settings/Pane */ 142)
+ ]);
+ }
+
+ _.extend(SettingsAdminScreen.prototype, AbstractSettings.prototype);
+
+ /**
+ * @param {Function=} fCallback
+ */
+ SettingsAdminScreen.prototype.setupSettings = function (fCallback)
+ {
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/General */ 122),
+ 'AdminSettingsGeneral', 'TABS_LABELS/LABEL_GENERAL_NAME', 'general', true);
+
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Login */ 123),
+ 'AdminSettingsLogin', 'TABS_LABELS/LABEL_LOGIN_NAME', 'login');
+
+ if (true)
+ {
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Branding */ 119),
+ 'AdminSettingsBranding', 'TABS_LABELS/LABEL_BRANDING_NAME', 'branding');
+ }
+ else
+ {
+ kn.addSettingsViewModel(require('Settings/Admin/Prem/Branding'),
+ 'AdminSettingsBranding', 'TABS_LABELS/LABEL_BRANDING_NAME', 'branding');
+ }
+
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Contacts */ 120),
+ 'AdminSettingsContacts', 'TABS_LABELS/LABEL_CONTACTS_NAME', 'contacts');
+
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Domains */ 121),
+ 'AdminSettingsDomains', 'TABS_LABELS/LABEL_DOMAINS_NAME', 'domains');
+
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Security */ 126),
+ 'AdminSettingsSecurity', 'TABS_LABELS/LABEL_SECURITY_NAME', 'security');
+
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Social */ 127),
+ 'AdminSettingsSocial', 'TABS_LABELS/LABEL_INTEGRATION_NAME', 'integrations');
+
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Plugins */ 125),
+ 'AdminSettingsPlugins', 'TABS_LABELS/LABEL_PLUGINS_NAME', 'plugins');
+
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Packages */ 124),
+ 'AdminSettingsPackages', 'TABS_LABELS/LABEL_PACKAGES_NAME', 'packages');
+
+ if (false)
+ {
+ kn.addSettingsViewModel(require('Settings/Admin/Prem/Licensing'),
+ 'AdminSettingsLicensing', 'TABS_LABELS/LABEL_LICENSING_NAME', 'licensing');
+ }
+
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/About */ 118),
+ 'AdminSettingsAbout', 'TABS_LABELS/LABEL_ABOUT_NAME', 'about');
+
+ Plugins.runSettingsViewModelHooks(true);
+
+ if (fCallback)
+ {
+ fCallback();
+ }
+ };
+
+ SettingsAdminScreen.prototype.onShow = function ()
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.setWindowTitle('');
+ };
+
+ module.exports = SettingsAdminScreen;
+
+ }());
+
+/***/ },
+/* 115 */,
+/* 116 */,
+/* 117 */,
+/* 118 */
+/*!*************************************!*\
+ !*** ./dev/Settings/Admin/About.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ CoreStore = __webpack_require__(/*! Stores/Admin/Core */ 89),
+ AppStore = __webpack_require__(/*! Stores/Admin/App */ 35)
+ ;
+
+ /**
+ * @constructor
+ */
+ function AboutAdminSettings()
+ {
+ this.version = ko.observable(Settings.appSettingsGet('version'));
+ this.access = ko.observable(!!Settings.settingsGet('CoreAccess'));
+ this.errorDesc = ko.observable('');
+
+ this.coreReal = CoreStore.coreReal;
+ this.coreChannel = CoreStore.coreChannel;
+ this.coreType = CoreStore.coreType;
+ this.coreUpdatable = CoreStore.coreUpdatable;
+ this.coreAccess = CoreStore.coreAccess;
+ this.coreChecking = CoreStore.coreChecking;
+ this.coreUpdating = CoreStore.coreUpdating;
+ this.coreWarning = CoreStore.coreWarning;
+ this.coreVersion = CoreStore.coreVersion;
+ this.coreRemoteVersion = CoreStore.coreRemoteVersion;
+ this.coreRemoteRelease = CoreStore.coreRemoteRelease;
+ this.coreVersionCompare = CoreStore.coreVersionCompare;
+
+ this.community = (true) || AppStore.community();
+
+ this.coreRemoteVersionHtmlDesc = ko.computed(function () {
+ Translator.trigger();
+ return Translator.i18n('TAB_ABOUT/HTML_NEW_VERSION', {'VERSION': this.coreRemoteVersion()});
+ }, this);
+
+ this.statusType = ko.computed(function () {
+
+ var
+ sType = '',
+ iVersionCompare = this.coreVersionCompare(),
+ bChecking = this.coreChecking(),
+ bUpdating = this.coreUpdating(),
+ bReal = this.coreReal()
+ ;
+
+ if (bChecking)
+ {
+ sType = 'checking';
+ }
+ else if (bUpdating)
+ {
+ sType = 'updating';
+ }
+ else if (bReal && 0 === iVersionCompare)
+ {
+ sType = 'up-to-date';
+ }
+ else if (bReal && -1 === iVersionCompare)
+ {
+ sType = 'available';
+ }
+ else if (!bReal)
+ {
+ sType = 'error';
+ this.errorDesc('Cannot access the repository at the moment.');
+ }
+
+ return sType;
+
+ }, this);
+ }
+
+ AboutAdminSettings.prototype.onBuild = function ()
+ {
+ if (this.access() && !this.community)
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.reloadCoreData();
+ }
+ };
+
+ AboutAdminSettings.prototype.updateCoreData = function ()
+ {
+ if (!this.coreUpdating() && !this.community)
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.updateCoreData();
+ }
+ };
+
+ module.exports = AboutAdminSettings;
+
+ }());
+
+/***/ },
+/* 119 */
+/*!****************************************!*\
+ !*** ./dev/Settings/Admin/Branding.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6)
+ ;
+
+ /**
+ * @constructor
+ */
+ function BrandingAdminSettings()
+ {
+ var
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ AppStore = __webpack_require__(/*! Stores/Admin/App */ 35)
+ ;
+
+ this.capa = AppStore.prem;
+
+ this.title = ko.observable(Settings.settingsGet('Title'));
+ this.title.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.loadingDesc = ko.observable(Settings.settingsGet('LoadingDescription'));
+ this.loadingDesc.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.faviconUrl = ko.observable(Settings.settingsGet('FaviconUrl'));
+ this.faviconUrl.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.loginLogo = ko.observable(Settings.settingsGet('LoginLogo') || '');
+ this.loginLogo.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.loginBackground = ko.observable(Settings.settingsGet('LoginBackground') || '');
+ this.loginBackground.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.userLogo = ko.observable(Settings.settingsGet('UserLogo') || '');
+ this.userLogo.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.userLogoMessage = ko.observable(Settings.settingsGet('UserLogoMessage') || '');
+ this.userLogoMessage.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.userIframeMessage = ko.observable(Settings.settingsGet('UserIframeMessage') || '');
+ this.userIframeMessage.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.userLogoTitle = ko.observable(Settings.settingsGet('UserLogoTitle') || '');
+ this.userLogoTitle.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.loginDescription = ko.observable(Settings.settingsGet('LoginDescription'));
+ this.loginDescription.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.loginCss = ko.observable(Settings.settingsGet('LoginCss'));
+ this.loginCss.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.userCss = ko.observable(Settings.settingsGet('UserCss'));
+ this.userCss.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.welcomePageUrl = ko.observable(Settings.settingsGet('WelcomePageUrl'));
+ this.welcomePageUrl.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.welcomePageDisplay = ko.observable(Settings.settingsGet('WelcomePageDisplay'));
+ this.welcomePageDisplay.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.welcomePageDisplay.options = ko.computed(function () {
+ Translator.trigger();
+ return [
+ {'optValue': 'none', 'optText': Translator.i18n('TAB_BRANDING/OPTION_WELCOME_PAGE_DISPLAY_NONE')},
+ {'optValue': 'once', 'optText': Translator.i18n('TAB_BRANDING/OPTION_WELCOME_PAGE_DISPLAY_ONCE')},
+ {'optValue': 'always', 'optText': Translator.i18n('TAB_BRANDING/OPTION_WELCOME_PAGE_DISPLAY_ALWAYS')}
+ ];
+ });
+
+ this.loginPowered = ko.observable(!!Settings.settingsGet('LoginPowered'));
+
+ this.community = (true) || AppStore.community();
+ }
+
+ BrandingAdminSettings.prototype.onBuild = function ()
+ {
+ var
+ self = this,
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ _.delay(function () {
+
+ var
+ f1 = Utils.settingsSaveHelperSimpleFunction(self.title.trigger, self),
+ f2 = Utils.settingsSaveHelperSimpleFunction(self.loadingDesc.trigger, self),
+ f3 = Utils.settingsSaveHelperSimpleFunction(self.faviconUrl.trigger, self)
+ ;
+
+ self.title.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f1, {
+ 'Title': Utils.trim(sValue)
+ });
+ });
+
+ self.loadingDesc.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f2, {
+ 'LoadingDescription': Utils.trim(sValue)
+ });
+ });
+
+ self.faviconUrl.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f3, {
+ 'FaviconUrl': Utils.trim(sValue)
+ });
+ });
+
+ }, 50);
+ };
+
+ module.exports = BrandingAdminSettings;
+
+ }());
+
+/***/ },
+/* 120 */
+/*!****************************************!*\
+ !*** ./dev/Settings/Admin/Contacts.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function ContactsAdminSettings()
+ {
+ var
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ this.defautOptionsAfterRender = Utils.defautOptionsAfterRender;
+ this.enableContacts = ko.observable(!!Settings.settingsGet('ContactsEnable'));
+ this.contactsSharing = ko.observable(!!Settings.settingsGet('ContactsSharing'));
+ this.contactsSync = ko.observable(!!Settings.settingsGet('ContactsSync'));
+
+ var
+ aTypes = ['sqlite', 'mysql', 'pgsql'],
+ aSupportedTypes = [],
+ getTypeName = function(sName) {
+ switch (sName)
+ {
+ case 'sqlite':
+ sName = 'SQLite';
+ break;
+ case 'mysql':
+ sName = 'MySQL';
+ break;
+ case 'pgsql':
+ sName = 'PostgreSQL';
+ break;
+ }
+
+ return sName;
+ }
+ ;
+
+ if (!!Settings.settingsGet('SQLiteIsSupported'))
+ {
+ aSupportedTypes.push('sqlite');
+ }
+ if (!!Settings.settingsGet('MySqlIsSupported'))
+ {
+ aSupportedTypes.push('mysql');
+ }
+ if (!!Settings.settingsGet('PostgreSqlIsSupported'))
+ {
+ aSupportedTypes.push('pgsql');
+ }
+
+ this.contactsSupported = 0 < aSupportedTypes.length;
+
+ this.contactsTypes = ko.observableArray([]);
+ this.contactsTypesOptions = this.contactsTypes.map(function (sValue) {
+ var bDisabled = -1 === Utils.inArray(sValue, aSupportedTypes);
+ return {
+ 'id': sValue,
+ 'name': getTypeName(sValue) + (bDisabled ? ' (' + Translator.i18n('HINTS/NOT_SUPPORTED') + ')' : ''),
+ 'disabled': bDisabled
+ };
+ });
+
+ this.contactsTypes(aTypes);
+ this.contactsType = ko.observable('');
+
+ this.mainContactsType = ko.computed({
+ 'owner': this,
+ 'read': this.contactsType,
+ 'write': function (sValue) {
+ if (sValue !== this.contactsType())
+ {
+ if (-1 < Utils.inArray(sValue, aSupportedTypes))
+ {
+ this.contactsType(sValue);
+ }
+ else if (0 < aSupportedTypes.length)
+ {
+ this.contactsType('');
+ }
+ }
+ else
+ {
+ this.contactsType.valueHasMutated();
+ }
+ }
+ }).extend({'notify': 'always'});
+
+ this.contactsType.subscribe(function () {
+ this.testContactsSuccess(false);
+ this.testContactsError(false);
+ this.testContactsErrorMessage('');
+ }, this);
+
+ this.pdoDsn = ko.observable(Settings.settingsGet('ContactsPdoDsn'));
+ this.pdoUser = ko.observable(Settings.settingsGet('ContactsPdoUser'));
+ this.pdoPassword = ko.observable(Settings.settingsGet('ContactsPdoPassword'));
+
+ this.pdoDsnTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.pdoUserTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.pdoPasswordTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.contactsTypeTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.testing = ko.observable(false);
+ this.testContactsSuccess = ko.observable(false);
+ this.testContactsError = ko.observable(false);
+ this.testContactsErrorMessage = ko.observable('');
+
+ this.testContactsCommand = Utils.createCommand(this, function () {
+
+ this.testContactsSuccess(false);
+ this.testContactsError(false);
+ this.testContactsErrorMessage('');
+ this.testing(true);
+
+ Remote.testContacts(this.onTestContactsResponse, {
+ 'ContactsPdoType': this.contactsType(),
+ 'ContactsPdoDsn': this.pdoDsn(),
+ 'ContactsPdoUser': this.pdoUser(),
+ 'ContactsPdoPassword': this.pdoPassword()
+ });
+
+ }, function () {
+ return '' !== this.pdoDsn() && '' !== this.pdoUser();
+ });
+
+ this.contactsType(Settings.settingsGet('ContactsPdoType'));
+
+ this.onTestContactsResponse = _.bind(this.onTestContactsResponse, this);
+ }
+
+ ContactsAdminSettings.prototype.onTestContactsResponse = function (sResult, oData)
+ {
+ this.testContactsSuccess(false);
+ this.testContactsError(false);
+ this.testContactsErrorMessage('');
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result.Result)
+ {
+ this.testContactsSuccess(true);
+ }
+ else
+ {
+ this.testContactsError(true);
+ if (oData && oData.Result)
+ {
+ this.testContactsErrorMessage(oData.Result.Message || '');
+ }
+ else
+ {
+ this.testContactsErrorMessage('');
+ }
+ }
+
+ this.testing(false);
+ };
+
+ ContactsAdminSettings.prototype.onShow = function ()
+ {
+ this.testContactsSuccess(false);
+ this.testContactsError(false);
+ this.testContactsErrorMessage('');
+ };
+
+ ContactsAdminSettings.prototype.onBuild = function ()
+ {
+ var
+ self = this,
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ _.delay(function () {
+
+ var
+ f1 = Utils.settingsSaveHelperSimpleFunction(self.pdoDsnTrigger, self),
+ f3 = Utils.settingsSaveHelperSimpleFunction(self.pdoUserTrigger, self),
+ f4 = Utils.settingsSaveHelperSimpleFunction(self.pdoPasswordTrigger, self),
+ f5 = Utils.settingsSaveHelperSimpleFunction(self.contactsTypeTrigger, self)
+ ;
+
+ self.enableContacts.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'ContactsEnable': bValue ? '1' : '0'
+ });
+ });
+
+ self.contactsSharing.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'ContactsSharing': bValue ? '1' : '0'
+ });
+ });
+
+ self.contactsSync.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'ContactsSync': bValue ? '1' : '0'
+ });
+ });
+
+ self.contactsType.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f5, {
+ 'ContactsPdoType': sValue
+ });
+ });
+
+ self.pdoDsn.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f1, {
+ 'ContactsPdoDsn': Utils.trim(sValue)
+ });
+ });
+
+ self.pdoUser.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f3, {
+ 'ContactsPdoUser': Utils.trim(sValue)
+ });
+ });
+
+ self.pdoPassword.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f4, {
+ 'ContactsPdoPassword': Utils.trim(sValue)
+ });
+ });
+
+ self.contactsType(Settings.settingsGet('ContactsPdoType'));
+
+ }, 50);
+ };
+
+ module.exports = ContactsAdminSettings;
+
+ }());
+
+/***/ },
+/* 121 */
+/*!***************************************!*\
+ !*** ./dev/Settings/Admin/Domains.js ***!
+ \***************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+
+ DomainStore = __webpack_require__(/*! Stores/Admin/Domain */ 57),
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ /**
+ * @constructor
+ */
+ function DomainsAdminSettings()
+ {
+ this.domains = DomainStore.domains;
+
+ this.visibility = ko.computed(function () {
+ return this.domains.loading() ? 'visible' : 'hidden';
+ }, this);
+
+ this.domainForDeletion = ko.observable(null).deleteAccessHelper();
+ }
+
+ DomainsAdminSettings.prototype.createDomain = function ()
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Domain */ 93));
+ };
+
+ DomainsAdminSettings.prototype.deleteDomain = function (oDomain)
+ {
+ this.domains.remove(oDomain);
+ Remote.domainDelete(_.bind(this.onDomainListChangeRequest, this), oDomain.name);
+ };
+
+ DomainsAdminSettings.prototype.disableDomain = function (oDomain)
+ {
+ oDomain.disabled(!oDomain.disabled());
+ Remote.domainDisable(_.bind(this.onDomainListChangeRequest, this), oDomain.name, oDomain.disabled());
+ };
+
+ DomainsAdminSettings.prototype.onBuild = function (oDom)
+ {
+ var self = this;
+ oDom
+ .on('click', '.b-admin-domains-list-table .e-item .e-action', function () {
+ var oDomainItem = ko.dataFor(this);
+ if (oDomainItem)
+ {
+ Remote.domain(_.bind(self.onDomainLoadRequest, self), oDomainItem.name);
+ }
+ })
+ ;
+
+ __webpack_require__(/*! App/Admin */ 22).default.reloadDomainList();
+ };
+
+ DomainsAdminSettings.prototype.onDomainLoadRequest = function (sResult, oData)
+ {
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Domain */ 93), [oData.Result]);
+ }
+ };
+
+ DomainsAdminSettings.prototype.onDomainListChangeRequest = function ()
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.reloadDomainList();
+ };
+
+ module.exports = DomainsAdminSettings;
+
+ }());
+
+/***/ },
+/* 122 */
+/*!***************************************!*\
+ !*** ./dev/Settings/Admin/General.js ***!
+ \***************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ ThemeStore = __webpack_require__(/*! Stores/Theme */ 42),
+ LanguageStore = __webpack_require__(/*! Stores/Language */ 40),
+ AppAdminStore = __webpack_require__(/*! Stores/Admin/App */ 35),
+ CapaAdminStore = __webpack_require__(/*! Stores/Admin/Capa */ 50),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function GeneralAdminSettings()
+ {
+ this.language = LanguageStore.language;
+ this.languages = LanguageStore.languages;
+ this.languageAdmin = LanguageStore.languageAdmin;
+ this.languagesAdmin = LanguageStore.languagesAdmin;
+
+ this.theme = ThemeStore.theme;
+ this.themes = ThemeStore.themes;
+
+ this.capaThemes = CapaAdminStore.themes;
+ this.capaUserBackground = CapaAdminStore.userBackground;
+ this.capaGravatar = CapaAdminStore.gravatar;
+ this.capaAdditionalAccounts = CapaAdminStore.additionalAccounts;
+ this.capaIdentities = CapaAdminStore.identities;
+ this.capaAttachmentThumbnails = CapaAdminStore.attachmentThumbnails;
+ this.capaTemplates = CapaAdminStore.templates;
+
+ this.allowLanguagesOnSettings = AppAdminStore.allowLanguagesOnSettings;
+ this.weakPassword = AppAdminStore.weakPassword;
+
+ this.mainAttachmentLimit = ko.observable(Utils.pInt(Settings.settingsGet('AttachmentLimit')) / (1024 * 1024)).extend({'posInterer': 25});
+ this.uploadData = Settings.settingsGet('PhpUploadSizes');
+ this.uploadDataDesc = this.uploadData && (this.uploadData['upload_max_filesize'] || this.uploadData['post_max_size']) ? [
+ this.uploadData['upload_max_filesize'] ? 'upload_max_filesize = ' + this.uploadData['upload_max_filesize'] + '; ' : '',
+ this.uploadData['post_max_size'] ? 'post_max_size = ' + this.uploadData['post_max_size'] : ''
+ ].join('') : '';
+
+ this.themesOptions = ko.computed(function () {
+ return _.map(this.themes(), function (sTheme) {
+ return {
+ 'optValue': sTheme,
+ 'optText': Utils.convertThemeName(sTheme)
+ };
+ });
+ }, this);
+
+ this.languageFullName = ko.computed(function () {
+ return Utils.convertLangName(this.language());
+ }, this);
+
+ this.languageAdminFullName = ko.computed(function () {
+ return Utils.convertLangName(this.languageAdmin());
+ }, this);
+
+ this.attachmentLimitTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.languageTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.languageAdminTrigger = ko.observable(Enums.SaveSettingsStep.Idle).extend({'throttle': 100});
+ this.themeTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+ }
+
+ GeneralAdminSettings.prototype.onBuild = function ()
+ {
+ var
+ self = this,
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ _.delay(function () {
+
+ var
+ f1 = Utils.settingsSaveHelperSimpleFunction(self.attachmentLimitTrigger, self),
+ f2 = Utils.settingsSaveHelperSimpleFunction(self.languageTrigger, self),
+ f3 = Utils.settingsSaveHelperSimpleFunction(self.themeTrigger, self),
+ fReloadLanguageHelper = function (iSaveSettingsStep) {
+ return function() {
+ self.languageAdminTrigger(iSaveSettingsStep);
+ _.delay(function () {
+ self.languageAdminTrigger(Enums.SaveSettingsStep.Idle);
+ }, 1000);
+ };
+ }
+ ;
+
+ self.mainAttachmentLimit.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f1, {
+ 'AttachmentLimit': Utils.pInt(sValue)
+ });
+ });
+
+ self.language.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f2, {
+ 'Language': Utils.trim(sValue)
+ });
+ });
+
+ self.languageAdmin.subscribe(function (sValue) {
+
+ self.languageAdminTrigger(Enums.SaveSettingsStep.Animate);
+
+ Translator.reload(true, sValue,
+ fReloadLanguageHelper(Enums.SaveSettingsStep.TrueResult),
+ fReloadLanguageHelper(Enums.SaveSettingsStep.FalseResult));
+
+ Remote.saveAdminConfig(null, {
+ 'LanguageAdmin': Utils.trim(sValue)
+ });
+ });
+
+ self.theme.subscribe(function (sValue) {
+
+ Utils.changeTheme(sValue, self.themeTrigger);
+
+ Remote.saveAdminConfig(f3, {
+ 'Theme': Utils.trim(sValue)
+ });
+ });
+
+ self.capaAdditionalAccounts.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'CapaAdditionalAccounts': bValue ? '1' : '0'
+ });
+ });
+
+ self.capaIdentities.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'CapaIdentities': bValue ? '1' : '0'
+ });
+ });
+
+ self.capaTemplates.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'CapaTemplates': bValue ? '1' : '0'
+ });
+ });
+
+ self.capaGravatar.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'CapaGravatar': bValue ? '1' : '0'
+ });
+ });
+
+ self.capaAttachmentThumbnails.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'CapaAttachmentThumbnails': bValue ? '1' : '0'
+ });
+ });
+
+ self.capaThemes.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'CapaThemes': bValue ? '1' : '0'
+ });
+ });
+
+ self.capaUserBackground.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'CapaUserBackground': bValue ? '1' : '0'
+ });
+ });
+
+ self.allowLanguagesOnSettings.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'AllowLanguagesOnSettings': bValue ? '1' : '0'
+ });
+ });
+
+ }, 50);
+ };
+
+ GeneralAdminSettings.prototype.selectLanguage = function ()
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Languages */ 44), [
+ this.language, this.languages(), LanguageStore.userLanguage()
+ ]);
+ };
+
+ GeneralAdminSettings.prototype.selectLanguageAdmin = function ()
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Languages */ 44), [
+ this.languageAdmin, this.languagesAdmin(), LanguageStore.userLanguageAdmin()
+ ]);
+ };
+
+ /**
+ * @return {string}
+ */
+ GeneralAdminSettings.prototype.phpInfoLink = function ()
+ {
+ return Links.phpInfo();
+ };
+
+ module.exports = GeneralAdminSettings;
+
+ }());
+
+/***/ },
+/* 123 */
+/*!*************************************!*\
+ !*** ./dev/Settings/Admin/Login.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ AppAdminStore = __webpack_require__(/*! Stores/Admin/App */ 35),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function LoginAdminSettings()
+ {
+ this.determineUserLanguage = AppAdminStore.determineUserLanguage;
+ this.determineUserDomain = AppAdminStore.determineUserDomain;
+
+ this.defaultDomain = ko.observable(Settings.settingsGet('LoginDefaultDomain'));
+
+ this.allowLanguagesOnLogin = AppAdminStore.allowLanguagesOnLogin;
+ this.defaultDomainTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.dummy = ko.observable(false);
+ }
+
+ LoginAdminSettings.prototype.onBuild = function ()
+ {
+ var
+ self = this,
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ _.delay(function () {
+
+ var f1 = Utils.settingsSaveHelperSimpleFunction(self.defaultDomainTrigger, self);
+
+ self.determineUserLanguage.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'DetermineUserLanguage': bValue ? '1' : '0'
+ });
+ });
+
+ self.determineUserDomain.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'DetermineUserDomain': bValue ? '1' : '0'
+ });
+ });
+
+ self.allowLanguagesOnLogin.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'AllowLanguagesOnLogin': bValue ? '1' : '0'
+ });
+ });
+
+ self.defaultDomain.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f1, {
+ 'LoginDefaultDomain': Utils.trim(sValue)
+ });
+ });
+
+ }, 50);
+ };
+
+ module.exports = LoginAdminSettings;
+
+ }());
+
+/***/ },
+/* 124 */
+/*!****************************************!*\
+ !*** ./dev/Settings/Admin/Packages.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ PackageStore = __webpack_require__(/*! Stores/Admin/Package */ 58),
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ /**
+ * @constructor
+ */
+ function PackagesAdminSettings()
+ {
+ this.packagesError = ko.observable('');
+
+ this.packages = PackageStore.packages;
+ this.packagesReal = PackageStore.packagesReal;
+ this.packagesMainUpdatable = PackageStore.packagesMainUpdatable;
+
+ this.packagesCurrent = this.packages.filter(function (oItem) {
+ return oItem && '' !== oItem['installed'] && !oItem['compare'];
+ });
+
+ this.packagesAvailableForUpdate = this.packages.filter(function (oItem) {
+ return oItem && '' !== oItem['installed'] && !!oItem['compare'];
+ });
+
+ this.packagesAvailableForInstallation = this.packages.filter(function (oItem) {
+ return oItem && '' === oItem['installed'];
+ });
+
+ this.visibility = ko.computed(function () {
+ return PackageStore.packages.loading() ? 'visible' : 'hidden';
+ }, this);
+ }
+
+ PackagesAdminSettings.prototype.onShow = function ()
+ {
+ this.packagesError('');
+ };
+
+ PackagesAdminSettings.prototype.onBuild = function ()
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.reloadPackagesList();
+ };
+
+ PackagesAdminSettings.prototype.requestHelper = function (oPackage, bInstall)
+ {
+ var self = this;
+ return function (sResult, oData) {
+
+ if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result)
+ {
+ if (oData && oData.ErrorCode)
+ {
+ self.packagesError(Translator.getNotification(oData.ErrorCode));
+ }
+ else
+ {
+ self.packagesError(Translator.getNotification(
+ bInstall ? Enums.Notification.CantInstallPackage : Enums.Notification.CantDeletePackage));
+ }
+ }
+
+ _.each(self.packages(), function (oItem) {
+ if (oItem && oPackage && oItem['loading']() && oPackage['file'] === oItem['file'])
+ {
+ oPackage['loading'](false);
+ oItem['loading'](false);
+ }
+ });
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result['Reload'])
+ {
+ window.location.reload();
+ }
+ else
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.reloadPackagesList();
+ }
+ };
+ };
+
+ PackagesAdminSettings.prototype.deletePackage = function (oPackage)
+ {
+ if (oPackage)
+ {
+ oPackage['loading'](true);
+ Remote.packageDelete(this.requestHelper(oPackage, false), oPackage);
+ }
+ };
+
+ PackagesAdminSettings.prototype.installPackage = function (oPackage)
+ {
+ if (oPackage)
+ {
+ oPackage['loading'](true);
+ Remote.packageInstall(this.requestHelper(oPackage, true), oPackage);
+ }
+ };
+
+ module.exports = PackagesAdminSettings;
+
+ }());
+
+/***/ },
+/* 125 */
+/*!***************************************!*\
+ !*** ./dev/Settings/Admin/Plugins.js ***!
+ \***************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+
+ AppStore = __webpack_require__(/*! Stores/Admin/App */ 35),
+ PluginStore = __webpack_require__(/*! Stores/Admin/Plugin */ 59),
+
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ /**
+ * @constructor
+ */
+ function PluginsAdminSettings()
+ {
+ this.enabledPlugins = ko.observable(!!Settings.settingsGet('EnabledPlugins'));
+
+ this.plugins = PluginStore.plugins;
+ this.pluginsError = PluginStore.plugins.error;
+
+ this.community = (true) || AppStore.community();
+
+ this.visibility = ko.computed(function () {
+ return PluginStore.plugins.loading() ? 'visible' : 'hidden';
+ }, this);
+
+ this.onPluginLoadRequest = _.bind(this.onPluginLoadRequest, this);
+ this.onPluginDisableRequest = _.bind(this.onPluginDisableRequest, this);
+ }
+
+ PluginsAdminSettings.prototype.disablePlugin = function (oPlugin)
+ {
+ oPlugin.disabled(!oPlugin.disabled());
+ Remote.pluginDisable(this.onPluginDisableRequest, oPlugin.name, oPlugin.disabled());
+ };
+
+ PluginsAdminSettings.prototype.configurePlugin = function (oPlugin)
+ {
+ Remote.plugin(this.onPluginLoadRequest, oPlugin.name);
+ };
+
+ PluginsAdminSettings.prototype.onBuild = function (oDom)
+ {
+ var self = this;
+
+ oDom
+ .on('click', '.e-item .configure-plugin-action', function () {
+ var oPlugin = ko.dataFor(this);
+ if (oPlugin)
+ {
+ self.configurePlugin(oPlugin);
+ }
+ })
+ .on('click', '.e-item .disabled-plugin', function () {
+ var oPlugin = ko.dataFor(this);
+ if (oPlugin)
+ {
+ self.disablePlugin(oPlugin);
+ }
+ })
+ ;
+
+ this.enabledPlugins.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'EnabledPlugins': bValue ? '1' : '0'
+ });
+ });
+ };
+
+ PluginsAdminSettings.prototype.onShow = function ()
+ {
+ PluginStore.plugins.error('');
+ __webpack_require__(/*! App/Admin */ 22).default.reloadPluginList();
+ };
+
+ PluginsAdminSettings.prototype.onPluginLoadRequest = function (sResult, oData)
+ {
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Plugin */ 149), [oData.Result]);
+ }
+ };
+
+ PluginsAdminSettings.prototype.onPluginDisableRequest = function (sResult, oData)
+ {
+ if (Enums.StorageResultType.Success === sResult && oData)
+ {
+ if (!oData.Result && oData.ErrorCode)
+ {
+ if (Enums.Notification.UnsupportedPluginPackage === oData.ErrorCode && oData.ErrorMessage && '' !== oData.ErrorMessage)
+ {
+ PluginStore.plugins.error(oData.ErrorMessage);
+ }
+ else
+ {
+ PluginStore.plugins.error(Translator.getNotification(oData.ErrorCode));
+ }
+ }
+ }
+
+ __webpack_require__(/*! App/Admin */ 22).default.reloadPluginList();
+ };
+
+ module.exports = PluginsAdminSettings;
+
+ }());
+
+/***/ },
+/* 126 */
+/*!****************************************!*\
+ !*** ./dev/Settings/Admin/Security.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+
+ AppAdminStore = __webpack_require__(/*! Stores/Admin/App */ 35),
+ CapaAdminStore = __webpack_require__(/*! Stores/Admin/Capa */ 50),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ /**
+ * @constructor
+ */
+ function SecurityAdminSettings()
+ {
+ this.useLocalProxyForExternalImages = AppAdminStore.useLocalProxyForExternalImages;
+
+ this.weakPassword = AppAdminStore.weakPassword;
+
+ this.capaOpenPGP = CapaAdminStore.openPGP;
+
+ this.capaTwoFactorAuth = CapaAdminStore.twoFactorAuth;
+ this.capaTwoFactorAuthForce = CapaAdminStore.twoFactorAuthForce;
+
+ this.capaTwoFactorAuth.subscribe(function (bValue) {
+ if (!bValue)
+ {
+ this.capaTwoFactorAuthForce(false);
+ }
+ }, this);
+
+ this.verifySslCertificate = ko.observable(!!Settings.settingsGet('VerifySslCertificate'));
+ this.allowSelfSigned = ko.observable(!!Settings.settingsGet('AllowSelfSigned'));
+
+ this.verifySslCertificate.subscribe(function (bValue) {
+ if (!bValue)
+ {
+ this.allowSelfSigned(true);
+ }
+ }, this);
+
+ this.adminLogin = ko.observable(Settings.settingsGet('AdminLogin'));
+ this.adminLoginError = ko.observable(false);
+ this.adminPassword = ko.observable('');
+ this.adminPasswordNew = ko.observable('');
+ this.adminPasswordNew2 = ko.observable('');
+ this.adminPasswordNewError = ko.observable(false);
+
+ this.adminPasswordUpdateError = ko.observable(false);
+ this.adminPasswordUpdateSuccess = ko.observable(false);
+
+ this.adminPassword.subscribe(function () {
+ this.adminPasswordUpdateError(false);
+ this.adminPasswordUpdateSuccess(false);
+ }, this);
+
+ this.adminLogin.subscribe(function () {
+ this.adminLoginError(false);
+ }, this);
+
+ this.adminPasswordNew.subscribe(function () {
+ this.adminPasswordUpdateError(false);
+ this.adminPasswordUpdateSuccess(false);
+ this.adminPasswordNewError(false);
+ }, this);
+
+ this.adminPasswordNew2.subscribe(function () {
+ this.adminPasswordUpdateError(false);
+ this.adminPasswordUpdateSuccess(false);
+ this.adminPasswordNewError(false);
+ }, this);
+
+ this.saveNewAdminPasswordCommand = Utils.createCommand(this, function () {
+
+ if ('' === Utils.trim(this.adminLogin()))
+ {
+ this.adminLoginError(true);
+ return false;
+ }
+
+ if (this.adminPasswordNew() !== this.adminPasswordNew2())
+ {
+ this.adminPasswordNewError(true);
+ return false;
+ }
+
+ this.adminPasswordUpdateError(false);
+ this.adminPasswordUpdateSuccess(false);
+
+ Remote.saveNewAdminPassword(this.onNewAdminPasswordResponse, {
+ 'Login': this.adminLogin(),
+ 'Password': this.adminPassword(),
+ 'NewPassword': this.adminPasswordNew()
+ });
+
+ }, function () {
+ return '' !== Utils.trim(this.adminLogin()) && '' !== this.adminPassword();
+ });
+
+ this.onNewAdminPasswordResponse = _.bind(this.onNewAdminPasswordResponse, this);
+ }
+
+ SecurityAdminSettings.prototype.onNewAdminPasswordResponse = function (sResult, oData)
+ {
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ this.adminPassword('');
+ this.adminPasswordNew('');
+ this.adminPasswordNew2('');
+
+ this.adminPasswordUpdateSuccess(true);
+
+ this.weakPassword(!!oData.Result.Weak);
+ }
+ else
+ {
+ this.adminPasswordUpdateError(true);
+ }
+ };
+
+ SecurityAdminSettings.prototype.onBuild = function ()
+ {
+ this.capaOpenPGP.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'CapaOpenPGP': bValue ? '1' : '0'
+ });
+ });
+
+ this.capaTwoFactorAuth.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'CapaTwoFactorAuth': bValue ? '1' : '0'
+ });
+ });
+
+ this.capaTwoFactorAuthForce.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'CapaTwoFactorAuthForce': bValue ? '1' : '0'
+ });
+ });
+
+ this.useLocalProxyForExternalImages.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'UseLocalProxyForExternalImages': bValue ? '1' : '0'
+ });
+ });
+
+ this.verifySslCertificate.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'VerifySslCertificate': bValue ? '1' : '0'
+ });
+ });
+
+ this.allowSelfSigned.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'AllowSelfSigned': bValue ? '1' : '0'
+ });
+ });
+ };
+
+ SecurityAdminSettings.prototype.onHide = function ()
+ {
+ this.adminPassword('');
+ this.adminPasswordNew('');
+ this.adminPasswordNew2('');
+ };
+
+ /**
+ * @return {string}
+ */
+ SecurityAdminSettings.prototype.phpInfoLink = function ()
+ {
+ return Links.phpInfo();
+ };
+
+ module.exports = SecurityAdminSettings;
+
+ }());
+
+
+/***/ },
+/* 127 */
+/*!**************************************!*\
+ !*** ./dev/Settings/Admin/Social.js ***!
+ \**************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1)
+ ;
+
+ /**
+ * @constructor
+ */
+ function SocialAdminSettings()
+ {
+ var SocialStore = __webpack_require__(/*! Stores/Social */ 34);
+
+ this.googleEnable = SocialStore.google.enabled;
+ this.googleEnableAuth = SocialStore.google.capa.auth;
+ this.googleEnableAuthFast = SocialStore.google.capa.authFast;
+ this.googleEnableDrive = SocialStore.google.capa.drive;
+ this.googleEnablePreview = SocialStore.google.capa.preview;
+
+ this.googleEnableRequireClientSettings = SocialStore.google.require.clientSettings;
+ this.googleEnableRequireApiKey = SocialStore.google.require.apiKeySettings;
+
+ this.googleClientID = SocialStore.google.clientID;
+ this.googleClientSecret = SocialStore.google.clientSecret;
+ this.googleApiKey = SocialStore.google.apiKey;
+
+ this.googleTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.googleTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.googleTrigger3 = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.facebookSupported = SocialStore.facebook.supported;
+ this.facebookEnable = SocialStore.facebook.enabled;
+ this.facebookAppID = SocialStore.facebook.appID;
+ this.facebookAppSecret = SocialStore.facebook.appSecret;
+
+ this.facebookTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.facebookTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.twitterEnable = SocialStore.twitter.enabled;
+ this.twitterConsumerKey = SocialStore.twitter.consumerKey;
+ this.twitterConsumerSecret = SocialStore.twitter.consumerSecret;
+
+ this.twitterTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.twitterTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.dropboxEnable = SocialStore.dropbox.enabled;
+ this.dropboxApiKey = SocialStore.dropbox.apiKey;
+
+ this.dropboxTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
+ }
+
+ SocialAdminSettings.prototype.onBuild = function ()
+ {
+ var
+ self = this,
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ _.delay(function () {
+
+ var
+ f1 = Utils.settingsSaveHelperSimpleFunction(self.facebookTrigger1, self),
+ f2 = Utils.settingsSaveHelperSimpleFunction(self.facebookTrigger2, self),
+ f3 = Utils.settingsSaveHelperSimpleFunction(self.twitterTrigger1, self),
+ f4 = Utils.settingsSaveHelperSimpleFunction(self.twitterTrigger2, self),
+ f5 = Utils.settingsSaveHelperSimpleFunction(self.googleTrigger1, self),
+ f6 = Utils.settingsSaveHelperSimpleFunction(self.googleTrigger2, self),
+ f7 = Utils.settingsSaveHelperSimpleFunction(self.googleTrigger3, self),
+ f8 = Utils.settingsSaveHelperSimpleFunction(self.dropboxTrigger1, self)
+ ;
+
+ self.facebookEnable.subscribe(function (bValue) {
+ if (self.facebookSupported())
+ {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'FacebookEnable': bValue ? '1' : '0'
+ });
+ }
+ });
+
+ self.facebookAppID.subscribe(function (sValue) {
+ if (self.facebookSupported())
+ {
+ Remote.saveAdminConfig(f1, {
+ 'FacebookAppID': Utils.trim(sValue)
+ });
+ }
+ });
+
+ self.facebookAppSecret.subscribe(function (sValue) {
+ if (self.facebookSupported())
+ {
+ Remote.saveAdminConfig(f2, {
+ 'FacebookAppSecret': Utils.trim(sValue)
+ });
+ }
+ });
+
+ self.twitterEnable.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'TwitterEnable': bValue ? '1' : '0'
+ });
+ });
+
+ self.twitterConsumerKey.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f3, {
+ 'TwitterConsumerKey': Utils.trim(sValue)
+ });
+ });
+
+ self.twitterConsumerSecret.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f4, {
+ 'TwitterConsumerSecret': Utils.trim(sValue)
+ });
+ });
+
+ self.googleEnable.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'GoogleEnable': bValue ? '1' : '0'
+ });
+ });
+
+ self.googleEnableAuth.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'GoogleEnableAuth': bValue ? '1' : '0'
+ });
+ });
+
+ self.googleEnableDrive.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'GoogleEnableDrive': bValue ? '1' : '0'
+ });
+ });
+
+ self.googleEnablePreview.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'GoogleEnablePreview': bValue ? '1' : '0'
+ });
+ });
+
+ self.googleClientID.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f5, {
+ 'GoogleClientID': Utils.trim(sValue)
+ });
+ });
+
+ self.googleClientSecret.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f6, {
+ 'GoogleClientSecret': Utils.trim(sValue)
+ });
+ });
+
+ self.googleApiKey.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f7, {
+ 'GoogleApiKey': Utils.trim(sValue)
+ });
+ });
+
+ self.dropboxEnable.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'DropboxEnable': bValue ? '1' : '0'
+ });
+ });
+
+ self.dropboxApiKey.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f8, {
+ 'DropboxApiKey': Utils.trim(sValue)
+ });
+ });
+
+ }, 50);
+ };
+
+ module.exports = SocialAdminSettings;
+
+ }());
+
+/***/ },
+/* 128 */,
+/* 129 */,
+/* 130 */,
+/* 131 */,
+/* 132 */,
+/* 133 */,
+/* 134 */,
+/* 135 */,
+/* 136 */,
+/* 137 */,
+/* 138 */,
+/* 139 */
+/*!*************************************!*\
+ !*** ./dev/Stores/Admin/License.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2)
+ ;
+
+ /**
+ * @constructor
+ */
+ function LicenseAdminStore()
+ {
+ this.licensing = ko.observable(false);
+ this.licensingProcess = ko.observable(false);
+ this.licenseValid = ko.observable(false);
+ this.licenseExpired = ko.observable(0);
+ this.licenseError = ko.observable('');
+
+ this.licenseTrigger = ko.observable(false);
+ }
+
+ module.exports = new LicenseAdminStore();
+
+ }());
+
+
+/***/ },
+/* 140 */
+/*!*********************************!*\
+ !*** ./dev/View/Admin/Login.js ***!
+ \*********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function LoginAdminView()
+ {
+ AbstractView.call(this, 'Center', 'AdminLogin');
+
+ this.logoPowered = !!Settings.settingsGet('LoginPowered');
+
+ this.mobile = !!Settings.appSettingsGet('mobile');
+ this.mobileDevice = !!Settings.appSettingsGet('mobileDevice');
+
+ this.login = ko.observable('');
+ this.password = ko.observable('');
+
+ this.loginError = ko.observable(false);
+ this.passwordError = ko.observable(false);
+
+ this.loginErrorAnimation = ko.observable(false).extend({'falseTimeout': 500});
+ this.passwordErrorAnimation = ko.observable(false).extend({'falseTimeout': 500});
+
+ this.loginFocus = ko.observable(false);
+
+ this.formHidden = ko.observable(false);
+
+ this.formError = ko.computed(function () {
+ return this.loginErrorAnimation() || this.passwordErrorAnimation();
+ }, this);
+
+ this.login.subscribe(function () {
+ this.loginError(false);
+ }, this);
+
+ this.password.subscribe(function () {
+ this.passwordError(false);
+ }, this);
+
+ this.loginError.subscribe(function (bV) {
+ this.loginErrorAnimation(!!bV);
+ }, this);
+
+ this.passwordError.subscribe(function (bV) {
+ this.passwordErrorAnimation(!!bV);
+ }, this);
+
+ this.submitRequest = ko.observable(false);
+ this.submitError = ko.observable('');
+
+ this.submitCommand = Utils.createCommand(this, function () {
+
+ Utils.triggerAutocompleteInputChange();
+
+ this.loginError(false);
+ this.passwordError(false);
+
+ this.loginError('' === Utils.trim(this.login()));
+ this.passwordError('' === Utils.trim(this.password()));
+
+ if (this.loginError() || this.passwordError())
+ {
+ return false;
+ }
+
+ this.submitRequest(true);
+
+ Remote.adminLogin(_.bind(function (sResult, oData) {
+
+ if (Enums.StorageResultType.Success === sResult && oData && 'AdminLogin' === oData.Action)
+ {
+ if (oData.Result)
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.loginAndLogoutReload(true);
+ }
+ else if (oData.ErrorCode)
+ {
+ this.submitRequest(false);
+ this.submitError(Translator.getNotification(oData.ErrorCode));
+ }
+ }
+ else
+ {
+ this.submitRequest(false);
+ this.submitError(Translator.getNotification(Enums.Notification.UnknownError));
+ }
+
+ }, this), this.login(), this.password());
+
+ return true;
+
+ }, function () {
+ return !this.submitRequest();
+ });
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Admin/Login', 'AdminLoginViewModel'], LoginAdminView);
+ _.extend(LoginAdminView.prototype, AbstractView.prototype);
+
+ LoginAdminView.prototype.onShow = function ()
+ {
+ kn.routeOff();
+
+ _.delay(_.bind(function () {
+ this.loginFocus(true);
+ }, this), 100);
+
+ };
+
+ LoginAdminView.prototype.onHide = function ()
+ {
+ this.loginFocus(false);
+ };
+
+ LoginAdminView.prototype.onBuild = function ()
+ {
+ Utils.triggerAutocompleteInputChange(true);
+ };
+
+ LoginAdminView.prototype.submitForm = function ()
+ {
+ this.submitCommand();
+ };
+
+ module.exports = LoginAdminView;
+
+ }());
+
+/***/ },
+/* 141 */
+/*!*****************************************!*\
+ !*** ./dev/View/Admin/Settings/Menu.js ***!
+ \*****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @param {?} oScreen
+ *
+ * @constructor
+ * @extends AbstractView
+ */
+ function MenuSettingsAdminView(oScreen)
+ {
+ AbstractView.call(this, 'Left', 'AdminMenu');
+
+ this.leftPanelDisabled = Globals.leftPanelDisabled;
+
+ this.menu = oScreen.menu;
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Admin/Settings/Menu', 'AdminSettingsMenuViewModel'], MenuSettingsAdminView);
+ _.extend(MenuSettingsAdminView.prototype, AbstractView.prototype);
+
+ MenuSettingsAdminView.prototype.link = function (sRoute)
+ {
+ return '#/' + sRoute;
+ };
+
+ MenuSettingsAdminView.prototype.onBuild = function (oDom)
+ {
+ key('up, down', _.throttle(function (event, handler) {
+
+ var
+ sH = '',
+ iIndex = -1,
+ bUp = handler && 'up' === handler.shortcut,
+ $items = $('.b-admin-menu .e-item', oDom)
+ ;
+
+ if (event && $items.length)
+ {
+ iIndex = $items.index($items.filter('.selected'));
+ if (bUp && iIndex > 0)
+ {
+ iIndex--;
+ }
+ else if (!bUp && iIndex < $items.length - 1)
+ {
+ iIndex++;
+ }
+
+ sH = $items.eq(iIndex).attr('href');
+ if (sH)
+ {
+ kn.setHash(sH, false, true);
+ }
+ }
+
+ }, 200));
+ };
+
+ module.exports = MenuSettingsAdminView;
+
+ }());
+
+
+/***/ },
+/* 142 */
+/*!*****************************************!*\
+ !*** ./dev/View/Admin/Settings/Pane.js ***!
+ \*****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function PaneSettingsAdminView()
+ {
+ AbstractView.call(this, 'Right', 'AdminPane');
+
+ this.adminDomain = ko.observable(Settings.settingsGet('AdminDomain'));
+ this.version = ko.observable(Settings.appSettingsGet('version'));
+
+ this.capa = !!Settings.settingsGet('PremType');
+ this.community = (true);
+
+ this.adminManLoading = ko.computed(function () {
+ return '000' !== [
+ __webpack_require__(/*! Stores/Admin/Domain */ 57).domains.loading() ? '1' : '0',
+ __webpack_require__(/*! Stores/Admin/Plugin */ 59).plugins.loading() ? '1' : '0',
+ __webpack_require__(/*! Stores/Admin/Package */ 58).packages.loading() ? '1' : '0'
+ ].join('');
+ }, this);
+
+ this.adminManLoadingVisibility = ko.computed(function () {
+ return this.adminManLoading() ? 'visible' : 'hidden';
+ }, this).extend({'rateLimit': 300});
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Admin/Settings/Pane', 'AdminSettingsPaneViewModel'], PaneSettingsAdminView);
+ _.extend(PaneSettingsAdminView.prototype, AbstractView.prototype);
+
+ PaneSettingsAdminView.prototype.logoutClick = function ()
+ {
+ Remote.adminLogout(function () {
+ __webpack_require__(/*! App/Admin */ 22).default.loginAndLogoutReload(true, true);
+ });
+ };
+
+ module.exports = PaneSettingsAdminView;
+
+ }());
+
+/***/ },
+/* 143 */,
+/* 144 */,
+/* 145 */,
+/* 146 */,
+/* 147 */,
+/* 148 */,
+/* 149 */
+/*!**********************************!*\
+ !*** ./dev/View/Popup/Plugin.js ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+ key = __webpack_require__(/*! key */ 18),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function PluginPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsPlugin');
+
+ var self = this;
+
+ this.onPluginSettingsUpdateResponse = _.bind(this.onPluginSettingsUpdateResponse, this);
+
+ this.saveError = ko.observable('');
+
+ this.name = ko.observable('');
+ this.readme = ko.observable('');
+
+ this.configures = ko.observableArray([]);
+
+ this.hasReadme = ko.computed(function () {
+ return '' !== this.readme();
+ }, this);
+
+ this.hasConfiguration = ko.computed(function () {
+ return 0 < this.configures().length;
+ }, this);
+
+ this.readmePopoverConf = {
+ 'placement': 'right',
+ 'trigger': 'hover',
+ // 'trigger': 'click',
+ 'title': Translator.i18n('POPUPS_PLUGIN/TOOLTIP_ABOUT_TITLE'),
+ 'container': 'body',
+ 'html': true,
+ 'content': function () {
+ return '' + self.readme() + ' ';
+ // .replace(/[\r]/g, '').replace(/[\n]/g, ' ').replace(/[\t]/g, ' ');
+ }
+ };
+
+ this.saveCommand = Utils.createCommand(this, function () {
+
+ var oList = {};
+
+ oList['Name'] = this.name();
+
+ _.each(this.configures(), function (oItem) {
+
+ var mValue = oItem.value();
+ if (false === mValue || true === mValue)
+ {
+ mValue = mValue ? '1' : '0';
+ }
+
+ oList['_' + oItem['Name']] = mValue;
+
+ }, this);
+
+ this.saveError('');
+ Remote.pluginSettingsUpdate(this.onPluginSettingsUpdateResponse, oList);
+
+ }, this.hasConfiguration);
+
+ this.bDisabeCloseOnEsc = true;
+ this.sDefaultKeyScope = Enums.KeyState.All;
+
+ this.tryToClosePopup = _.debounce(_.bind(this.tryToClosePopup, this), 200);
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/Plugin', 'PopupsPluginViewModel'], PluginPopupView);
+ _.extend(PluginPopupView.prototype, AbstractView.prototype);
+
+ PluginPopupView.prototype.onPluginSettingsUpdateResponse = function (sResult, oData)
+ {
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ this.cancelCommand();
+ }
+ else
+ {
+ this.saveError('');
+ if (oData && oData.ErrorCode)
+ {
+ this.saveError(Translator.getNotification(oData.ErrorCode));
+ }
+ else
+ {
+ this.saveError(Translator.getNotification(Enums.Notification.CantSavePluginSettings));
+ }
+ }
+ };
+
+ PluginPopupView.prototype.onShow = function (oPlugin)
+ {
+ this.name();
+ this.readme();
+ this.configures([]);
+
+ if (oPlugin)
+ {
+ this.name(oPlugin['Name']);
+ this.readme(oPlugin['Readme']);
+
+ var aConfig = oPlugin['Config'];
+ if (Utils.isNonEmptyArray(aConfig))
+ {
+ this.configures(_.map(aConfig, function (aItem) {
+ return {
+ 'value': ko.observable(aItem[0]),
+ 'placeholder': ko.observable(aItem[6]),
+ 'Name': aItem[1],
+ 'Type': aItem[2],
+ 'Label': aItem[3],
+ 'Default': aItem[4],
+ 'Desc': aItem[5]
+ };
+ }));
+ }
+ }
+ };
+
+ PluginPopupView.prototype.tryToClosePopup = function ()
+ {
+ var
+ self = this,
+ PopupsAskViewModel = __webpack_require__(/*! View/Popup/Ask */ 43)
+ ;
+
+ if (!kn.isPopupVisible(PopupsAskViewModel))
+ {
+ kn.showScreenPopup(PopupsAskViewModel, [Translator.i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'), function () {
+ if (self.modalVisibility())
+ {
+ Utils.delegateRun(self, 'cancelCommand');
+ }
+ }]);
+ }
+ };
+
+ PluginPopupView.prototype.onBuild = function ()
+ {
+ key('esc', Enums.KeyState.All, _.bind(function () {
+ if (this.modalVisibility())
+ {
+ this.tryToClosePopup();
+ }
+ return false;
+ }, this));
+ };
+
+ module.exports = PluginPopupView;
+
+ }());
+
+/***/ }
+/******/ ]);
diff --git a/rainloop/rainloop/v/1.10.0.103/static/js/admin.js b/rainloop/rainloop/v/1.10.0.103/static/js/admin.js
new file mode 100644
index 0000000..0d19c11
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/static/js/admin.js
@@ -0,0 +1,13046 @@
+/* RainLoop Webmail (c) RainLoop Team | Licensed under AGPL v3 */
+/******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId])
+/******/ return installedModules[moduleId].exports;
+
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ exports: {},
+/******/ id: moduleId,
+/******/ loaded: false
+/******/ };
+
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ // Flag the module as loaded
+/******/ module.loaded = true;
+
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+
+
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "rainloop/v/0.0.0/static/js/";
+
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/*!***********************!*\
+ !*** ./dev/admin.jsx ***!
+ \***********************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _bootstrap = __webpack_require__(/*! bootstrap */ 77);
+
+ var _bootstrap2 = _interopRequireDefault(_bootstrap);
+
+ var _Admin = __webpack_require__(/*! App/Admin */ 22);
+
+ var _Admin2 = _interopRequireDefault(_Admin);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ (0, _bootstrap2.default)(_Admin2.default);
+
+/***/ },
+/* 1 */
+/*!*****************************!*\
+ !*** ./dev/Common/Utils.js ***!
+ \*****************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ oEncryptObject = null,
+
+ Utils = {},
+
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+ Autolinker = __webpack_require__(/*! Autolinker */ 78),
+ JSON = __webpack_require__(/*! JSON */ 36),
+ JSEncrypt = __webpack_require__(/*! JSEncrypt */ 79),
+
+ Mime = __webpack_require__(/*! Common/Mime */ 66),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Globals = __webpack_require__(/*! Common/Globals */ 8)
+ ;
+
+ Utils.trim = $.trim;
+ Utils.inArray = $.inArray;
+ Utils.isArray = _.isArray;
+ Utils.isObject = _.isObject;
+ Utils.isFunc = _.isFunction;
+ Utils.isUnd = _.isUndefined;
+ Utils.isNull = _.isNull;
+ Utils.emptyFunction = Utils.noop = function () {};
+
+ /**
+ * @param {Function} callback
+ */
+ Utils.silentTryCatch = function (callback)
+ {
+ try
+ {
+ callback();
+ }
+ catch (e)
+ {
+ // eslint-disable-line no-empty
+ }
+ };
+
+ /**
+ * @param {*} oValue
+ * @return {boolean}
+ */
+ Utils.isNormal = function (oValue)
+ {
+ return !Utils.isUnd(oValue) && !Utils.isNull(oValue);
+ };
+
+ Utils.windowResize = _.debounce(function (iTimeout) {
+ if (Utils.isUnd(iTimeout))
+ {
+ Globals.$win.resize();
+ }
+ else
+ {
+ window.setTimeout(function () {
+ Globals.$win.resize();
+ }, iTimeout);
+ }
+ }, 50);
+
+ Utils.windowResizeCallback = function () {
+ Utils.windowResize();
+ };
+
+ /**
+ * @param {(string|number)} mValue
+ * @param {boolean=} bIncludeZero
+ * @return {boolean}
+ */
+ Utils.isPosNumeric = function (mValue, bIncludeZero)
+ {
+ return Utils.isNormal(mValue) ?
+ ((Utils.isUnd(bIncludeZero) ? true : !!bIncludeZero) ?
+ (/^[0-9]*$/).test(mValue.toString()) :
+ (/^[1-9]+[0-9]*$/).test(mValue.toString())) :
+ false;
+ };
+
+ /**
+ * @param {*} iValue
+ * @param {number=} iDefault = 0
+ * @return {number}
+ */
+ Utils.pInt = function (iValue, iDefault)
+ {
+ var iResult = Utils.isNormal(iValue) && '' !== iValue ? window.parseInt(iValue, 10) : (iDefault || 0);
+ return window.isNaN(iResult) ? (iDefault || 0) : iResult;
+ };
+
+ /**
+ * @param {*} mValue
+ * @return {string}
+ */
+ Utils.pString = function (mValue)
+ {
+ return Utils.isNormal(mValue) ? '' + mValue : '';
+ };
+
+ /**
+ * @param {*} mValue
+ * @return {boolean}
+ */
+ Utils.pBool = function (mValue)
+ {
+ return !!mValue;
+ };
+
+ /**
+ * @param {string} sComponent
+ * @return {string}
+ */
+ Utils.encodeURIComponent = function (sComponent)
+ {
+ return window.encodeURIComponent(sComponent);
+ };
+
+ /**
+ * @param {*} aValue
+ * @return {boolean}
+ */
+ Utils.isNonEmptyArray = function (aValue)
+ {
+ return Utils.isArray(aValue) && 0 < aValue.length;
+ };
+
+ /**
+ * @param {string} sQueryString
+ * @return {Object}
+ */
+ Utils.simpleQueryParser = function (sQueryString)
+ {
+ var
+ oParams = {},
+ aQueries = [],
+ aTemp = [],
+ iIndex = 0,
+ iLen = 0
+ ;
+
+ aQueries = sQueryString.split('&');
+ for (iIndex = 0, iLen = aQueries.length; iIndex < iLen; iIndex++)
+ {
+ aTemp = aQueries[iIndex].split('=');
+ oParams[window.decodeURIComponent(aTemp[0])] = window.decodeURIComponent(aTemp[1]);
+ }
+
+ return oParams;
+ };
+
+ /**
+ * @param {string} sMailToUrl
+ * @param {Function} PopupComposeVoreModel
+ * @return {boolean}
+ */
+ Utils.mailToHelper = function (sMailToUrl, PopupComposeVoreModel)
+ {
+ if (sMailToUrl && 'mailto:' === sMailToUrl.toString().substr(0, 7).toLowerCase())
+ {
+ if (!PopupComposeVoreModel)
+ {
+ return true;
+ }
+
+ sMailToUrl = sMailToUrl.toString().substr(7);
+
+ var
+ aTo = [],
+ aCc = null,
+ aBcc = null,
+ oParams = {},
+ EmailModel = __webpack_require__(/*! Model/Email */ 30),
+ sEmail = sMailToUrl.replace(/\?.+$/, ''),
+ sQueryString = sMailToUrl.replace(/^[^\?]*\?/, ''),
+ fParseEmailLine = function (sLine) {
+ return sLine ? _.compact(_.map(window.decodeURIComponent(sLine).split(/[,]/), function (sItem) {
+ var oEmailModel = new EmailModel();
+ oEmailModel.mailsoParse(sItem);
+ return '' !== oEmailModel.email ? oEmailModel : null;
+ })) : null;
+ }
+ ;
+
+ aTo = fParseEmailLine(sEmail);
+
+ oParams = Utils.simpleQueryParser(sQueryString);
+
+ if (!Utils.isUnd(oParams.cc))
+ {
+ aCc = fParseEmailLine(window.decodeURIComponent(oParams.cc));
+ }
+
+ if (!Utils.isUnd(oParams.bcc))
+ {
+ aBcc = fParseEmailLine(window.decodeURIComponent(oParams.bcc));
+ }
+
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(PopupComposeVoreModel, [Enums.ComposeType.Empty, null,
+ aTo, aCc, aBcc,
+ Utils.isUnd(oParams.subject) ? null :
+ Utils.pString(window.decodeURIComponent(oParams.subject)),
+ Utils.isUnd(oParams.body) ? null :
+ Utils.plainToHtml(Utils.pString(window.decodeURIComponent(oParams.body)))
+ ]);
+
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {string} sPublicKey
+ * @return {JSEncrypt}
+ */
+ Utils.rsaObject = function (sPublicKey)
+ {
+ if (JSEncrypt && sPublicKey && (null === oEncryptObject || (oEncryptObject && oEncryptObject.__sPublicKey !== sPublicKey)) &&
+ window.crypto && window.crypto.getRandomValues)
+ {
+ oEncryptObject = new JSEncrypt();
+ oEncryptObject.setPublicKey(sPublicKey);
+ oEncryptObject.__sPublicKey = sPublicKey;
+ }
+ else
+ {
+ oEncryptObject = false;
+ }
+
+ return oEncryptObject;
+ };
+
+ /**
+ * @param {string} sValue
+ * @param {string} sPublicKey
+ * @return {string}
+ */
+ Utils.rsaEncode = function (sValue, sPublicKey)
+ {
+ if (window.crypto && window.crypto.getRandomValues && sPublicKey)
+ {
+ var
+ sResultValue = false,
+ oEncrypt = Utils.rsaObject(sPublicKey)
+ ;
+
+ if (oEncrypt)
+ {
+ sResultValue = oEncrypt.encrypt(Utils.fakeMd5() + ':' + sValue + ':' + Utils.fakeMd5());
+ if (false !== sResultValue && Utils.isNormal(sResultValue))
+ {
+ return 'rsa:xxx:' + sResultValue;
+ }
+ }
+ }
+
+ return sValue;
+ };
+
+ Utils.rsaEncode.supported = !!(window.crypto && window.crypto.getRandomValues && false && JSEncrypt);
+
+ /**
+ * @param {string} sText
+ * @return {string}
+ */
+ Utils.encodeHtml = function (sText)
+ {
+ return Utils.isNormal(sText) ? _.escape(sText.toString()) : '';
+ };
+
+ /**
+ * @param {string} sText
+ * @param {number=} iLen
+ * @return {string}
+ */
+ Utils.splitPlainText = function (sText, iLen)
+ {
+ var
+ sPrefix = '',
+ sSubText = '',
+ sResult = sText,
+ iSpacePos = 0,
+ iNewLinePos = 0
+ ;
+
+ iLen = Utils.isUnd(iLen) ? 100 : iLen;
+
+ while (sResult.length > iLen)
+ {
+ sSubText = sResult.substring(0, iLen);
+ iSpacePos = sSubText.lastIndexOf(' ');
+ iNewLinePos = sSubText.lastIndexOf('\n');
+
+ if (-1 !== iNewLinePos)
+ {
+ iSpacePos = iNewLinePos;
+ }
+
+ if (-1 === iSpacePos)
+ {
+ iSpacePos = iLen;
+ }
+
+ sPrefix += sSubText.substring(0, iSpacePos) + '\n';
+ sResult = sResult.substring(iSpacePos + 1);
+ }
+
+ return sPrefix + sResult;
+ };
+
+ Utils.timeOutAction = (function () {
+
+ var
+ oTimeOuts = {}
+ ;
+
+ return function (sAction, fFunction, iTimeOut)
+ {
+ if (Utils.isUnd(oTimeOuts[sAction]))
+ {
+ oTimeOuts[sAction] = 0;
+ }
+
+ window.clearTimeout(oTimeOuts[sAction]);
+ oTimeOuts[sAction] = window.setTimeout(fFunction, iTimeOut);
+ };
+ }());
+
+ Utils.timeOutActionSecond = (function () {
+
+ var
+ oTimeOuts = {}
+ ;
+
+ return function (sAction, fFunction, iTimeOut)
+ {
+ if (!oTimeOuts[sAction])
+ {
+ oTimeOuts[sAction] = window.setTimeout(function () {
+ fFunction();
+ oTimeOuts[sAction] = 0;
+ }, iTimeOut);
+ }
+ };
+ }());
+
+ /**
+ * @param {(Object|null|undefined)} oObject
+ * @param {string} sProp
+ * @return {boolean}
+ */
+ Utils.hos = function (oObject, sProp)
+ {
+ return oObject && window.Object && window.Object.hasOwnProperty ? window.Object.hasOwnProperty.call(oObject, sProp) : false;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ Utils.inFocus = function ()
+ {
+ if (window.document.activeElement)
+ {
+ if (Utils.isUnd(window.document.activeElement.__inFocusCache))
+ {
+ window.document.activeElement.__inFocusCache = $(window.document.activeElement).is('input,textarea,iframe,.cke_editable');
+ }
+
+ return !!window.document.activeElement.__inFocusCache;
+ }
+
+ return false;
+ };
+
+ Utils.removeInFocus = function (force)
+ {
+ if (window.document && window.document.activeElement && window.document.activeElement.blur)
+ {
+ var oA = $(window.document.activeElement);
+ if (oA.is('input,textarea'))
+ {
+ window.document.activeElement.blur();
+ }
+ else if (force)
+ {
+ try {
+ window.document.activeElement.blur();
+ } catch (e) {}
+ }
+ }
+ };
+
+ Utils.removeSelection = function ()
+ {
+ if (window && window.getSelection)
+ {
+ var oSel = window.getSelection();
+ if (oSel && oSel.removeAllRanges)
+ {
+ oSel.removeAllRanges();
+ }
+ }
+ else if (window.document && window.document.selection && window.document.selection.empty)
+ {
+ window.document.selection.empty();
+ }
+ };
+
+ /**
+ * @param {string} sPrefix
+ * @param {string} sSubject
+ * @return {string}
+ */
+ Utils.replySubjectAdd = function (sPrefix, sSubject)
+ {
+ sPrefix = Utils.trim(sPrefix.toUpperCase());
+ sSubject = Utils.trim(sSubject.replace(/[\s]+/g, ' '));
+
+ var
+ bDrop = false,
+ aSubject = [],
+ bRe = 'RE' === sPrefix,
+ bFwd = 'FWD' === sPrefix,
+ bPrefixIsRe = !bFwd
+ ;
+
+ if ('' !== sSubject)
+ {
+ _.each(sSubject.split(':'), function (sPart) {
+ var sTrimmedPart = Utils.trim(sPart);
+ if (!bDrop && (/^(RE|FWD)$/i.test(sTrimmedPart) || /^(RE|FWD)[\[\(][\d]+[\]\)]$/i.test(sTrimmedPart)))
+ {
+ if (!bRe)
+ {
+ bRe = !!(/^RE/i.test(sTrimmedPart));
+ }
+
+ if (!bFwd)
+ {
+ bFwd = !!(/^FWD/i.test(sTrimmedPart));
+ }
+ }
+ else
+ {
+ aSubject.push(sPart);
+ bDrop = true;
+ }
+ });
+ }
+
+ if (bPrefixIsRe)
+ {
+ bRe = false;
+ }
+ else
+ {
+ bFwd = false;
+ }
+
+ return Utils.trim(
+ (bPrefixIsRe ? 'Re: ' : 'Fwd: ') +
+ (bRe ? 'Re: ' : '') +
+ (bFwd ? 'Fwd: ' : '') +
+ Utils.trim(aSubject.join(':'))
+ );
+ };
+
+ /**
+ * @param {number} iNum
+ * @param {number} iDec
+ * @return {number}
+ */
+ Utils.roundNumber = function (iNum, iDec)
+ {
+ return window.Math.round(iNum * window.Math.pow(10, iDec)) / window.Math.pow(10, iDec);
+ };
+
+ /**
+ * @param {(number|string)} iSizeInBytes
+ * @return {string}
+ */
+ Utils.friendlySize = function (iSizeInBytes)
+ {
+ iSizeInBytes = Utils.pInt(iSizeInBytes);
+
+ if (iSizeInBytes >= 1073741824)
+ {
+ return Utils.roundNumber(iSizeInBytes / 1073741824, 1) + 'GB';
+ }
+ else if (iSizeInBytes >= 1048576)
+ {
+ return Utils.roundNumber(iSizeInBytes / 1048576, 1) + 'MB';
+ }
+ else if (iSizeInBytes >= 1024)
+ {
+ return Utils.roundNumber(iSizeInBytes / 1024, 0) + 'KB';
+ }
+
+ return iSizeInBytes + 'B';
+ };
+
+ /**
+ * @param {string} sDesc
+ */
+ Utils.log = function (sDesc)
+ {
+ if (window.console && window.console.log)
+ {
+ window.console.log(sDesc);
+ }
+ };
+
+ /**
+ * @param {?} oObject
+ * @param {string} sMethodName
+ * @param {Array=} aParameters
+ * @param {number=} nDelay
+ */
+ Utils.delegateRun = function (oObject, sMethodName, aParameters, nDelay)
+ {
+ if (oObject && oObject[sMethodName])
+ {
+ nDelay = Utils.pInt(nDelay);
+ if (0 >= nDelay)
+ {
+ oObject[sMethodName].apply(oObject, Utils.isArray(aParameters) ? aParameters : []);
+ }
+ else
+ {
+ _.delay(function () {
+ oObject[sMethodName].apply(oObject, Utils.isArray(aParameters) ? aParameters : []);
+ }, nDelay);
+ }
+ }
+ };
+
+ /**
+ * @param {?} oEvent
+ */
+ Utils.kill_CtrlA_CtrlS = function (oEvent)
+ {
+ oEvent = oEvent || window.event;
+ if (oEvent && oEvent.ctrlKey && !oEvent.shiftKey && !oEvent.altKey)
+ {
+ var
+ oSender = oEvent.target || oEvent.srcElement,
+ iKey = oEvent.keyCode || oEvent.which
+ ;
+
+ if (iKey === Enums.EventKeyCode.S)
+ {
+ oEvent.preventDefault();
+ return;
+ }
+ else if (iKey === Enums.EventKeyCode.A)
+ {
+ if (oSender && ('true' === '' + oSender.contentEditable ||
+ (oSender.tagName && oSender.tagName.match(/INPUT|TEXTAREA/i))))
+ {
+ return;
+ }
+
+ if (window.getSelection)
+ {
+ window.getSelection().removeAllRanges();
+ }
+ else if (window.document.selection && window.document.selection.clear)
+ {
+ window.document.selection.clear();
+ }
+
+ oEvent.preventDefault();
+ }
+ }
+ };
+
+ /**
+ * @param {(Object|null|undefined)} oContext
+ * @param {Function} fExecute
+ * @param {(Function|boolean|null)=} fCanExecute
+ * @return {Function}
+ */
+ Utils.createCommand = function (oContext, fExecute, fCanExecute)
+ {
+ var
+ fResult = Utils.emptyFunction,
+ fNonEmpty = function () {
+ if (fResult && fResult.canExecute && fResult.canExecute())
+ {
+ fExecute.apply(oContext, Array.prototype.slice.call(arguments));
+ }
+ return false;
+ }
+ ;
+
+ fResult = fExecute ? fNonEmpty : Utils.emptyFunction;
+ fResult.enabled = ko.observable(true);
+
+ fCanExecute = Utils.isUnd(fCanExecute) ? true : fCanExecute;
+ if (Utils.isFunc(fCanExecute))
+ {
+ fResult.canExecute = ko.computed(function () {
+ return fResult.enabled() && fCanExecute.call(oContext);
+ });
+ }
+ else
+ {
+ fResult.canExecute = ko.computed(function () {
+ return fResult.enabled() && !!fCanExecute;
+ });
+ }
+
+ return fResult;
+ };
+
+ /**
+ * @param {string} sTheme
+ * @return {string}
+ */
+ Utils.convertThemeName = _.memoize(function (sTheme)
+ {
+ if ('@custom' === sTheme.substr(-7))
+ {
+ sTheme = Utils.trim(sTheme.substring(0, sTheme.length - 7));
+ }
+
+ return Utils.trim(sTheme.replace(/[^a-zA-Z0-9]+/g, ' ').replace(/([A-Z])/g, ' $1').replace(/[\s]+/g, ' '));
+ });
+
+ /**
+ * @param {string} sName
+ * @return {string}
+ */
+ Utils.quoteName = function (sName)
+ {
+ return sName.replace(/["]/g, '\\"');
+ };
+
+ /**
+ * @return {number}
+ */
+ Utils.microtime = function ()
+ {
+ return (new window.Date()).getTime();
+ };
+
+ /**
+ * @return {number}
+ */
+ Utils.timestamp = function ()
+ {
+ return window.Math.round(Utils.microtime() / 1000);
+ };
+
+ /**
+ *
+ * @param {string} sLanguage
+ * @param {boolean=} bEng = false
+ * @return {string}
+ */
+ Utils.convertLangName = function (sLanguage, bEng)
+ {
+ return __webpack_require__(/*! Common/Translator */ 6).i18n('LANGS_NAMES' + (true === bEng ? '_EN' : '') + '/LANG_' +
+ sLanguage.toUpperCase().replace(/[^a-zA-Z0-9]+/g, '_'), null, sLanguage);
+ };
+
+ /**
+ * @param {number=} iLen
+ * @return {string}
+ */
+ Utils.fakeMd5 = function(iLen)
+ {
+ var
+ sResult = '',
+ sLine = '0123456789abcdefghijklmnopqrstuvwxyz'
+ ;
+
+ iLen = Utils.isUnd(iLen) ? 32 : Utils.pInt(iLen);
+
+ while (sResult.length < iLen)
+ {
+ sResult += sLine.substr(window.Math.round(window.Math.random() * sLine.length), 1);
+ }
+
+ return sResult;
+ };
+
+ Utils.draggablePlace = function ()
+ {
+ return $('' +
+ ' ' +
+ '
').appendTo('#rl-hidden');
+ };
+
+ Utils.defautOptionsAfterRender = function (oDomOption, oItem)
+ {
+ if (oItem && !Utils.isUnd(oItem.disabled) && oDomOption)
+ {
+ $(oDomOption)
+ .toggleClass('disabled', oItem.disabled)
+ .prop('disabled', oItem.disabled)
+ ;
+ }
+ };
+
+ /**
+ * @param {Object} oViewModel
+ * @param {string} sTemplateID
+ * @param {string} sTitle
+ * @param {Function=} fCallback
+ */
+ Utils.windowPopupKnockout = function (oViewModel, sTemplateID, sTitle, fCallback)
+ {
+ var
+ oScript = null,
+ oWin = window.open(''),
+ sFunc = '__OpenerApplyBindingsUid' + Utils.fakeMd5() + '__',
+ oTemplate = $('#' + sTemplateID)
+ ;
+
+ window[sFunc] = function () {
+
+ if (oWin && oWin.document.body && oTemplate && oTemplate[0])
+ {
+ var oBody = $(oWin.document.body);
+
+ $('#rl-content', oBody).html(oTemplate.html());
+ $('html', oWin.document).addClass('external ' + $('html').attr('class'));
+
+ __webpack_require__(/*! Common/Translator */ 6).i18nToNodes(oBody);
+
+ if (oViewModel && $('#rl-content', oBody)[0])
+ {
+ ko.applyBindings(oViewModel, $('#rl-content', oBody)[0]);
+ }
+
+ window[sFunc] = null;
+
+ fCallback(oWin);
+ }
+ };
+
+ oWin.document.open();
+ oWin.document.write('' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ '' + Utils.encodeHtml(sTitle) + ' ' +
+ '
');
+ oWin.document.close();
+
+ oScript = oWin.document.createElement('script');
+ oScript.type = 'text/javascript';
+ oScript.innerHTML = 'if(window&&window.opener&&window.opener[\'' + sFunc + '\']){window.opener[\'' + sFunc + '\']();window.opener[\'' + sFunc + '\']=null}';
+ oWin.document.getElementsByTagName('head')[0].appendChild(oScript);
+ };
+
+ /**
+ * @param {Function} fCallback
+ * @param {?} koTrigger
+ * @param {?} oContext = null
+ * @param {number=} iTimer = 1000
+ * @return {Function}
+ */
+ Utils.settingsSaveHelperFunction = function (fCallback, koTrigger, oContext, iTimer)
+ {
+ oContext = oContext || null;
+ iTimer = Utils.isUnd(iTimer) ? 1000 : Utils.pInt(iTimer);
+
+ return function (sType, mData, bCached, sRequestAction, oRequestParameters) {
+ koTrigger.call(oContext, mData && mData['Result'] ? Enums.SaveSettingsStep.TrueResult : Enums.SaveSettingsStep.FalseResult);
+ if (fCallback)
+ {
+ fCallback.call(oContext, sType, mData, bCached, sRequestAction, oRequestParameters);
+ }
+ _.delay(function () {
+ koTrigger.call(oContext, Enums.SaveSettingsStep.Idle);
+ }, iTimer);
+ };
+ };
+
+ Utils.settingsSaveHelperSimpleFunction = function (koTrigger, oContext)
+ {
+ return Utils.settingsSaveHelperFunction(null, koTrigger, oContext, 1000);
+ };
+
+ Utils.settingsSaveHelperSubscribeFunction = function (oRemote, sSettingName, sType, fTriggerFunction)
+ {
+ return function (mValue) {
+
+ if (oRemote)
+ {
+ switch (sType)
+ {
+ default:
+ mValue = Utils.pString(mValue);
+ break;
+ case 'bool':
+ case 'boolean':
+ mValue = mValue ? '1' : '0';
+ break;
+ case 'int':
+ case 'integer':
+ case 'number':
+ mValue = Utils.pInt(mValue);
+ break;
+ case 'trim':
+ mValue = Utils.trim(mValue);
+ break;
+ }
+
+ var oData = {};
+ oData[sSettingName] = mValue;
+
+ if (oRemote.saveAdminConfig)
+ {
+ oRemote.saveAdminConfig(fTriggerFunction || null, oData);
+ }
+ else if (oRemote.saveSettings)
+ {
+ oRemote.saveSettings(fTriggerFunction || null, oData);
+ }
+ }
+ };
+ };
+
+ /**
+ * @param {string} sHtml
+ * @return {string}
+ */
+ Utils.htmlToPlain = function (sHtml)
+ {
+ var
+ iPos = 0,
+ iP1 = 0,
+ iP2 = 0,
+ iP3 = 0,
+ iLimit = 0,
+
+ sText = '',
+
+ convertBlockquote = function (sText) {
+ sText = Utils.trim(sText);
+ sText = '> ' + sText.replace(/\n/gm, '\n> ');
+ return sText.replace(/(^|\n)([> ]+)/gm, function () {
+ return (arguments && 2 < arguments.length) ? arguments[1] + $.trim(arguments[2].replace(/[\s]/g, '')) + ' ' : '';
+ });
+ },
+
+ convertDivs = function () {
+ if (arguments && 1 < arguments.length)
+ {
+ var sText = $.trim(arguments[1]);
+ if (0 < sText.length)
+ {
+ sText = sText.replace(/]*>([\s\S\r\n]*)<\/div>/gmi, convertDivs);
+ sText = '\n' + $.trim(sText) + '\n';
+ }
+
+ return sText;
+ }
+
+ return '';
+ },
+
+ convertPre = function () {
+ return (arguments && 1 < arguments.length) ?
+ arguments[1].toString()
+ .replace(/[\n]/gm, '
')
+ .replace(/[\r]/gm, '')
+ : '';
+ },
+
+ fixAttibuteValue = function () {
+ return (arguments && 1 < arguments.length) ?
+ '' + arguments[1] + _.escape(arguments[2]) : '';
+ },
+
+ convertLinks = function () {
+ return (arguments && 1 < arguments.length) ? $.trim(arguments[1]) : '';
+ }
+ ;
+
+ sText = sHtml
+ .replace(/\u0002([\s\S]*)\u0002/gm, '\u200C$1\u200C')
+ .replace(/
]*><\/p>/gi, '')
+ .replace(/
]*>([\s\S\r\n\t]*)<\/pre>/gmi, convertPre)
+ .replace(/[\s]+/gm, ' ')
+ .replace(/((?:href|data)\s?=\s?)("[^"]+?"|'[^']+?')/gmi, fixAttibuteValue)
+ .replace(/ ]*>/gmi, '\n')
+ .replace(/<\/h[\d]>/gi, '\n')
+ .replace(/<\/p>/gi, '\n\n')
+ .replace(/ ]*>/gmi, '\n')
+ .replace(/<\/ul>/gi, '\n')
+ .replace(/]*>/gmi, ' * ')
+ .replace(/<\/li>/gi, '\n')
+ .replace(/<\/td>/gi, '\n')
+ .replace(/<\/tr>/gi, '\n')
+ .replace(/ ]*>/gmi, '\n_______________________________\n\n')
+ .replace(/]*>([\s\S\r\n]*)<\/div>/gmi, convertDivs)
+ .replace(/
]*>/gmi, '\n__bq__start__\n')
+ .replace(/<\/blockquote>/gmi, '\n__bq__end__\n')
+ .replace(/]*>([\s\S\r\n]*?)<\/a>/gmi, convertLinks)
+ .replace(/<\/div>/gi, '\n')
+ .replace(/ /gi, ' ')
+ .replace(/"/gi, '"')
+ .replace(/<[^>]*>/gm, '')
+ ;
+
+ sText = Globals.$div.html(sText).text();
+
+ sText = sText
+ .replace(/\n[ \t]+/gm, '\n')
+ .replace(/[\n]{3,}/gm, '\n\n')
+ .replace(/>/gi, '>')
+ .replace(/</gi, '<')
+ .replace(/&/gi, '&')
+ ;
+
+ sText = Utils.splitPlainText(Utils.trim(sText));
+
+ iPos = 0;
+ iLimit = 800;
+
+ while (0 < iLimit)
+ {
+ iLimit--;
+ iP1 = sText.indexOf('__bq__start__', iPos);
+ if (-1 < iP1)
+ {
+ iP2 = sText.indexOf('__bq__start__', iP1 + 5);
+ iP3 = sText.indexOf('__bq__end__', iP1 + 5);
+
+ if ((-1 === iP2 || iP3 < iP2) && iP1 < iP3)
+ {
+ sText = sText.substring(0, iP1) +
+ convertBlockquote(sText.substring(iP1 + 13, iP3)) +
+ sText.substring(iP3 + 11);
+
+ iPos = 0;
+ }
+ else if (-1 < iP2 && iP2 < iP3)
+ {
+ iPos = iP2 - 1;
+ }
+ else
+ {
+ iPos = 0;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ sText = sText
+ .replace(/__bq__start__/gm, '')
+ .replace(/__bq__end__/gm, '')
+ ;
+
+ return sText;
+ };
+
+ /**
+ * @param {string} sPlain
+ * @param {boolean} bFindEmailAndLinks = false
+ * @return {string}
+ */
+ Utils.plainToHtml = function (sPlain, bFindEmailAndLinks)
+ {
+ sPlain = sPlain.toString().replace(/\r/g, '');
+
+ bFindEmailAndLinks = Utils.isUnd(bFindEmailAndLinks) ? false : !!bFindEmailAndLinks;
+
+ var
+ bIn = false,
+ bDo = true,
+ bStart = true,
+ aNextText = [],
+ sLine = '',
+ iIndex = 0,
+ aText = sPlain.split("\n")
+ ;
+
+ do
+ {
+ bDo = false;
+ aNextText = [];
+ for (iIndex = 0; iIndex < aText.length; iIndex++)
+ {
+ sLine = aText[iIndex];
+ bStart = '>' === sLine.substr(0, 1);
+ if (bStart && !bIn)
+ {
+ bDo = true;
+ bIn = true;
+ aNextText.push('~~~blockquote~~~');
+ aNextText.push(sLine.substr(1));
+ }
+ else if (!bStart && bIn)
+ {
+ if ('' !== sLine)
+ {
+ bIn = false;
+ aNextText.push('~~~/blockquote~~~');
+ aNextText.push(sLine);
+ }
+ else
+ {
+ aNextText.push(sLine);
+ }
+ }
+ else if (bStart && bIn)
+ {
+ aNextText.push(sLine.substr(1));
+ }
+ else
+ {
+ aNextText.push(sLine);
+ }
+ }
+
+ if (bIn)
+ {
+ bIn = false;
+ aNextText.push('~~~/blockquote~~~');
+ }
+
+ aText = aNextText;
+ }
+ while (bDo);
+
+ sPlain = aText.join("\n");
+
+ sPlain = sPlain
+ // .replace(/~~~\/blockquote~~~\n~~~blockquote~~~/g, '\n')
+ .replace(/&/g, '&')
+ .replace(/>/g, '>').replace(/')
+ .replace(/[\s]*~~~\/blockquote~~~/g, ' ')
+ .replace(/\u200C([\s\S]*)\u200C/g, '\u0002$1\u0002')
+ .replace(/\n/g, '
')
+ ;
+
+ return bFindEmailAndLinks ? Utils.findEmailAndLinks(sPlain) : sPlain;
+ };
+
+ window.rainloop_Utils_htmlToPlain = Utils.htmlToPlain;
+ window.rainloop_Utils_plainToHtml = Utils.plainToHtml;
+
+ /**
+ * @param {string} sHtml
+ * @return {string}
+ */
+ Utils.findEmailAndLinks = function (sHtml)
+ {
+ // return sHtml;
+ sHtml = Autolinker.link(sHtml, {
+ 'newWindow': true,
+ 'stripPrefix': false,
+ 'urls': true,
+ 'email': true,
+ 'twitter': false,
+ 'replaceFn': function (autolinker, match) {
+ return !(autolinker && match && 'url' === match.getType() && match.matchedText && 0 !== match.matchedText.indexOf('http'));
+ }
+ });
+
+ return sHtml;
+ };
+
+ /**
+ * @param {string} sUrl
+ * @param {number} iValue
+ * @param {Function} fCallback
+ */
+ Utils.resizeAndCrop = function (sUrl, iValue, fCallback)
+ {
+ var oTempImg = new window.Image();
+ oTempImg.onload = function() {
+
+ var
+ aDiff = [0, 0],
+ oCanvas = window.document.createElement('canvas'),
+ oCtx = oCanvas.getContext('2d')
+ ;
+
+ oCanvas.width = iValue;
+ oCanvas.height = iValue;
+
+ if (this.width > this.height)
+ {
+ aDiff = [this.width - this.height, 0];
+ }
+ else
+ {
+ aDiff = [0, this.height - this.width];
+ }
+
+ oCtx.fillStyle = '#fff';
+ oCtx.fillRect(0, 0, iValue, iValue);
+ oCtx.drawImage(this, aDiff[0] / 2, aDiff[1] / 2, this.width - aDiff[0], this.height - aDiff[1], 0, 0, iValue, iValue);
+
+ fCallback(oCanvas.toDataURL('image/jpeg'));
+ };
+
+ oTempImg.src = sUrl;
+ };
+
+ /**
+ * @param {Array} aSystem
+ * @param {Array} aList
+ * @param {Array=} aDisabled
+ * @param {Array=} aHeaderLines
+ * @param {?number=} iUnDeep
+ * @param {Function=} fDisableCallback
+ * @param {Function=} fVisibleCallback
+ * @param {Function=} fRenameCallback
+ * @param {boolean=} bSystem
+ * @param {boolean=} bBuildUnvisible
+ * @return {Array}
+ */
+ Utils.folderListOptionsBuilder = function (aSystem, aList, aDisabled, aHeaderLines,
+ iUnDeep, fDisableCallback, fVisibleCallback, fRenameCallback, bSystem, bBuildUnvisible)
+ {
+ var
+ /**
+ * @type {?FolderModel}
+ */
+ oItem = null,
+ bSep = false,
+ iIndex = 0,
+ iLen = 0,
+ sDeepPrefix = '\u00A0\u00A0\u00A0',
+ aResult = []
+ ;
+
+ bBuildUnvisible = Utils.isUnd(bBuildUnvisible) ? false : !!bBuildUnvisible;
+ bSystem = !Utils.isNormal(bSystem) ? 0 < aSystem.length : bSystem;
+ iUnDeep = !Utils.isNormal(iUnDeep) ? 0 : iUnDeep;
+ fDisableCallback = Utils.isNormal(fDisableCallback) ? fDisableCallback : null;
+ fVisibleCallback = Utils.isNormal(fVisibleCallback) ? fVisibleCallback : null;
+ fRenameCallback = Utils.isNormal(fRenameCallback) ? fRenameCallback : null;
+
+ if (!Utils.isArray(aDisabled))
+ {
+ aDisabled = [];
+ }
+
+ if (!Utils.isArray(aHeaderLines))
+ {
+ aHeaderLines = [];
+ }
+
+ for (iIndex = 0, iLen = aHeaderLines.length; iIndex < iLen; iIndex++)
+ {
+ aResult.push({
+ 'id': aHeaderLines[iIndex][0],
+ 'name': aHeaderLines[iIndex][1],
+ 'system': false,
+ 'seporator': false,
+ 'disabled': false
+ });
+ }
+
+ bSep = true;
+ for (iIndex = 0, iLen = aSystem.length; iIndex < iLen; iIndex++)
+ {
+ oItem = aSystem[iIndex];
+ if (fVisibleCallback ? fVisibleCallback.call(null, oItem) : true)
+ {
+ if (bSep && 0 < aResult.length)
+ {
+ aResult.push({
+ 'id': '---',
+ 'name': '---',
+ 'system': false,
+ 'seporator': true,
+ 'disabled': true
+ });
+ }
+
+ bSep = false;
+ aResult.push({
+ 'id': oItem.fullNameRaw,
+ 'name': fRenameCallback ? fRenameCallback.call(null, oItem) : oItem.name(),
+ 'system': true,
+ 'seporator': false,
+ 'disabled': !oItem.selectable || -1 < Utils.inArray(oItem.fullNameRaw, aDisabled) ||
+ (fDisableCallback ? fDisableCallback.call(null, oItem) : false)
+ });
+ }
+ }
+
+ bSep = true;
+ for (iIndex = 0, iLen = aList.length; iIndex < iLen; iIndex++)
+ {
+ oItem = aList[iIndex];
+ // if (oItem.subScribed() || !oItem.existen || bBuildUnvisible)
+ if ((oItem.subScribed() || !oItem.existen || bBuildUnvisible) && (oItem.selectable || oItem.hasSubScribedSubfolders()))
+ {
+ if (fVisibleCallback ? fVisibleCallback.call(null, oItem) : true)
+ {
+ if (Enums.FolderType.User === oItem.type() || !bSystem || oItem.hasSubScribedSubfolders())
+ {
+ if (bSep && 0 < aResult.length)
+ {
+ aResult.push({
+ 'id': '---',
+ 'name': '---',
+ 'system': false,
+ 'seporator': true,
+ 'disabled': true
+ });
+ }
+
+ bSep = false;
+ aResult.push({
+ 'id': oItem.fullNameRaw,
+ 'name': (new window.Array(oItem.deep + 1 - iUnDeep)).join(sDeepPrefix) +
+ (fRenameCallback ? fRenameCallback.call(null, oItem) : oItem.name()),
+ 'system': false,
+ 'seporator': false,
+ 'disabled': !oItem.selectable || -1 < Utils.inArray(oItem.fullNameRaw, aDisabled) ||
+ (fDisableCallback ? fDisableCallback.call(null, oItem) : false)
+ });
+ }
+ }
+ }
+
+ if (oItem.subScribed() && 0 < oItem.subFolders().length)
+ {
+ aResult = aResult.concat(Utils.folderListOptionsBuilder([], oItem.subFolders(), aDisabled, [],
+ iUnDeep, fDisableCallback, fVisibleCallback, fRenameCallback, bSystem, bBuildUnvisible));
+ }
+ }
+
+ return aResult;
+ };
+
+ Utils.computedPagenatorHelper = function (koCurrentPage, koPageCount)
+ {
+ return function() {
+
+ var
+ iPrev = 0,
+ iNext = 0,
+ iLimit = 2,
+ aResult = [],
+ iCurrentPage = koCurrentPage(),
+ iPageCount = koPageCount(),
+
+ /**
+ * @param {number} iIndex
+ * @param {boolean=} bPush = true
+ * @param {string=} sCustomName = ''
+ */
+ fAdd = function (iIndex, bPush, sCustomName) {
+
+ var oData = {
+ 'current': iIndex === iCurrentPage,
+ 'name': Utils.isUnd(sCustomName) ? iIndex.toString() : sCustomName.toString(),
+ 'custom': Utils.isUnd(sCustomName) ? false : true,
+ 'title': Utils.isUnd(sCustomName) ? '' : iIndex.toString(),
+ 'value': iIndex.toString()
+ };
+
+ if (Utils.isUnd(bPush) ? true : !!bPush)
+ {
+ aResult.push(oData);
+ }
+ else
+ {
+ aResult.unshift(oData);
+ }
+ }
+ ;
+
+ if (1 < iPageCount || (0 < iPageCount && iPageCount < iCurrentPage))
+ // if (0 < iPageCount && 0 < iCurrentPage)
+ {
+ if (iPageCount < iCurrentPage)
+ {
+ fAdd(iPageCount);
+ iPrev = iPageCount;
+ iNext = iPageCount;
+ }
+ else
+ {
+ if (3 >= iCurrentPage || iPageCount - 2 <= iCurrentPage)
+ {
+ iLimit += 2;
+ }
+
+ fAdd(iCurrentPage);
+ iPrev = iCurrentPage;
+ iNext = iCurrentPage;
+ }
+
+ while (0 < iLimit) {
+
+ iPrev -= 1;
+ iNext += 1;
+
+ if (0 < iPrev)
+ {
+ fAdd(iPrev, false);
+ iLimit--;
+ }
+
+ if (iPageCount >= iNext)
+ {
+ fAdd(iNext, true);
+ iLimit--;
+ }
+ else if (0 >= iPrev)
+ {
+ break;
+ }
+ }
+
+ if (3 === iPrev)
+ {
+ fAdd(2, false);
+ }
+ else if (3 < iPrev)
+ {
+ fAdd(window.Math.round((iPrev - 1) / 2), false, '...');
+ }
+
+ if (iPageCount - 2 === iNext)
+ {
+ fAdd(iPageCount - 1, true);
+ }
+ else if (iPageCount - 2 > iNext)
+ {
+ fAdd(window.Math.round((iPageCount + iNext) / 2), true, '...');
+ }
+
+ // first and last
+ if (1 < iPrev)
+ {
+ fAdd(1, false);
+ }
+
+ if (iPageCount > iNext)
+ {
+ fAdd(iPageCount, true);
+ }
+ }
+
+ return aResult;
+ };
+ };
+
+ Utils.selectElement = function (element)
+ {
+ var sel, range;
+ if (window.getSelection)
+ {
+ sel = window.getSelection();
+ sel.removeAllRanges();
+ range = window.document.createRange();
+ range.selectNodeContents(element);
+ sel.addRange(range);
+ }
+ else if (window.document.selection)
+ {
+ range = window.document.body.createTextRange();
+ range.moveToElementText(element);
+ range.select();
+ }
+ };
+
+ Utils.detectDropdownVisibility = _.debounce(function () {
+ Globals.dropdownVisibility(!!_.find(Globals.aBootstrapDropdowns, function (oItem) {
+ return oItem.hasClass('open');
+ }));
+ }, 50);
+
+ /**
+ * @param {boolean=} bDelay = false
+ */
+ Utils.triggerAutocompleteInputChange = function (bDelay) {
+
+ var fFunc = function () {
+ $('.checkAutocomplete').trigger('change');
+ };
+
+ if (Utils.isUnd(bDelay) ? false : !!bDelay)
+ {
+ _.delay(fFunc, 100);
+ }
+ else
+ {
+ fFunc();
+ }
+ };
+
+ /**
+ * @param {Object} oParams
+ */
+ Utils.setHeadViewport = function (oParams)
+ {
+ var aContent = [];
+ _.each(oParams, function (sKey, sValue) {
+ aContent.push('' + sKey + '=' + sValue);
+ });
+
+ $('#rl-head-viewport').attr('content', aContent.join(', '));
+ };
+
+ /**
+ * @param {string} sFileName
+ * @return {string}
+ */
+ Utils.getFileExtension = function (sFileName)
+ {
+ sFileName = Utils.trim(sFileName).toLowerCase();
+
+ var sResult = sFileName.split('.').pop();
+ return (sResult === sFileName) ? '' : sResult;
+ };
+
+ Utils.configurationScriptTagCache = {};
+
+ /**
+ * @param {string} sConfiguration
+ * @return {object}
+ */
+ Utils.getConfigurationFromScriptTag = function (sConfiguration)
+ {
+ var oResult = {};
+
+ if (!Utils.configurationScriptTagCache[sConfiguration])
+ {
+ Utils.configurationScriptTagCache[sConfiguration] = $('script[type="application/json"][data-configuration="' + sConfiguration + '"]');
+ }
+
+ try {
+ oResult = JSON.parse(Utils.configurationScriptTagCache[sConfiguration].text());
+ } catch (e) {/* eslint-disable-line no-empty */}
+
+ return oResult;
+ };
+
+ /**
+ * @param {string} sFileName
+ * @return {string}
+ */
+ Utils.mimeContentType = function (sFileName)
+ {
+ var
+ sExt = '',
+ sResult = 'application/octet-stream'
+ ;
+
+ sFileName = Utils.trim(sFileName).toLowerCase();
+
+ if ('winmail.dat' === sFileName)
+ {
+ return 'application/ms-tnef';
+ }
+
+ sExt = Utils.getFileExtension(sFileName);
+ if (sExt && 0 < sExt.length && !Utils.isUnd(Mime[sExt]))
+ {
+ sResult = Mime[sExt];
+ }
+
+ return sResult;
+ };
+
+ /**
+ * @param {mixed} mPropOrValue
+ * @param {mixed} mValue
+ */
+ Utils.disposeOne = function (mPropOrValue, mValue)
+ {
+ var mDisposable = mValue || mPropOrValue;
+ if (mDisposable && typeof mDisposable.dispose === 'function')
+ {
+ mDisposable.dispose();
+ }
+ };
+
+ /**
+ * @param {Object} oObject
+ */
+ Utils.disposeObject = function (oObject)
+ {
+ if (oObject)
+ {
+ if (Utils.isArray(oObject.disposables))
+ {
+ _.each(oObject.disposables, Utils.disposeOne);
+ }
+
+ ko.utils.objectForEach(oObject, Utils.disposeOne);
+ }
+ };
+
+ /**
+ * @param {Object|Array} mObjectOrObjects
+ */
+ Utils.delegateRunOnDestroy = function (mObjectOrObjects)
+ {
+ if (mObjectOrObjects)
+ {
+ if (Utils.isArray(mObjectOrObjects))
+ {
+ _.each(mObjectOrObjects, function (oItem) {
+ Utils.delegateRunOnDestroy(oItem);
+ });
+ }
+ else if (mObjectOrObjects && mObjectOrObjects.onDestroy)
+ {
+ mObjectOrObjects.onDestroy();
+ }
+ }
+ };
+
+ Utils.__themeTimer = 0;
+ Utils.__themeAjax = null;
+
+ Utils.changeTheme = function (sValue, themeTrigger)
+ {
+ var
+ oThemeLink = $('#rlThemeLink'),
+ oThemeStyle = $('#rlThemeStyle'),
+ sUrl = oThemeLink.attr('href')
+ ;
+
+ if (!sUrl)
+ {
+ sUrl = oThemeStyle.attr('data-href');
+ }
+
+ if (sUrl)
+ {
+ sUrl = sUrl.toString().replace(/\/-\/[^\/]+\/\-\//, '/-/' + sValue + '/-/');
+ sUrl = sUrl.toString().replace(/\/Css\/[^\/]+\/User\//, '/Css/0/User/');
+ sUrl = sUrl.toString().replace(/\/Hash\/[^\/]+\//, '/Hash/-/');
+
+ if ('Json/' !== sUrl.substring(sUrl.length - 5, sUrl.length))
+ {
+ sUrl += 'Json/';
+ }
+
+ window.clearTimeout(Utils.__themeTimer);
+ themeTrigger(Enums.SaveSettingsStep.Animate);
+
+ if (Utils.__themeAjax && Utils.__themeAjax.abort)
+ {
+ Utils.__themeAjax.abort();
+ }
+
+ Utils.__themeAjax = $.ajax({
+ 'url': sUrl,
+ 'dataType': 'json'
+ }).done(function(aData) {
+
+ if (aData && Utils.isArray(aData) && 2 === aData.length)
+ {
+ if (oThemeLink && oThemeLink[0] && (!oThemeStyle || !oThemeStyle[0]))
+ {
+ oThemeStyle = $('');
+ oThemeLink.after(oThemeStyle);
+ oThemeLink.remove();
+ }
+
+ if (oThemeStyle && oThemeStyle[0])
+ {
+ oThemeStyle.attr('data-href', sUrl).attr('data-theme', aData[0]);
+ if (oThemeStyle[0].styleSheet && !Utils.isUnd(oThemeStyle[0].styleSheet.cssText))
+ {
+ oThemeStyle[0].styleSheet.cssText = aData[1];
+ }
+ else
+ {
+ oThemeStyle.text(aData[1]);
+ }
+ }
+
+ themeTrigger(Enums.SaveSettingsStep.TrueResult);
+ }
+
+ }).always(function() {
+
+ Utils.__themeTimer = window.setTimeout(function () {
+ themeTrigger(Enums.SaveSettingsStep.Idle);
+ }, 1000);
+
+ Utils.__themeAjax = null;
+ });
+ }
+ };
+
+ Utils.substr = window.String.substr;
+ if ('ab'.substr(-1) !== 'b')
+ {
+ Utils.substr = function(sStr, iStart, iLength)
+ {
+ if (iStart < 0)
+ {
+ iStart = sStr.length + iStart;
+ }
+
+ return sStr.substr(iStart, iLength);
+ };
+ }
+
+ module.exports = Utils;
+
+ }());
+
+/***/ },
+/* 2 */
+/*!****************************!*\
+ !*** ./dev/External/ko.js ***!
+ \****************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function (ko) {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ JSON = __webpack_require__(/*! JSON */ 36),
+ Opentip = __webpack_require__(/*! Opentip */ 54),
+
+ fDisposalTooltipHelper = function (oElement) {
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ if (oElement && oElement.__opentip)
+ {
+ oElement.__opentip.deactivate();
+ }
+ });
+ }
+ ;
+
+ ko.bindingHandlers.updateWidth = {
+ 'init': function (oElement, fValueAccessor) {
+ var
+ $w = $(window),
+ $oEl = $(oElement),
+ fValue = fValueAccessor(),
+ fInit = function(){
+ fValue($oEl.width());
+ window.setTimeout(function(){
+ fValue($oEl.width());
+ }, 500);
+ }
+ ;
+
+ $w.on('resize', fInit);
+ fInit();
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $w.off('resize', fInit);
+ });
+ }
+ };
+
+ ko.bindingHandlers.editor = {
+ 'init': function (oElement, fValueAccessor) {
+
+ var
+ oEditor = null,
+ fValue = fValueAccessor(),
+
+ fUpdateEditorValue = function () {
+ if (fValue && fValue.__editor)
+ {
+ fValue.__editor.setHtmlOrPlain(fValue());
+ }
+ },
+
+ fUpdateKoValue = function () {
+ if (fValue && fValue.__editor)
+ {
+ fValue(fValue.__editor.getDataWithHtmlMark());
+ }
+ },
+
+ fOnReady = function () {
+ fValue.__editor = oEditor;
+ fUpdateEditorValue();
+ },
+
+ HtmlEditor = __webpack_require__(/*! Common/HtmlEditor */ 45)
+ ;
+
+ if (ko.isObservable(fValue) && HtmlEditor)
+ {
+ oEditor = new HtmlEditor(oElement, fUpdateKoValue, fOnReady, fUpdateKoValue);
+
+ fValue.__fetchEditorValue = fUpdateKoValue;
+
+ fValue.subscribe(fUpdateEditorValue);
+
+ // ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ // });
+ }
+ }
+ };
+
+ ko.bindingHandlers.json = {
+ 'init': function (oElement, fValueAccessor) {
+ $(oElement).text(JSON.stringify(ko.unwrap(fValueAccessor())));
+ },
+ 'update': function (oElement, fValueAccessor) {
+ $(oElement).text(JSON.stringify(ko.unwrap(fValueAccessor())));
+ }
+ };
+
+ ko.bindingHandlers.scrollerShadows = {
+ 'init': function (oElement) {
+
+ var
+ iLimit = 8,
+ $oEl = $(oElement),
+ $win = $(window),
+ oCont = $oEl.find('[data-scroller-shadows-content]')[0] || null,
+ fFunc = _.throttle(function () {
+ $oEl
+ .toggleClass('scroller-shadow-top', iLimit < oCont.scrollTop)
+ .toggleClass('scroller-shadow-bottom', oCont.scrollTop + iLimit < oCont.scrollHeight - oCont.clientHeight)
+ ;
+ }, 100)
+ ;
+
+ if (oCont)
+ {
+ $(oCont).on('scroll resize', fFunc);
+ $win.on('resize', fFunc);
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oCont, function () {
+ $(oCont).off();
+ $win.off('resize', fFunc);
+ });
+ }
+ }
+ };
+
+ ko.bindingHandlers.tooltip = {
+ 'init': function (oElement, fValueAccessor) {
+
+ var
+ bi18n = true,
+ sValue = '',
+ Translator = null,
+ $oEl = $(oElement),
+ fValue = fValueAccessor(),
+ bMobile = 'on' === ($oEl.data('tooltip-mobile') || 'off'),
+ Globals = __webpack_require__(/*! Common/Globals */ 8)
+ ;
+
+ if (!Globals.bMobileDevice || bMobile)
+ {
+ bi18n = 'on' === ($oEl.data('tooltip-i18n') || 'on');
+ sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue);
+
+ oElement.__opentip = new Opentip(oElement, {
+ 'style': 'rainloopTip',
+ 'element': oElement,
+ 'tipJoint': $oEl.data('tooltip-join') || 'bottom'
+ });
+
+ Globals.dropdownVisibility.subscribe(function (bV) {
+ if (bV) {
+ oElement.__opentip.hide();
+ }
+ });
+
+ if ('' === sValue)
+ {
+ oElement.__opentip.hide();
+ oElement.__opentip.deactivate();
+ oElement.__opentip.setContent('');
+ }
+ else
+ {
+ oElement.__opentip.activate();
+ }
+
+ if (bi18n)
+ {
+ Translator = __webpack_require__(/*! Common/Translator */ 6);
+
+ oElement.__opentip.setContent(Translator.i18n(sValue));
+
+ Translator.trigger.subscribe(function () {
+ oElement.__opentip.setContent(Translator.i18n(sValue));
+ });
+
+ Globals.dropdownVisibility.subscribe(function () {
+ if (oElement && oElement.__opentip)
+ {
+ oElement.__opentip.setContent(__webpack_require__(/*! Common/Translator */ 6).i18n(sValue));
+ }
+ });
+ }
+ else
+ {
+ oElement.__opentip.setContent(sValue);
+ }
+ }
+ },
+ 'update': function (oElement, fValueAccessor) {
+
+ var
+ bi18n = true,
+ sValue = '',
+ $oEl = $(oElement),
+ fValue = fValueAccessor(),
+ bMobile = 'on' === ($oEl.data('tooltip-mobile') || 'off'),
+ Globals = __webpack_require__(/*! Common/Globals */ 8)
+ ;
+
+ if ((!Globals.bMobileDevice || bMobile) && oElement.__opentip)
+ {
+ bi18n = 'on' === ($oEl.data('tooltip-i18n') || 'on');
+ sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue);
+
+ if (sValue)
+ {
+ oElement.__opentip.setContent(
+ bi18n ? __webpack_require__(/*! Common/Translator */ 6).i18n(sValue) : sValue);
+ oElement.__opentip.activate();
+ }
+ else
+ {
+ oElement.__opentip.hide();
+ oElement.__opentip.deactivate();
+ oElement.__opentip.setContent('');
+ }
+ }
+ }
+ };
+
+ ko.bindingHandlers.tooltipErrorTip = {
+ 'init': function (oElement) {
+
+ var $oEl = $(oElement);
+
+ oElement.__opentip = new Opentip(oElement, {
+ 'style': 'rainloopErrorTip',
+ 'hideOn': 'mouseout click',
+ 'element': oElement,
+ 'tipJoint': $oEl.data('tooltip-join') || 'top'
+ });
+
+ oElement.__opentip.deactivate();
+
+ $(window.document).on('click', function () {
+ if (oElement && oElement.__opentip)
+ {
+ oElement.__opentip.hide();
+ }
+ });
+
+ fDisposalTooltipHelper(oElement);
+ },
+ 'update': function (oElement, fValueAccessor) {
+
+ var
+ $oEl = $(oElement),
+ fValue = fValueAccessor(),
+ sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue),
+ oOpenTips = oElement.__opentip
+ ;
+
+ if (oOpenTips)
+ {
+ if ('' === sValue)
+ {
+ oOpenTips.hide();
+ oOpenTips.deactivate();
+ oOpenTips.setContent('');
+ }
+ else
+ {
+ _.delay(function () {
+ if ($oEl.is(':visible'))
+ {
+ oOpenTips.setContent(sValue);
+ oOpenTips.activate();
+ oOpenTips.show();
+ }
+ else
+ {
+ oOpenTips.hide();
+ oOpenTips.deactivate();
+ oOpenTips.setContent('');
+ }
+ }, 100);
+ }
+ }
+ }
+ };
+
+ ko.bindingHandlers.registrateBootstrapDropdown = {
+ 'init': function (oElement) {
+ var Globals = __webpack_require__(/*! Common/Globals */ 8);
+ if (Globals && Globals.aBootstrapDropdowns)
+ {
+ Globals.aBootstrapDropdowns.push($(oElement));
+
+ $(oElement).click(function () {
+ __webpack_require__(/*! Common/Utils */ 1).detectDropdownVisibility();
+ });
+
+ // ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ // });
+ }
+ }
+ };
+
+ ko.bindingHandlers.openDropdownTrigger = {
+ 'update': function (oElement, fValueAccessor) {
+ if (ko.unwrap(fValueAccessor()))
+ {
+ var $oEl = $(oElement);
+ if (!$oEl.hasClass('open'))
+ {
+ $oEl.find('.dropdown-toggle').dropdown('toggle');
+ }
+
+ $oEl.find('.dropdown-toggle').focus();
+
+ __webpack_require__(/*! Common/Utils */ 1).detectDropdownVisibility();
+ fValueAccessor()(false);
+ }
+ }
+ };
+
+ ko.bindingHandlers.dropdownCloser = {
+ 'init': function (oElement) {
+ $(oElement).closest('.dropdown').on('click', '.e-item', function () {
+ $(oElement).dropdown('toggle');
+ });
+ }
+ };
+
+ ko.bindingHandlers.popover = {
+ 'init': function (oElement, fValueAccessor) {
+ $(oElement).popover(ko.unwrap(fValueAccessor()));
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement).popover('destroy');
+ });
+ }
+ };
+
+ ko.bindingHandlers.csstext = {
+ 'init': function (oElement, fValueAccessor) {
+ if (oElement && oElement.styleSheet && undefined !== oElement.styleSheet.cssText)
+ {
+ oElement.styleSheet.cssText = ko.unwrap(fValueAccessor());
+ }
+ else
+ {
+ $(oElement).text(ko.unwrap(fValueAccessor()));
+ }
+ },
+ 'update': function (oElement, fValueAccessor) {
+ if (oElement && oElement.styleSheet && undefined !== oElement.styleSheet.cssText)
+ {
+ oElement.styleSheet.cssText = ko.unwrap(fValueAccessor());
+ }
+ else
+ {
+ $(oElement).text(ko.unwrap(fValueAccessor()));
+ }
+ }
+ };
+
+ ko.bindingHandlers.resizecrop = {
+ 'init': function (oElement) {
+ $(oElement).addClass('resizecrop').resizecrop({
+ 'width': '100',
+ 'height': '100',
+ 'wrapperCSS': {
+ 'border-radius': '10px'
+ }
+ });
+ },
+ 'update': function (oElement, fValueAccessor) {
+ fValueAccessor()();
+ $(oElement).resizecrop({
+ 'width': '100',
+ 'height': '100'
+ });
+ }
+ };
+
+ ko.bindingHandlers.onEnter = {
+ 'init': function (oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) {
+ $(oElement).on('keypress.koOnEnter', function (oEvent) {
+ if (oEvent && 13 === window.parseInt(oEvent.keyCode, 10))
+ {
+ $(oElement).trigger('change');
+ fValueAccessor().call(oViewModel);
+ }
+ });
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement).off('keypress.koOnEnter');
+ });
+ }
+ };
+
+ ko.bindingHandlers.onSpace = {
+ 'init': function (oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) {
+ $(oElement).on('keyup.koOnSpace', function (oEvent) {
+ if (oEvent && 32 === window.parseInt(oEvent.keyCode, 10))
+ {
+ fValueAccessor().call(oViewModel, oEvent);
+ }
+ });
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement).off('keyup.koOnSpace');
+ });
+ }
+ };
+
+ ko.bindingHandlers.onTab = {
+ 'init': function (oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) {
+ $(oElement).on('keydown.koOnTab', function (oEvent) {
+ if (oEvent && 9 === window.parseInt(oEvent.keyCode, 10))
+ {
+ return fValueAccessor().call(oViewModel, !!oEvent.shiftKey);
+ }
+ });
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement).off('keydown.koOnTab');
+ });
+ }
+ };
+
+ ko.bindingHandlers.onEsc = {
+ 'init': function (oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) {
+ $(oElement).on('keypress.koOnEsc', function (oEvent) {
+ if (oEvent && 27 === window.parseInt(oEvent.keyCode, 10))
+ {
+ $(oElement).trigger('change');
+ fValueAccessor().call(oViewModel);
+ }
+ });
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement).off('keypress.koOnEsc');
+ });
+ }
+ };
+
+ ko.bindingHandlers.clickOnTrue = {
+ 'update': function (oElement, fValueAccessor) {
+ if (ko.unwrap(fValueAccessor()))
+ {
+ $(oElement).click();
+ }
+ }
+ };
+
+ ko.bindingHandlers.modal = {
+ 'init': function (oElement, fValueAccessor) {
+
+ var
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1)
+ ;
+
+ $(oElement).toggleClass('fade', !Globals.bMobileDevice).modal({
+ 'keyboard': false,
+ 'show': ko.unwrap(fValueAccessor())
+ })
+ .on('shown.koModal', Utils.windowResizeCallback)
+ .find('.close').on('click.koModal', function () {
+ fValueAccessor()(false);
+ });
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement)
+ .off('shown.koModal')
+ .find('.close')
+ .off('click.koModal')
+ ;
+ });
+ },
+ 'update': function (oElement, fValueAccessor) {
+
+ var Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ $(oElement).modal(!!ko.unwrap(fValueAccessor()) ? 'show' : 'hide');
+
+ if (Globals.$html.hasClass('rl-anim'))
+ {
+ Globals.$html.addClass('rl-modal-animation');
+ _.delay(function () {
+ Globals.$html.removeClass('rl-modal-animation');
+ }, 400);
+ }
+
+ }
+ };
+
+ ko.bindingHandlers.moment = {
+ 'init': function (oElement, fValueAccessor) {
+ __webpack_require__(/*! Common/Momentor */ 26).momentToNode(
+ $(oElement).addClass('moment').data('moment-time', ko.unwrap(fValueAccessor()))
+ );
+ },
+ 'update': function (oElement, fValueAccessor) {
+ __webpack_require__(/*! Common/Momentor */ 26).momentToNode(
+ $(oElement).data('moment-time', ko.unwrap(fValueAccessor()))
+ );
+ }
+ };
+
+ ko.bindingHandlers.i18nInit = {
+ 'init': function (oElement) {
+ __webpack_require__(/*! Common/Translator */ 6).i18nToNodes(oElement);
+ }
+ };
+
+ ko.bindingHandlers.translatorInit = {
+ 'init': function (oElement) {
+ __webpack_require__(/*! Common/Translator */ 6).i18nToNodes(oElement);
+ }
+ };
+
+ ko.bindingHandlers.i18nUpdate = {
+ 'update': function (oElement, fValueAccessor) {
+ ko.unwrap(fValueAccessor());
+ __webpack_require__(/*! Common/Translator */ 6).i18nToNodes(oElement);
+ }
+ };
+
+ ko.bindingHandlers.link = {
+ 'update': function (oElement, fValueAccessor) {
+ $(oElement).attr('href', ko.unwrap(fValueAccessor()));
+ }
+ };
+
+ ko.bindingHandlers.title = {
+ 'update': function (oElement, fValueAccessor) {
+ $(oElement).attr('title', ko.unwrap(fValueAccessor()));
+ }
+ };
+
+ ko.bindingHandlers.textF = {
+ 'init': function (oElement, fValueAccessor) {
+ $(oElement).text(ko.unwrap(fValueAccessor()));
+ }
+ };
+
+ ko.bindingHandlers.initDom = {
+ 'init': function (oElement, fValueAccessor) {
+ fValueAccessor()(oElement);
+ }
+ };
+
+ ko.bindingHandlers.initFixedTrigger = {
+ 'init': function (oElement, fValueAccessor) {
+ var
+ aValues = ko.unwrap(fValueAccessor()),
+ $oContainer = null,
+ $oElement = $(oElement),
+ oOffset = null,
+
+ iTop = aValues[1] || 0
+ ;
+
+ $oContainer = $(aValues[0] || null);
+ $oContainer = $oContainer[0] ? $oContainer : null;
+
+ if ($oContainer)
+ {
+ $(window).resize(function () {
+ oOffset = $oContainer.offset();
+ if (oOffset && oOffset.top)
+ {
+ $oElement.css('top', oOffset.top + iTop);
+ }
+ });
+ }
+ }
+ };
+
+ ko.bindingHandlers.initResizeTrigger = {
+ 'init': function (oElement, fValueAccessor) {
+ var aValues = ko.unwrap(fValueAccessor());
+ $(oElement).css({
+ 'height': aValues[1],
+ 'min-height': aValues[1]
+ });
+ },
+ 'update': function (oElement, fValueAccessor) {
+
+ var
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ aValues = ko.unwrap(fValueAccessor()),
+ iValue = Utils.pInt(aValues[1]),
+ iSize = 0,
+ iOffset = $(oElement).offset().top
+ ;
+
+ if (0 < iOffset)
+ {
+ iOffset += Utils.pInt(aValues[2]);
+ iSize = Globals.$win.height() - iOffset;
+
+ if (iValue < iSize)
+ {
+ iValue = iSize;
+ }
+
+ $(oElement).css({
+ 'height': iValue,
+ 'min-height': iValue
+ });
+ }
+ }
+ };
+
+ ko.bindingHandlers.appendDom = {
+ 'update': function (oElement, fValueAccessor) {
+ $(oElement).hide().empty().append(ko.unwrap(fValueAccessor())).show();
+ }
+ };
+
+ ko.bindingHandlers.draggable = {
+ 'init': function (oElement, fValueAccessor, fAllBindingsAccessor) {
+
+ var
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1)
+ ;
+
+ if (!Globals.bMobileDevice)
+ {
+ var
+ iTriggerZone = 100,
+ iScrollSpeed = 3,
+ fAllValueFunc = fAllBindingsAccessor(),
+ sDroppableSelector = fAllValueFunc && fAllValueFunc['droppableSelector'] ? fAllValueFunc['droppableSelector'] : '',
+ oConf = {
+ 'distance': 20,
+ 'handle': '.dragHandle',
+ 'cursorAt': {'top': 22, 'left': 3},
+ 'refreshPositions': true,
+ 'scroll': true
+ }
+ ;
+
+ if (sDroppableSelector)
+ {
+ oConf['drag'] = function (oEvent) {
+
+ $(sDroppableSelector).each(function () {
+ var
+ moveUp = null,
+ moveDown = null,
+ $this = $(this),
+ oOffset = $this.offset(),
+ bottomPos = oOffset.top + $this.height()
+ ;
+
+ window.clearInterval($this.data('timerScroll'));
+ $this.data('timerScroll', false);
+
+ if (oEvent.pageX >= oOffset.left && oEvent.pageX <= oOffset.left + $this.width())
+ {
+ if (oEvent.pageY >= bottomPos - iTriggerZone && oEvent.pageY <= bottomPos)
+ {
+ moveUp = function() {
+ $this.scrollTop($this.scrollTop() + iScrollSpeed);
+ Utils.windowResize();
+ };
+
+ $this.data('timerScroll', window.setInterval(moveUp, 10));
+ moveUp();
+ }
+
+ if (oEvent.pageY >= oOffset.top && oEvent.pageY <= oOffset.top + iTriggerZone)
+ {
+ moveDown = function() {
+ $this.scrollTop($this.scrollTop() - iScrollSpeed);
+ Utils.windowResize();
+ };
+
+ $this.data('timerScroll', window.setInterval(moveDown, 10));
+ moveDown();
+ }
+ }
+ });
+ };
+
+ oConf['stop'] = function() {
+ $(sDroppableSelector).each(function () {
+ window.clearInterval($(this).data('timerScroll'));
+ $(this).data('timerScroll', false);
+ });
+ };
+ }
+
+ oConf['helper'] = function (oEvent) {
+ return fValueAccessor()(oEvent && oEvent.target ? ko.dataFor(oEvent.target) : null);
+ };
+
+ $(oElement).draggable(oConf).on('mousedown.koDraggable', function () {
+ Utils.removeInFocus();
+ });
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement)
+ .off('mousedown.koDraggable')
+ .draggable('destroy')
+ ;
+ });
+ }
+ }
+ };
+
+ ko.bindingHandlers.droppable = {
+ 'init': function (oElement, fValueAccessor, fAllBindingsAccessor) {
+ var Globals = __webpack_require__(/*! Common/Globals */ 8);
+ if (!Globals.bMobileDevice)
+ {
+ var
+ fValueFunc = fValueAccessor(),
+ fAllValueFunc = fAllBindingsAccessor(),
+ fOverCallback = fAllValueFunc && fAllValueFunc['droppableOver'] ? fAllValueFunc['droppableOver'] : null,
+ fOutCallback = fAllValueFunc && fAllValueFunc['droppableOut'] ? fAllValueFunc['droppableOut'] : null,
+ oConf = {
+ 'tolerance': 'pointer',
+ 'hoverClass': 'droppableHover'
+ }
+ ;
+
+ if (fValueFunc)
+ {
+ oConf['drop'] = function (oEvent, oUi) {
+ fValueFunc(oEvent, oUi);
+ };
+
+ if (fOverCallback)
+ {
+ oConf['over'] = function (oEvent, oUi) {
+ fOverCallback(oEvent, oUi);
+ };
+ }
+
+ if (fOutCallback)
+ {
+ oConf['out'] = function (oEvent, oUi) {
+ fOutCallback(oEvent, oUi);
+ };
+ }
+
+ $(oElement).droppable(oConf);
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement).droppable('destroy');
+ });
+ }
+ }
+ }
+ };
+
+ ko.bindingHandlers.nano = {
+ 'init': function (oElement) {
+ var Globals = __webpack_require__(/*! Common/Globals */ 8);
+ if (!Globals.bDisableNanoScroll)
+ {
+ $(oElement)
+ .addClass('nano')
+ .nanoScroller({
+ 'iOSNativeScrolling': false,
+ 'preventPageScrolling': true
+ })
+ ;
+ }
+ }
+ };
+
+ ko.bindingHandlers.saveTrigger = {
+ 'init': function (oElement) {
+
+ var $oEl = $(oElement);
+
+ $oEl.data('save-trigger-type', $oEl.is('input[type=text],input[type=email],input[type=password],select,textarea') ? 'input' : 'custom');
+
+ if ('custom' === $oEl.data('save-trigger-type'))
+ {
+ $oEl.append(
+ '
'
+ ).addClass('settings-saved-trigger');
+ }
+ else
+ {
+ $oEl.addClass('settings-saved-trigger-input');
+ }
+ },
+ 'update': function (oElement, fValueAccessor) {
+ var
+ mValue = ko.unwrap(fValueAccessor()),
+ $oEl = $(oElement)
+ ;
+
+ if ('custom' === $oEl.data('save-trigger-type'))
+ {
+ switch (mValue.toString())
+ {
+ case '1':
+ $oEl
+ .find('.animated,.error').hide().removeClass('visible')
+ .end()
+ .find('.success').show().addClass('visible')
+ ;
+ break;
+ case '0':
+ $oEl
+ .find('.animated,.success').hide().removeClass('visible')
+ .end()
+ .find('.error').show().addClass('visible')
+ ;
+ break;
+ case '-2':
+ $oEl
+ .find('.error,.success').hide().removeClass('visible')
+ .end()
+ .find('.animated').show().addClass('visible')
+ ;
+ break;
+ default:
+ $oEl
+ .find('.animated').hide()
+ .end()
+ .find('.error,.success').removeClass('visible')
+ ;
+ break;
+ }
+ }
+ else
+ {
+ switch (mValue.toString())
+ {
+ case '1':
+ $oEl.addClass('success').removeClass('error');
+ break;
+ case '0':
+ $oEl.addClass('error').removeClass('success');
+ break;
+ case '-2':
+ // $oEl;
+ break;
+ default:
+ $oEl.removeClass('error success');
+ break;
+ }
+ }
+ }
+ };
+
+ ko.bindingHandlers.emailsTags = {
+ 'init': function(oElement, fValueAccessor, fAllBindingsAccessor) {
+
+ var
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ EmailModel = __webpack_require__(/*! Model/Email */ 30),
+
+ $oEl = $(oElement),
+ fValue = fValueAccessor(),
+ fAllBindings = fAllBindingsAccessor(),
+ fAutoCompleteSource = fAllBindings['autoCompleteSource'] || null,
+ fFocusCallback = function (bValue) {
+ if (fValue && fValue.focused)
+ {
+ fValue.focused(!!bValue);
+ }
+ }
+ ;
+
+ $oEl.inputosaurus({
+ 'parseOnBlur': true,
+ 'allowDragAndDrop': true,
+ 'focusCallback': fFocusCallback,
+ 'inputDelimiters': [',', ';', "\n"],
+ 'autoCompleteSource': fAutoCompleteSource,
+ // 'elementHook': function (oEl, oItem) {
+ // if (oEl && oItem)
+ // {
+ // oEl.addClass('pgp');
+ // window.console.log(arguments);
+ // }
+ // },
+ 'parseHook': function (aInput) {
+
+ return _.map(aInput, function (sInputValue) {
+
+ var
+ sValue = Utils.trim(sInputValue),
+ oEmail = null
+ ;
+
+ if ('' !== sValue)
+ {
+ oEmail = new EmailModel();
+ oEmail.mailsoParse(sValue);
+ return [oEmail.toLine(false), oEmail];
+ }
+
+ return [sValue, null];
+
+ });
+
+ // var aResult = [];
+ //
+ // _.each(aInput, function (sInputValue) {
+ //
+ // var
+ // aM = null,
+ // aValues = [],
+ // sValue = Utils.trim(sInputValue),
+ // oEmail = null
+ // ;
+ //
+ // if ('' !== sValue)
+ // {
+ // aM = sValue.match(/[@]/g);
+ // if (aM && 0 < aM.length)
+ // {
+ // sValue = sValue.replace(/[\r\n]+/g, '; ').replace(/[\s]+/g, ' ');
+ // aValues = EmailModel.splitHelper(sValue, ';');
+ //
+ // _.each(aValues, function (sV) {
+ //
+ // oEmail = new EmailModel();
+ // oEmail.mailsoParse(sV);
+ //
+ // if (oEmail.email)
+ // {
+ // aResult.push([oEmail.toLine(false), oEmail]);
+ // }
+ // else
+ // {
+ // aResult.push(['', null]);
+ // }
+ // });
+ // }
+ // else
+ // {
+ // aResult.push([sInputValue, null]);
+ // }
+ // }
+ // else
+ // {
+ // aResult.push([sInputValue, null]);
+ // }
+ // });
+ //
+ // return aResult;
+ },
+ 'change': _.bind(function (oEvent) {
+ $oEl.data('EmailsTagsValue', oEvent.target.value);
+ fValue(oEvent.target.value);
+ }, this)
+ });
+
+ if (fValue && fValue.focused && fValue.focused.subscribe)
+ {
+ fValue.focused.subscribe(function (bValue) {
+ $oEl.inputosaurus(!!bValue ? 'focus' : 'blur');
+ });
+ }
+ },
+ 'update': function (oElement, fValueAccessor) {
+
+ var
+ $oEl = $(oElement),
+ fValue = fValueAccessor(),
+ sValue = ko.unwrap(fValue)
+ ;
+
+ if ($oEl.data('EmailsTagsValue') !== sValue)
+ {
+ $oEl.val(sValue);
+ $oEl.data('EmailsTagsValue', sValue);
+ $oEl.inputosaurus('refresh');
+ }
+ }
+ };
+
+ ko.bindingHandlers.command = {
+ 'init': function (oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) {
+ var
+ jqElement = $(oElement),
+ oCommand = fValueAccessor()
+ ;
+
+ if (!oCommand || !oCommand.enabled || !oCommand.canExecute)
+ {
+ throw new Error('You are not using command function');
+ }
+
+ jqElement.addClass('command');
+ ko.bindingHandlers[jqElement.is('form') ? 'submit' : 'click'].init.apply(oViewModel, arguments);
+ },
+
+ 'update': function (oElement, fValueAccessor) {
+
+ var
+ bResult = true,
+ jqElement = $(oElement),
+ oCommand = fValueAccessor()
+ ;
+
+ bResult = oCommand.enabled();
+ jqElement.toggleClass('command-not-enabled', !bResult);
+
+ if (bResult)
+ {
+ bResult = oCommand.canExecute();
+ jqElement.toggleClass('command-can-not-be-execute', !bResult);
+ }
+
+ jqElement.toggleClass('command-disabled disable disabled', !bResult).toggleClass('no-disabled', !!bResult);
+
+ if (jqElement.is('input') || jqElement.is('button'))
+ {
+ jqElement.prop('disabled', !bResult);
+ }
+ }
+ };
+
+ // extenders
+
+ ko.extenders.trimmer = function (oTarget)
+ {
+ var
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ oResult = ko.computed({
+ 'read': oTarget,
+ 'write': function (sNewValue) {
+ oTarget(Utils.trim(sNewValue.toString()));
+ },
+ 'owner': this
+ })
+ ;
+
+ oResult(oTarget());
+ return oResult;
+ };
+
+ ko.extenders.posInterer = function (oTarget, iDefault)
+ {
+ var
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ oResult = ko.computed({
+ 'read': oTarget,
+ 'write': function (sNewValue) {
+ var iNew = Utils.pInt(sNewValue.toString(), iDefault);
+ if (0 >= iNew)
+ {
+ iNew = iDefault;
+ }
+
+ if (iNew === oTarget() && '' + iNew !== '' + sNewValue)
+ {
+ oTarget(iNew + 1);
+ }
+
+ oTarget(iNew);
+ }
+ })
+ ;
+
+ oResult(oTarget());
+ return oResult;
+ };
+
+ ko.extenders.limitedList = function (oTarget, mList)
+ {
+ var
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ oResult = ko.computed({
+ 'read': oTarget,
+ 'write': function (sNewValue) {
+
+ var
+ sCurrentValue = ko.unwrap(oTarget),
+ aList = ko.unwrap(mList)
+ ;
+
+ if (Utils.isNonEmptyArray(aList))
+ {
+ if (-1 < Utils.inArray(sNewValue, aList))
+ {
+ oTarget(sNewValue);
+ }
+ else if (-1 < Utils.inArray(sCurrentValue, aList))
+ {
+ oTarget(sCurrentValue + ' ');
+ oTarget(sCurrentValue);
+ }
+ else
+ {
+ oTarget(aList[0] + ' ');
+ oTarget(aList[0]);
+ }
+ }
+ else
+ {
+ oTarget('');
+ }
+ }
+ }).extend({'notify': 'always'})
+ ;
+
+ oResult(oTarget());
+
+ if (!oResult.valueHasMutated)
+ {
+ oResult.valueHasMutated = function () {
+ oTarget.valueHasMutated();
+ };
+ }
+
+ return oResult;
+ };
+
+ ko.extenders.reversible = function (oTarget)
+ {
+ var mValue = oTarget();
+
+ oTarget.commit = function ()
+ {
+ mValue = oTarget();
+ };
+
+ oTarget.reverse = function ()
+ {
+ oTarget(mValue);
+ };
+
+ oTarget.commitedValue = function ()
+ {
+ return mValue;
+ };
+
+ return oTarget;
+ };
+
+ ko.extenders.toggleSubscribe = function (oTarget, oOptions)
+ {
+ oTarget.subscribe(oOptions[1], oOptions[0], 'beforeChange');
+ oTarget.subscribe(oOptions[2], oOptions[0]);
+
+ return oTarget;
+ };
+
+ ko.extenders.toggleSubscribeProperty = function (oTarget, oOptions)
+ {
+ var sProp = oOptions[1];
+
+ if (sProp)
+ {
+ oTarget.subscribe(function (oPrev) {
+ if (oPrev && oPrev[sProp])
+ {
+ oPrev[sProp](false);
+ }
+ }, oOptions[0], 'beforeChange');
+
+ oTarget.subscribe(function (oNext) {
+ if (oNext && oNext[sProp])
+ {
+ oNext[sProp](true);
+ }
+ }, oOptions[0]);
+ }
+
+ return oTarget;
+ };
+
+ ko.extenders.falseTimeout = function (oTarget, iOption)
+ {
+ oTarget.iFalseTimeoutTimeout = 0;
+ oTarget.subscribe(function (bValue) {
+ if (bValue)
+ {
+ window.clearTimeout(oTarget.iFalseTimeoutTimeout);
+ oTarget.iFalseTimeoutTimeout = window.setTimeout(function () {
+ oTarget(false);
+ oTarget.iFalseTimeoutTimeout = 0;
+ }, __webpack_require__(/*! Common/Utils */ 1).pInt(iOption));
+ }
+ });
+
+ return oTarget;
+ };
+
+ ko.extenders.specialThrottle = function (oTarget, iOption)
+ {
+ oTarget.iSpecialThrottleTimeoutValue = __webpack_require__(/*! Common/Utils */ 1).pInt(iOption);
+ if (0 < oTarget.iSpecialThrottleTimeoutValue)
+ {
+ oTarget.iSpecialThrottleTimeout = 0;
+ oTarget.valueForRead = ko.observable(!!oTarget()).extend({'throttle': 10});
+
+ return ko.computed({
+ 'read': oTarget.valueForRead,
+ 'write': function (bValue) {
+
+ if (bValue)
+ {
+ oTarget.valueForRead(bValue);
+ }
+ else
+ {
+ if (oTarget.valueForRead())
+ {
+ window.clearTimeout(oTarget.iSpecialThrottleTimeout);
+ oTarget.iSpecialThrottleTimeout = window.setTimeout(function () {
+ oTarget.valueForRead(false);
+ oTarget.iSpecialThrottleTimeout = 0;
+ }, oTarget.iSpecialThrottleTimeoutValue);
+ }
+ else
+ {
+ oTarget.valueForRead(bValue);
+ }
+ }
+ }
+ });
+ }
+
+ return oTarget;
+ };
+
+ // functions
+
+ ko.observable.fn.validateNone = function ()
+ {
+ this.hasError = ko.observable(false);
+ return this;
+ };
+
+ ko.observable.fn.validateEmail = function ()
+ {
+ var Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ this.hasError = ko.observable(false);
+
+ this.subscribe(function (sValue) {
+ sValue = Utils.trim(sValue);
+ this.hasError('' !== sValue && !(/^[^@\s]+@[^@\s]+$/.test(sValue)));
+ }, this);
+
+ this.valueHasMutated();
+ return this;
+ };
+
+ ko.observable.fn.validateSimpleEmail = function ()
+ {
+ var Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ this.hasError = ko.observable(false);
+
+ this.subscribe(function (sValue) {
+ sValue = Utils.trim(sValue);
+ this.hasError('' !== sValue && !(/^.+@.+$/.test(sValue)));
+ }, this);
+
+ this.valueHasMutated();
+ return this;
+ };
+
+ ko.observable.fn.deleteAccessHelper = function ()
+ {
+ this.extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [null,
+ function (oPrev) {
+ if (oPrev && oPrev.deleteAccess)
+ {
+ oPrev.deleteAccess(false);
+ }
+ }, function (oNext) {
+ if (oNext && oNext.deleteAccess)
+ {
+ oNext.deleteAccess(true);
+ }
+ }
+ ]});
+
+ return this;
+ };
+
+ ko.observable.fn.validateFunc = function (fFunc)
+ {
+ var Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ this.hasFuncError = ko.observable(false);
+
+ if (Utils.isFunc(fFunc))
+ {
+ this.subscribe(function (sValue) {
+ this.hasFuncError(!fFunc(sValue));
+ }, this);
+
+ this.valueHasMutated();
+ }
+
+ return this;
+ };
+
+ module.exports = ko;
+
+ }(ko));
+
+
+/***/ },
+/* 3 */
+/*!***************************!*\
+ !*** external "window._" ***!
+ \***************************/
+/***/ function(module, exports) {
+
+ module.exports = window._;
+
+/***/ },
+/* 4 */
+/*!******************************!*\
+ !*** ./dev/Common/Enums.jsx ***!
+ \******************************/
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ /* eslint quote-props: 0 */
+
+ /**
+ * @enum {string}
+ */
+ var FileType = exports.FileType = {
+ 'Unknown': 'unknown',
+ 'Text': 'text',
+ 'Html': 'html',
+ 'Code': 'code',
+ 'Eml': 'eml',
+ 'WordText': 'word-text',
+ 'Pdf': 'pdf',
+ 'Image': 'image',
+ 'Audio': 'audio',
+ 'Video': 'video',
+ 'Sheet': 'sheet',
+ 'Presentation': 'presentation',
+ 'Certificate': 'certificate',
+ 'CertificateBin': 'certificate-bin',
+ 'Archive': 'archive'
+ };
+
+ /**
+ * @enum {string}
+ */
+ var StorageResultType = exports.StorageResultType = {
+ 'Success': 'success',
+ 'Abort': 'abort',
+ 'Error': 'error',
+ 'Unload': 'unload'
+ };
+
+ /**
+ * @enum {string}
+ */
+ var Focused = exports.Focused = {
+ 'None': 'none',
+ 'MessageList': 'message-list',
+ 'MessageView': 'message-view',
+ 'FolderList': 'folder-list'
+ };
+
+ /**
+ * @enum {number}
+ */
+ var State = exports.State = {
+ 'Empty': 10,
+ 'Login': 20,
+ 'Auth': 30
+ };
+
+ /**
+ * @enum {number}
+ */
+ var StateType = exports.StateType = {
+ 'Webmail': 0,
+ 'Admin': 1
+ };
+
+ /**
+ * @enum {string}
+ */
+ var Capa = exports.Capa = {
+ 'TwoFactor': 'TWO_FACTOR',
+ 'TwoFactorForce': 'TWO_FACTOR_FORCE',
+ 'OpenPGP': 'OPEN_PGP',
+ 'Prefetch': 'PREFETCH',
+ 'Gravatar': 'GRAVATAR',
+ 'Folders': 'FOLDERS',
+ 'Composer': 'COMPOSER',
+ 'Contacts': 'CONTACTS',
+ 'Reload': 'RELOAD',
+ 'Search': 'SEARCH',
+ 'SearchAdv': 'SEARCH_ADV',
+ 'MessageActions': 'MESSAGE_ACTIONS',
+ 'MessageListActions': 'MESSAGELIST_ACTIONS',
+ 'AttachmentsActions': 'ATTACHMENTS_ACTIONS',
+ 'DangerousActions': 'DANGEROUS_ACTIONS',
+ 'Settings': 'SETTINGS',
+ 'Help': 'HELP',
+ 'Themes': 'THEMES',
+ 'UserBackground': 'USER_BACKGROUND',
+ 'Sieve': 'SIEVE',
+ 'Filters': 'FILTERS',
+ 'AttachmentThumbnails': 'ATTACHMENT_THUMBNAILS',
+ 'Templates': 'TEMPLATES',
+ 'AutoLogout': 'AUTOLOGOUT',
+ 'AdditionalAccounts': 'ADDITIONAL_ACCOUNTS',
+ 'Identities': 'IDENTITIES'
+ };
+
+ /**
+ * @enum {string}
+ */
+ var KeyState = exports.KeyState = {
+ 'All': 'all',
+ 'None': 'none',
+ 'ContactList': 'contact-list',
+ 'MessageList': 'message-list',
+ 'FolderList': 'folder-list',
+ 'MessageView': 'message-view',
+ 'Compose': 'compose',
+ 'Settings': 'settings',
+ 'Menu': 'menu',
+ 'PopupComposeOpenPGP': 'compose-open-pgp',
+ 'PopupMessageOpenPGP': 'message-open-pgp',
+ 'PopupViewOpenPGP': 'view-open-pgp',
+ 'PopupKeyboardShortcutsHelp': 'popup-keyboard-shortcuts-help',
+ 'PopupAsk': 'popup-ask'
+ };
+
+ /**
+ * @enum {number}
+ */
+ var FolderType = exports.FolderType = {
+ 'Inbox': 10,
+ 'SentItems': 11,
+ 'Draft': 12,
+ 'Trash': 13,
+ 'Spam': 14,
+ 'Archive': 15,
+ 'NotSpam': 80,
+ 'User': 99
+ };
+
+ /**
+ * @enum {number}
+ */
+ var ServerFolderType = exports.ServerFolderType = {
+ 'USER': 0,
+ 'INBOX': 1,
+ 'SENT': 2,
+ 'DRAFTS': 3,
+ 'JUNK': 4,
+ 'TRASH': 5,
+ 'IMPORTANT': 10,
+ 'FLAGGED': 11,
+ 'ALL': 12
+ };
+
+ /**
+ * @enum {string}
+ */
+ var LoginSignMeTypeAsString = exports.LoginSignMeTypeAsString = {
+ 'DefaultOff': 'defaultoff',
+ 'DefaultOn': 'defaulton',
+ 'Unused': 'unused'
+ };
+
+ /**
+ * @enum {number}
+ */
+ var LoginSignMeType = exports.LoginSignMeType = {
+ 'DefaultOff': 0,
+ 'DefaultOn': 1,
+ 'Unused': 2
+ };
+
+ /**
+ * @enum {string}
+ */
+ var ComposeType = exports.ComposeType = {
+ 'Empty': 'empty',
+ 'Reply': 'reply',
+ 'ReplyAll': 'replyall',
+ 'Forward': 'forward',
+ 'ForwardAsAttachment': 'forward-as-attachment',
+ 'Draft': 'draft',
+ 'EditAsNew': 'editasnew'
+ };
+
+ /**
+ * @enum {number}
+ */
+ var UploadErrorCode = exports.UploadErrorCode = {
+ 'Normal': 0,
+ 'FileIsTooBig': 1,
+ 'FilePartiallyUploaded': 2,
+ 'FileNoUploaded': 3,
+ 'MissingTempFolder': 4,
+ 'FileOnSaveingError': 5,
+ 'FileType': 98,
+ 'Unknown': 99
+ };
+
+ /**
+ * @enum {number}
+ */
+ var SetSystemFoldersNotification = exports.SetSystemFoldersNotification = {
+ 'None': 0,
+ 'Sent': 1,
+ 'Draft': 2,
+ 'Spam': 3,
+ 'Trash': 4,
+ 'Archive': 5
+ };
+
+ /**
+ * @enum {number}
+ */
+ var ClientSideKeyName = exports.ClientSideKeyName = {
+ 'FoldersLashHash': 0,
+ 'MessagesInboxLastHash': 1,
+ 'MailBoxListSize': 2,
+ 'ExpandedFolders': 3,
+ 'FolderListSize': 4,
+ 'MessageListSize': 5,
+ 'LastReplyAction': 6,
+ 'LastSignMe': 7,
+ 'ComposeLastIdentityID': 8
+ };
+
+ /**
+ * @enum {number}
+ */
+ var EventKeyCode = exports.EventKeyCode = {
+ 'Backspace': 8,
+ 'Tab': 9,
+ 'Enter': 13,
+ 'Esc': 27,
+ 'PageUp': 33,
+ 'PageDown': 34,
+ 'Left': 37,
+ 'Right': 39,
+ 'Up': 38,
+ 'Down': 40,
+ 'End': 35,
+ 'Home': 36,
+ 'Space': 32,
+ 'Insert': 45,
+ 'Delete': 46,
+ 'A': 65,
+ 'S': 83
+ };
+
+ /**
+ * @enum {number}
+ */
+ var MessageSetAction = exports.MessageSetAction = {
+ 'SetSeen': 0,
+ 'UnsetSeen': 1,
+ 'SetFlag': 2,
+ 'UnsetFlag': 3
+ };
+
+ /**
+ * @enum {number}
+ */
+ var MessageSelectAction = exports.MessageSelectAction = {
+ 'All': 0,
+ 'None': 1,
+ 'Invert': 2,
+ 'Unseen': 3,
+ 'Seen': 4,
+ 'Flagged': 5,
+ 'Unflagged': 6
+ };
+
+ /**
+ * @enum {number}
+ */
+ var DesktopNotification = exports.DesktopNotification = {
+ 'Allowed': 0,
+ 'NotAllowed': 1,
+ 'Denied': 2,
+ 'NotSupported': 9
+ };
+
+ /**
+ * @enum {number}
+ */
+ var MessagePriority = exports.MessagePriority = {
+ 'Low': 5,
+ 'Normal': 3,
+ 'High': 1
+ };
+
+ /**
+ * @enum {string}
+ */
+ var EditorDefaultType = exports.EditorDefaultType = {
+ 'Html': 'Html',
+ 'Plain': 'Plain',
+ 'HtmlForced': 'HtmlForced',
+ 'PlainForced': 'PlainForced'
+ };
+
+ /**
+ * @enum {number}
+ */
+ var ServerSecure = exports.ServerSecure = {
+ 'None': 0,
+ 'SSL': 1,
+ 'TLS': 2
+ };
+
+ /**
+ * @enum {number}
+ */
+ var SearchDateType = exports.SearchDateType = {
+ 'All': -1,
+ 'Days3': 3,
+ 'Days7': 7,
+ 'Month': 30
+ };
+
+ /**
+ * @enum {number}
+ */
+ var SaveSettingsStep = exports.SaveSettingsStep = {
+ 'Animate': -2,
+ 'Idle': -1,
+ 'TrueResult': 1,
+ 'FalseResult': 0
+ };
+
+ /**
+ * @enum {number}
+ */
+ var Layout = exports.Layout = {
+ 'NoPreview': 0,
+ 'SidePreview': 1,
+ 'BottomPreview': 2,
+ 'Mobile': 3
+ };
+
+ /**
+ * @enum {string}
+ */
+ var FilterConditionField = exports.FilterConditionField = {
+ 'From': 'From',
+ 'Recipient': 'Recipient',
+ 'Subject': 'Subject',
+ 'Header': 'Header',
+ 'Size': 'Size'
+ };
+
+ /**
+ * @enum {string}
+ */
+ var FilterConditionType = exports.FilterConditionType = {
+ 'Contains': 'Contains',
+ 'NotContains': 'NotContains',
+ 'EqualTo': 'EqualTo',
+ 'NotEqualTo': 'NotEqualTo',
+ 'Over': 'Over',
+ 'Under': 'Under'
+ };
+
+ /**
+ * @enum {string}
+ */
+ var FiltersAction = exports.FiltersAction = {
+ 'None': 'None',
+ 'MoveTo': 'MoveTo',
+ 'Discard': 'Discard',
+ 'Vacation': 'Vacation',
+ 'Reject': 'Reject',
+ 'Forward': 'Forward'
+ };
+
+ /**
+ * @enum {string}
+ */
+ var FilterRulesType = exports.FilterRulesType = {
+ 'All': 'All',
+ 'Any': 'Any'
+ };
+
+ /**
+ * @enum {number}
+ */
+ var SignedVerifyStatus = exports.SignedVerifyStatus = {
+ 'UnknownPublicKeys': -4,
+ 'UnknownPrivateKey': -3,
+ 'Unverified': -2,
+ 'Error': -1,
+ 'None': 0,
+ 'Success': 1
+ };
+
+ /**
+ * @enum {number}
+ */
+ var ContactPropertyType = exports.ContactPropertyType = {
+
+ 'Unknown': 0,
+
+ 'FullName': 10,
+
+ 'FirstName': 15,
+ 'LastName': 16,
+ 'MiddleName': 16,
+ 'Nick': 18,
+
+ 'NamePrefix': 20,
+ 'NameSuffix': 21,
+
+ 'Email': 30,
+ 'Phone': 31,
+ 'Web': 32,
+
+ 'Birthday': 40,
+
+ 'Facebook': 90,
+ 'Skype': 91,
+ 'GitHub': 92,
+
+ 'Note': 110,
+
+ 'Custom': 250
+ };
+
+ /**
+ * @enum {number}
+ */
+ var Notification = exports.Notification = {
+ 'InvalidToken': 101,
+ 'AuthError': 102,
+ 'AccessError': 103,
+ 'ConnectionError': 104,
+ 'CaptchaError': 105,
+ 'SocialFacebookLoginAccessDisable': 106,
+ 'SocialTwitterLoginAccessDisable': 107,
+ 'SocialGoogleLoginAccessDisable': 108,
+ 'DomainNotAllowed': 109,
+ 'AccountNotAllowed': 110,
+
+ 'AccountTwoFactorAuthRequired': 120,
+ 'AccountTwoFactorAuthError': 121,
+
+ 'CouldNotSaveNewPassword': 130,
+ 'CurrentPasswordIncorrect': 131,
+ 'NewPasswordShort': 132,
+ 'NewPasswordWeak': 133,
+ 'NewPasswordForbidden': 134,
+
+ 'ContactsSyncError': 140,
+
+ 'CantGetMessageList': 201,
+ 'CantGetMessage': 202,
+ 'CantDeleteMessage': 203,
+ 'CantMoveMessage': 204,
+ 'CantCopyMessage': 205,
+
+ 'CantSaveMessage': 301,
+ 'CantSendMessage': 302,
+ 'InvalidRecipients': 303,
+
+ 'CantSaveFilters': 351,
+ 'CantGetFilters': 352,
+ 'FiltersAreNotCorrect': 355,
+
+ 'CantCreateFolder': 400,
+ 'CantRenameFolder': 401,
+ 'CantDeleteFolder': 402,
+ 'CantSubscribeFolder': 403,
+ 'CantUnsubscribeFolder': 404,
+ 'CantDeleteNonEmptyFolder': 405,
+
+ 'CantSaveSettings': 501,
+ 'CantSavePluginSettings': 502,
+
+ 'DomainAlreadyExists': 601,
+
+ 'CantInstallPackage': 701,
+ 'CantDeletePackage': 702,
+ 'InvalidPluginPackage': 703,
+ 'UnsupportedPluginPackage': 704,
+
+ 'LicensingServerIsUnavailable': 710,
+ 'LicensingExpired': 711,
+ 'LicensingBanned': 712,
+
+ 'DemoSendMessageError': 750,
+ 'DemoAccountError': 751,
+
+ 'AccountAlreadyExists': 801,
+ 'AccountDoesNotExist': 802,
+
+ 'MailServerError': 901,
+ 'ClientViewError': 902,
+ 'InvalidInputArgument': 903,
+
+ 'AjaxFalse': 950,
+ 'AjaxAbort': 951,
+ 'AjaxParse': 952,
+ 'AjaxTimeout': 953,
+
+ 'UnknownNotification': 999,
+ 'UnknownError': 999
+ };
+
+/***/ },
+/* 5 */
+/*!****************************!*\
+ !*** ./dev/Knoin/Knoin.js ***!
+ \****************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+ hasher = __webpack_require__(/*! hasher */ 81),
+ crossroads = __webpack_require__(/*! crossroads */ 49),
+
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Plugins = __webpack_require__(/*! Common/Plugins */ 23),
+ Utils = __webpack_require__(/*! Common/Utils */ 1)
+ ;
+
+ /**
+ * @constructor
+ */
+ function Knoin()
+ {
+ this.oScreens = {};
+ this.sDefaultScreenName = '';
+ this.oCurrentScreen = null;
+ }
+
+ Knoin.prototype.oScreens = {};
+ Knoin.prototype.sDefaultScreenName = '';
+ Knoin.prototype.oCurrentScreen = null;
+
+ Knoin.prototype.hideLoading = function ()
+ {
+ $('#rl-content').show();
+ $('#rl-loading').hide().remove();
+ };
+
+ /**
+ * @param {Object} thisObject
+ */
+ Knoin.prototype.constructorEnd = function (thisObject)
+ {
+ if (Utils.isFunc(thisObject['__constructor_end']))
+ {
+ thisObject['__constructor_end'].call(thisObject);
+ }
+ };
+
+ /**
+ * @param {string|Array} mName
+ * @param {Function} ViewModelClass
+ */
+ Knoin.prototype.extendAsViewModel = function (mName, ViewModelClass)
+ {
+ if (ViewModelClass)
+ {
+ if (Utils.isArray(mName))
+ {
+ ViewModelClass.__names = mName;
+ }
+ else
+ {
+ ViewModelClass.__names = [mName];
+ }
+
+ ViewModelClass.__name = ViewModelClass.__names[0];
+ }
+ };
+
+ /**
+ * @param {Function} SettingsViewModelClass
+ * @param {string} sLabelName
+ * @param {string} sTemplate
+ * @param {string} sRoute
+ * @param {boolean=} bDefault
+ */
+ Knoin.prototype.addSettingsViewModel = function (SettingsViewModelClass, sTemplate, sLabelName, sRoute, bDefault)
+ {
+ SettingsViewModelClass.__rlSettingsData = {
+ 'Label': sLabelName,
+ 'Template': sTemplate,
+ 'Route': sRoute,
+ 'IsDefault': !!bDefault
+ };
+
+ Globals.aViewModels['settings'].push(SettingsViewModelClass);
+ };
+
+ /**
+ * @param {Function} SettingsViewModelClass
+ */
+ Knoin.prototype.removeSettingsViewModel = function (SettingsViewModelClass)
+ {
+ Globals.aViewModels['settings-removed'].push(SettingsViewModelClass);
+ };
+
+ /**
+ * @param {Function} SettingsViewModelClass
+ */
+ Knoin.prototype.disableSettingsViewModel = function (SettingsViewModelClass)
+ {
+ Globals.aViewModels['settings-disabled'].push(SettingsViewModelClass);
+ };
+
+ Knoin.prototype.routeOff = function ()
+ {
+ hasher.changed.active = false;
+ };
+
+ Knoin.prototype.routeOn = function ()
+ {
+ hasher.changed.active = true;
+ };
+
+ /**
+ * @param {string} sScreenName
+ * @return {?Object}
+ */
+ Knoin.prototype.screen = function (sScreenName)
+ {
+ return ('' !== sScreenName && !Utils.isUnd(this.oScreens[sScreenName])) ? this.oScreens[sScreenName] : null;
+ };
+
+ /**
+ * @param {Function} ViewModelClass
+ * @param {Object=} oScreen
+ */
+ Knoin.prototype.buildViewModel = function (ViewModelClass, oScreen)
+ {
+ if (ViewModelClass && !ViewModelClass.__builded)
+ {
+ var
+ kn = this,
+ oViewModel = new ViewModelClass(oScreen),
+ sPosition = oViewModel.viewModelPosition(),
+ oViewModelPlace = $('#rl-content #rl-' + sPosition.toLowerCase()),
+ oViewModelDom = null
+ ;
+
+ ViewModelClass.__builded = true;
+ ViewModelClass.__vm = oViewModel;
+
+ oViewModel.onShowTrigger = ko.observable(false);
+ oViewModel.onHideTrigger = ko.observable(false);
+
+ oViewModel.viewModelName = ViewModelClass.__name;
+ oViewModel.viewModelNames = ViewModelClass.__names;
+
+ if (oViewModelPlace && 1 === oViewModelPlace.length)
+ {
+ oViewModelDom = $('
').addClass('rl-view-model').addClass('RL-' + oViewModel.viewModelTemplate()).hide();
+ oViewModelDom.appendTo(oViewModelPlace);
+
+ oViewModel.viewModelDom = oViewModelDom;
+ ViewModelClass.__dom = oViewModelDom;
+
+ if ('Popups' === sPosition)
+ {
+ oViewModel.cancelCommand = oViewModel.closeCommand = Utils.createCommand(oViewModel, function () {
+ kn.hideScreenPopup(ViewModelClass);
+ });
+
+ oViewModel.modalVisibility.subscribe(function (bValue) {
+
+ var self = this;
+ if (bValue)
+ {
+ this.viewModelDom.show();
+ this.storeAndSetKeyScope();
+
+ Globals.popupVisibilityNames.push(this.viewModelName);
+ oViewModel.viewModelDom.css('z-index', 3000 + Globals.popupVisibilityNames().length + 10);
+
+ if (this.onShowTrigger)
+ {
+ this.onShowTrigger(!this.onShowTrigger());
+ }
+
+ Utils.delegateRun(this, 'onShowWithDelay', [], 500);
+ }
+ else
+ {
+ Utils.delegateRun(this, 'onHide');
+ Utils.delegateRun(this, 'onHideWithDelay', [], 500);
+
+ if (this.onHideTrigger)
+ {
+ this.onHideTrigger(!this.onHideTrigger());
+ }
+
+ this.restoreKeyScope();
+
+ _.each(this.viewModelNames, function (sName) {
+ Plugins.runHook('view-model-on-hide', [sName, self]);
+ });
+
+ Globals.popupVisibilityNames.remove(this.viewModelName);
+ oViewModel.viewModelDom.css('z-index', 2000);
+
+ _.delay(function () {
+ self.viewModelDom.hide();
+ }, 300);
+ }
+
+ }, oViewModel);
+ }
+
+ _.each(ViewModelClass.__names, function (sName) {
+ Plugins.runHook('view-model-pre-build', [sName, oViewModel, oViewModelDom]);
+ });
+
+ ko.applyBindingAccessorsToNode(oViewModelDom[0], {
+ 'translatorInit': true,
+ 'template': function () { return {'name': oViewModel.viewModelTemplate()};}
+ }, oViewModel);
+
+ Utils.delegateRun(oViewModel, 'onBuild', [oViewModelDom]);
+ if (oViewModel && 'Popups' === sPosition)
+ {
+ oViewModel.registerPopupKeyDown();
+ }
+
+ _.each(ViewModelClass.__names, function (sName) {
+ Plugins.runHook('view-model-post-build', [sName, oViewModel, oViewModelDom]);
+ });
+ }
+ else
+ {
+ Utils.log('Cannot find view model position: ' + sPosition);
+ }
+ }
+
+ return ViewModelClass ? ViewModelClass.__vm : null;
+ };
+
+ /**
+ * @param {Function} ViewModelClassToHide
+ */
+ Knoin.prototype.hideScreenPopup = function (ViewModelClassToHide)
+ {
+ if (ViewModelClassToHide && ViewModelClassToHide.__vm && ViewModelClassToHide.__dom)
+ {
+ ViewModelClassToHide.__vm.modalVisibility(false);
+ }
+ };
+
+ /**
+ * @param {Function} ViewModelClassToShow
+ * @param {Array=} aParameters
+ */
+ Knoin.prototype.showScreenPopup = function (ViewModelClassToShow, aParameters)
+ {
+ if (ViewModelClassToShow)
+ {
+ this.buildViewModel(ViewModelClassToShow);
+
+ if (ViewModelClassToShow.__vm && ViewModelClassToShow.__dom)
+ {
+ Utils.delegateRun(ViewModelClassToShow.__vm, 'onBeforeShow', aParameters || []);
+
+ ViewModelClassToShow.__vm.modalVisibility(true);
+
+ Utils.delegateRun(ViewModelClassToShow.__vm, 'onShow', aParameters || []);
+
+ _.each(ViewModelClassToShow.__names, function (sName) {
+ Plugins.runHook('view-model-on-show', [sName, ViewModelClassToShow.__vm, aParameters || []]);
+ });
+ }
+ }
+ };
+
+ /**
+ * @param {Function} ViewModelClassToShow
+ * @return {boolean}
+ */
+ Knoin.prototype.isPopupVisible = function (ViewModelClassToShow)
+ {
+ return ViewModelClassToShow && ViewModelClassToShow.__vm ? ViewModelClassToShow.__vm.modalVisibility() : false;
+ };
+
+ /**
+ * @param {string} sScreenName
+ * @param {string} sSubPart
+ */
+ Knoin.prototype.screenOnRoute = function (sScreenName, sSubPart)
+ {
+ var
+ self = this,
+ oScreen = null,
+ bSameScreen= false,
+ oCross = null
+ ;
+
+ if ('' === Utils.pString(sScreenName))
+ {
+ sScreenName = this.sDefaultScreenName;
+ }
+
+ if ('' !== sScreenName)
+ {
+ oScreen = this.screen(sScreenName);
+ if (!oScreen)
+ {
+ oScreen = this.screen(this.sDefaultScreenName);
+ if (oScreen)
+ {
+ sSubPart = sScreenName + '/' + sSubPart;
+ sScreenName = this.sDefaultScreenName;
+ }
+ }
+
+ if (oScreen && oScreen.__started)
+ {
+ bSameScreen = this.oCurrentScreen && oScreen === this.oCurrentScreen;
+
+ if (!oScreen.__builded)
+ {
+ oScreen.__builded = true;
+
+ if (Utils.isNonEmptyArray(oScreen.viewModels()))
+ {
+ _.each(oScreen.viewModels(), function (ViewModelClass) {
+ this.buildViewModel(ViewModelClass, oScreen);
+ }, this);
+ }
+
+ Utils.delegateRun(oScreen, 'onBuild');
+ }
+
+ _.defer(function () {
+
+ // hide screen
+ if (self.oCurrentScreen && !bSameScreen)
+ {
+ Utils.delegateRun(self.oCurrentScreen, 'onHide');
+ Utils.delegateRun(self.oCurrentScreen, 'onHideWithDelay', [], 500);
+
+ if (self.oCurrentScreen.onHideTrigger)
+ {
+ self.oCurrentScreen.onHideTrigger(!self.oCurrentScreen.onHideTrigger());
+ }
+
+ if (Utils.isNonEmptyArray(self.oCurrentScreen.viewModels()))
+ {
+ _.each(self.oCurrentScreen.viewModels(), function (ViewModelClass) {
+
+ if (ViewModelClass.__vm && ViewModelClass.__dom &&
+ 'Popups' !== ViewModelClass.__vm.viewModelPosition())
+ {
+ ViewModelClass.__dom.hide();
+ ViewModelClass.__vm.viewModelVisibility(false);
+
+ Utils.delegateRun(ViewModelClass.__vm, 'onHide');
+ Utils.delegateRun(ViewModelClass.__vm, 'onHideWithDelay', [], 500);
+
+ if (ViewModelClass.__vm.onHideTrigger)
+ {
+ ViewModelClass.__vm.onHideTrigger(!ViewModelClass.__vm.onHideTrigger());
+ }
+ }
+
+ });
+ }
+ }
+ // --
+
+ self.oCurrentScreen = oScreen;
+
+ // show screen
+ if (self.oCurrentScreen && !bSameScreen)
+ {
+ Utils.delegateRun(self.oCurrentScreen, 'onShow');
+ if (self.oCurrentScreen.onShowTrigger)
+ {
+ self.oCurrentScreen.onShowTrigger(!self.oCurrentScreen.onShowTrigger());
+ }
+
+ Plugins.runHook('screen-on-show', [self.oCurrentScreen.screenName(), self.oCurrentScreen]);
+
+ if (Utils.isNonEmptyArray(self.oCurrentScreen.viewModels()))
+ {
+ _.each(self.oCurrentScreen.viewModels(), function (ViewModelClass) {
+
+ if (ViewModelClass.__vm && ViewModelClass.__dom &&
+ 'Popups' !== ViewModelClass.__vm.viewModelPosition())
+ {
+ Utils.delegateRun(ViewModelClass.__vm, 'onBeforeShow');
+
+ ViewModelClass.__dom.show();
+ ViewModelClass.__vm.viewModelVisibility(true);
+
+ Utils.delegateRun(ViewModelClass.__vm, 'onShow');
+ if (ViewModelClass.__vm.onShowTrigger)
+ {
+ ViewModelClass.__vm.onShowTrigger(!ViewModelClass.__vm.onShowTrigger());
+ }
+
+ Utils.delegateRun(ViewModelClass.__vm, 'onShowWithDelay', [], 200);
+
+ _.each(ViewModelClass.__names, function (sName) {
+ Plugins.runHook('view-model-on-show', [sName, ViewModelClass.__vm]);
+ });
+ }
+
+ }, self);
+ }
+ }
+ // --
+
+ oCross = oScreen.__cross ? oScreen.__cross() : null;
+ if (oCross)
+ {
+ oCross.parse(sSubPart);
+ }
+ });
+ }
+ }
+ };
+
+ /**
+ * @param {Array} aScreensClasses
+ */
+ Knoin.prototype.startScreens = function (aScreensClasses)
+ {
+ $('#rl-content').css({
+ 'visibility': 'hidden'
+ });
+
+ _.each(aScreensClasses, function (CScreen) {
+
+ if (CScreen)
+ {
+ var
+ oScreen = new CScreen(),
+ sScreenName = oScreen ? oScreen.screenName() : ''
+ ;
+
+ if (oScreen && '' !== sScreenName)
+ {
+ if ('' === this.sDefaultScreenName)
+ {
+ this.sDefaultScreenName = sScreenName;
+ }
+
+ this.oScreens[sScreenName] = oScreen;
+ }
+ }
+
+ }, this);
+
+
+ _.each(this.oScreens, function (oScreen) {
+ if (oScreen && !oScreen.__started && oScreen.__start)
+ {
+ oScreen.__started = true;
+ oScreen.__start();
+
+ Plugins.runHook('screen-pre-start', [oScreen.screenName(), oScreen]);
+ Utils.delegateRun(oScreen, 'onStart');
+ Plugins.runHook('screen-post-start', [oScreen.screenName(), oScreen]);
+ }
+ }, this);
+
+ var oCross = crossroads.create();
+ oCross.addRoute(/^([a-zA-Z0-9\-]*)\/?(.*)$/, _.bind(this.screenOnRoute, this));
+
+ hasher.initialized.add(oCross.parse, oCross);
+ hasher.changed.add(oCross.parse, oCross);
+ hasher.init();
+
+ $('#rl-content').css({
+ 'visibility': 'visible'
+ });
+
+ _.delay(function () {
+ Globals.$html.removeClass('rl-started-trigger').addClass('rl-started');
+ }, 100);
+
+ _.delay(function () {
+ Globals.$html.addClass('rl-started-delay');
+ }, 200);
+ };
+
+ /**
+ * @param {string} sHash
+ * @param {boolean=} bSilence = false
+ * @param {boolean=} bReplace = false
+ */
+ Knoin.prototype.setHash = function (sHash, bSilence, bReplace)
+ {
+ sHash = '#' === sHash.substr(0, 1) ? sHash.substr(1) : sHash;
+ sHash = '/' === sHash.substr(0, 1) ? sHash.substr(1) : sHash;
+
+ bReplace = Utils.isUnd(bReplace) ? false : !!bReplace;
+
+ if (Utils.isUnd(bSilence) ? false : !!bSilence)
+ {
+ hasher.changed.active = false;
+ hasher[bReplace ? 'replaceHash' : 'setHash'](sHash);
+ hasher.changed.active = true;
+ }
+ else
+ {
+ hasher.changed.active = true;
+ hasher[bReplace ? 'replaceHash' : 'setHash'](sHash);
+ hasher.setHash(sHash);
+ }
+ };
+
+ module.exports = new Knoin();
+
+ }());
+
+/***/ },
+/* 6 */
+/*!***********************************!*\
+ !*** ./dev/Common/Translator.jsx ***!
+ \***********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Enums = __webpack_require__(/*! Common/Enums */ 4);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ var _Globals2 = _interopRequireDefault(_Globals);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var Translator = function () {
+ function Translator() {
+ _classCallCheck(this, Translator);
+
+ this.data = {};
+ this.notificationI18N = {};
+
+ this.data = _common.window.rainloopI18N || {};
+ this.trigger = _ko2.default.observable(false);
+ this.i18n = _common._.bind(this.i18n, this);
+ this.init();
+ }
+
+ /**
+ * @param {string} key
+ * @param {Object=} valueList
+ * @param {string=} defaulValue
+ * @return {string}
+ */
+
+
+ Translator.prototype.i18n = function i18n(key, valueList, defaulValue) {
+
+ var valueName = '',
+ result = this.data[key];
+
+ if (_common._.isUndefined(result)) {
+ result = _common._.isUndefined(defaulValue) ? key : defaulValue;
+ }
+
+ if (!_common._.isUndefined(valueList) && !_common._.isNull(valueList)) {
+ for (valueName in valueList) {
+ if (_common._.has(valueList, valueName)) {
+ result = result.replace('%' + valueName + '%', valueList[valueName]);
+ }
+ }
+ }
+
+ return result;
+ };
+
+ /**
+ * @param {Object} element
+ */
+
+
+ Translator.prototype.i18nToNode = function i18nToNode(element) {
+
+ var $el = (0, _common.$)(element),
+ key = $el.data('i18n');
+
+ if (key) {
+ if ('[' === key.substr(0, 1)) {
+ switch (key.substr(0, 6)) {
+ case '[html]':
+ $el.html(this.i18n(key.substr(6)));
+ break;
+ case '[place':
+ $el.attr('placeholder', this.i18n(key.substr(13)));
+ break;
+ case '[title':
+ $el.attr('title', this.i18n(key.substr(7)));
+ break;
+ }
+ } else {
+ $el.text(this.i18n(key));
+ }
+ }
+ };
+
+ /**
+ * @param {Object} elements
+ * @param {boolean=} animate = false
+ */
+
+
+ Translator.prototype.i18nToNodes = function i18nToNodes(elements) {
+ var _this = this;
+
+ var animate = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
+
+ _common._.defer(function () {
+
+ (0, _common.$)('[data-i18n]', elements).each(function (index, item) {
+ _this.i18nToNode(item);
+ });
+
+ if (animate && _Globals2.default.bAnimationSupported) {
+ (0, _common.$)('.i18n-animation[data-i18n]', elements).letterfx({
+ fx: 'fall fade',
+ backwards: false,
+ timing: 50,
+ fx_duration: '50ms',
+ letter_end: 'restore',
+ element_end: 'restore'
+ });
+ }
+ });
+ };
+
+ Translator.prototype.reloadData = function reloadData() {
+ if (_common.window.rainloopI18N) {
+ this.data = _common.window.rainloopI18N || {};
+
+ this.i18nToNodes(_common.window.document, true);
+
+ __webpack_require__(/*! Common/Momentor */ 26).reload();
+ this.trigger(!this.trigger());
+ }
+
+ _common.window.rainloopI18N = null;
+ };
+
+ Translator.prototype.initNotificationLanguage = function initNotificationLanguage() {
+ var _this2 = this;
+
+ var map = [[_Enums.Notification.InvalidToken, 'NOTIFICATIONS/INVALID_TOKEN'], [_Enums.Notification.InvalidToken, 'NOTIFICATIONS/INVALID_TOKEN'], [_Enums.Notification.AuthError, 'NOTIFICATIONS/AUTH_ERROR'], [_Enums.Notification.AccessError, 'NOTIFICATIONS/ACCESS_ERROR'], [_Enums.Notification.ConnectionError, 'NOTIFICATIONS/CONNECTION_ERROR'], [_Enums.Notification.CaptchaError, 'NOTIFICATIONS/CAPTCHA_ERROR'], [_Enums.Notification.SocialFacebookLoginAccessDisable, 'NOTIFICATIONS/SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE'], [_Enums.Notification.SocialTwitterLoginAccessDisable, 'NOTIFICATIONS/SOCIAL_TWITTER_LOGIN_ACCESS_DISABLE'], [_Enums.Notification.SocialGoogleLoginAccessDisable, 'NOTIFICATIONS/SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE'], [_Enums.Notification.DomainNotAllowed, 'NOTIFICATIONS/DOMAIN_NOT_ALLOWED'], [_Enums.Notification.AccountNotAllowed, 'NOTIFICATIONS/ACCOUNT_NOT_ALLOWED'], [_Enums.Notification.AccountTwoFactorAuthRequired, 'NOTIFICATIONS/ACCOUNT_TWO_FACTOR_AUTH_REQUIRED'], [_Enums.Notification.AccountTwoFactorAuthError, 'NOTIFICATIONS/ACCOUNT_TWO_FACTOR_AUTH_ERROR'], [_Enums.Notification.CouldNotSaveNewPassword, 'NOTIFICATIONS/COULD_NOT_SAVE_NEW_PASSWORD'], [_Enums.Notification.CurrentPasswordIncorrect, 'NOTIFICATIONS/CURRENT_PASSWORD_INCORRECT'], [_Enums.Notification.NewPasswordShort, 'NOTIFICATIONS/NEW_PASSWORD_SHORT'], [_Enums.Notification.NewPasswordWeak, 'NOTIFICATIONS/NEW_PASSWORD_WEAK'], [_Enums.Notification.NewPasswordForbidden, 'NOTIFICATIONS/NEW_PASSWORD_FORBIDDENT'], [_Enums.Notification.ContactsSyncError, 'NOTIFICATIONS/CONTACTS_SYNC_ERROR'], [_Enums.Notification.CantGetMessageList, 'NOTIFICATIONS/CANT_GET_MESSAGE_LIST'], [_Enums.Notification.CantGetMessage, 'NOTIFICATIONS/CANT_GET_MESSAGE'], [_Enums.Notification.CantDeleteMessage, 'NOTIFICATIONS/CANT_DELETE_MESSAGE'], [_Enums.Notification.CantMoveMessage, 'NOTIFICATIONS/CANT_MOVE_MESSAGE'], [_Enums.Notification.CantCopyMessage, 'NOTIFICATIONS/CANT_MOVE_MESSAGE'], [_Enums.Notification.CantSaveMessage, 'NOTIFICATIONS/CANT_SAVE_MESSAGE'], [_Enums.Notification.CantSendMessage, 'NOTIFICATIONS/CANT_SEND_MESSAGE'], [_Enums.Notification.InvalidRecipients, 'NOTIFICATIONS/INVALID_RECIPIENTS'], [_Enums.Notification.CantSaveFilters, 'NOTIFICATIONS/CANT_SAVE_FILTERS'], [_Enums.Notification.CantGetFilters, 'NOTIFICATIONS/CANT_GET_FILTERS'], [_Enums.Notification.FiltersAreNotCorrect, 'NOTIFICATIONS/FILTERS_ARE_NOT_CORRECT'], [_Enums.Notification.CantCreateFolder, 'NOTIFICATIONS/CANT_CREATE_FOLDER'], [_Enums.Notification.CantRenameFolder, 'NOTIFICATIONS/CANT_RENAME_FOLDER'], [_Enums.Notification.CantDeleteFolder, 'NOTIFICATIONS/CANT_DELETE_FOLDER'], [_Enums.Notification.CantDeleteNonEmptyFolder, 'NOTIFICATIONS/CANT_DELETE_NON_EMPTY_FOLDER'], [_Enums.Notification.CantSubscribeFolder, 'NOTIFICATIONS/CANT_SUBSCRIBE_FOLDER'], [_Enums.Notification.CantUnsubscribeFolder, 'NOTIFICATIONS/CANT_UNSUBSCRIBE_FOLDER'], [_Enums.Notification.CantSaveSettings, 'NOTIFICATIONS/CANT_SAVE_SETTINGS'], [_Enums.Notification.CantSavePluginSettings, 'NOTIFICATIONS/CANT_SAVE_PLUGIN_SETTINGS'], [_Enums.Notification.DomainAlreadyExists, 'NOTIFICATIONS/DOMAIN_ALREADY_EXISTS'], [_Enums.Notification.CantInstallPackage, 'NOTIFICATIONS/CANT_INSTALL_PACKAGE'], [_Enums.Notification.CantDeletePackage, 'NOTIFICATIONS/CANT_DELETE_PACKAGE'], [_Enums.Notification.InvalidPluginPackage, 'NOTIFICATIONS/INVALID_PLUGIN_PACKAGE'], [_Enums.Notification.UnsupportedPluginPackage, 'NOTIFICATIONS/UNSUPPORTED_PLUGIN_PACKAGE'], [_Enums.Notification.LicensingServerIsUnavailable, 'NOTIFICATIONS/LICENSING_SERVER_IS_UNAVAILABLE'], [_Enums.Notification.LicensingExpired, 'NOTIFICATIONS/LICENSING_EXPIRED'], [_Enums.Notification.LicensingBanned, 'NOTIFICATIONS/LICENSING_BANNED'], [_Enums.Notification.DemoSendMessageError, 'NOTIFICATIONS/DEMO_SEND_MESSAGE_ERROR'], [_Enums.Notification.DemoAccountError, 'NOTIFICATIONS/DEMO_ACCOUNT_ERROR'], [_Enums.Notification.AccountAlreadyExists, 'NOTIFICATIONS/ACCOUNT_ALREADY_EXISTS'], [_Enums.Notification.AccountDoesNotExist, 'NOTIFICATIONS/ACCOUNT_DOES_NOT_EXIST'], [_Enums.Notification.MailServerError, 'NOTIFICATIONS/MAIL_SERVER_ERROR'], [_Enums.Notification.InvalidInputArgument, 'NOTIFICATIONS/INVALID_INPUT_ARGUMENT'], [_Enums.Notification.UnknownNotification, 'NOTIFICATIONS/UNKNOWN_ERROR'], [_Enums.Notification.UnknownError, 'NOTIFICATIONS/UNKNOWN_ERROR']];
+
+ this.notificationI18N = this.notificationI18N || {};
+
+ map.forEach(function (item) {
+ _this2.notificationI18N[item[0]] = _this2.i18n(item[1]);
+ });
+ };
+
+ /**
+ * @param {Function} callback
+ * @param {Object} scope
+ * @param {Function=} langCallback
+ */
+
+
+ Translator.prototype.initOnStartOrLangChange = function initOnStartOrLangChange(callback, scope) {
+ var langCallback = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2];
+
+ if (callback) {
+ callback.call(scope);
+ }
+
+ if (langCallback) {
+ this.trigger.subscribe(function () {
+ if (callback) {
+ callback.call(scope);
+ }
+
+ langCallback.call(scope);
+ });
+ } else if (callback) {
+ this.trigger.subscribe(callback, scope);
+ }
+ };
+
+ /**
+ * @param {number} code
+ * @param {*=} message = ''
+ * @param {*=} defCode = null
+ * @return {string}
+ */
+
+
+ Translator.prototype.getNotification = function getNotification(code) {
+ var message = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1];
+ var defCode = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2];
+
+ code = _common.window.parseInt(code, 10) || 0;
+ if (_Enums.Notification.ClientViewError === code && message) {
+ return message;
+ }
+
+ defCode = defCode ? _common.window.parseInt(defCode, 10) || 0 : 0;
+ return _common._.isUndefined(this.notificationI18N[code]) ? defCode && _common._.isUndefined(this.notificationI18N[defCode]) ? this.notificationI18N[defCode] : '' : this.notificationI18N[code];
+ };
+
+ /**
+ * @param {object} response
+ * @param {number} defCode = Notification.UnknownNotification
+ * @return {string}
+ */
+
+
+ Translator.prototype.getNotificationFromResponse = function getNotificationFromResponse(response) {
+ var defCode = arguments.length <= 1 || arguments[1] === undefined ? _Enums.Notification.UnknownNotification : arguments[1];
+
+ return response && response.ErrorCode ? this.getNotification(_Utils2.default.pInt(response.ErrorCode), response.ErrorMessage || '') : this.getNotification(defCode);
+ };
+
+ /**
+ * @param {*} code
+ * @return {string}
+ */
+
+
+ Translator.prototype.getUploadErrorDescByCode = function getUploadErrorDescByCode(code) {
+ var result = '';
+ switch (_common.window.parseInt(code, 10) || 0) {
+ case _Enums.UploadErrorCode.FileIsTooBig:
+ result = this.i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG');
+ break;
+ case _Enums.UploadErrorCode.FilePartiallyUploaded:
+ result = this.i18n('UPLOAD/ERROR_FILE_PARTIALLY_UPLOADED');
+ break;
+ case _Enums.UploadErrorCode.FileNoUploaded:
+ result = this.i18n('UPLOAD/ERROR_NO_FILE_UPLOADED');
+ break;
+ case _Enums.UploadErrorCode.MissingTempFolder:
+ result = this.i18n('UPLOAD/ERROR_MISSING_TEMP_FOLDER');
+ break;
+ case _Enums.UploadErrorCode.FileOnSaveingError:
+ result = this.i18n('UPLOAD/ERROR_ON_SAVING_FILE');
+ break;
+ case _Enums.UploadErrorCode.FileType:
+ result = this.i18n('UPLOAD/ERROR_FILE_TYPE');
+ break;
+ default:
+ result = this.i18n('UPLOAD/ERROR_UNKNOWN');
+ break;
+ }
+
+ return result;
+ };
+
+ /**
+ * @param {boolean} admin
+ * @param {string} language
+ * @param {Function=} done
+ * @param {Function=} fail
+ */
+
+
+ Translator.prototype.reload = function reload(admin, language, done, fail) {
+
+ var self = this,
+ start = _Utils2.default.microtime();
+
+ _Globals2.default.$html.addClass('rl-changing-language');
+
+ _common.$.ajax({
+ url: __webpack_require__(/*! Common/Links */ 12).langLink(language, admin),
+ dataType: 'script',
+ cache: true
+ }).fail(fail || _Utils2.default.emptyFunction).done(function () {
+ _common._.delay(function () {
+
+ self.reloadData();
+
+ (done || _Utils2.default.emptyFunction)();
+
+ var isRtl = -1 < _Utils2.default.inArray(language, ['ar', 'ar_sa', 'he', 'he_he', 'ur', 'ur_ir']);
+
+ _Globals2.default.$html.removeClass('rl-changing-language').removeClass('rl-rtl rl-ltr').addClass(isRtl ? 'rl-rtl' : 'rl-ltr')
+ // .attr('dir', isRtl ? 'rtl' : 'ltr')
+ ;
+ }, 500 < _Utils2.default.microtime() - start ? 1 : 500);
+ });
+ };
+
+ Translator.prototype.init = function init() {
+ _Globals2.default.$html.addClass('rl-' + (_Globals2.default.$html.attr('dir') || 'ltr'));
+ };
+
+ return Translator;
+ }();
+
+ module.exports = new Translator();
+
+/***/ },
+/* 7 */,
+/* 8 */
+/*!*******************************!*\
+ !*** ./dev/Common/Globals.js ***!
+ \*******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ /* global RL_COMMUNITY */
+
+ (function () {
+
+ 'use strict';
+
+ var
+ Globals = {},
+
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+ key = __webpack_require__(/*! key */ 18),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4)
+ ;
+
+ Globals.$win = $(window);
+ Globals.$doc = $(window.document);
+ Globals.$html = $('html');
+ Globals.$body = $('body');
+ Globals.$div = $('
');
+
+ Globals.$win.__sizes = [0, 0];
+
+ /**
+ * @type {?}
+ */
+ Globals.startMicrotime = (new window.Date()).getTime();
+
+ /**
+ * @type {boolean}
+ */
+ Globals.community = (true);
+
+ /**
+ * @type {?}
+ */
+ Globals.dropdownVisibility = ko.observable(false).extend({'rateLimit': 0});
+
+ /**
+ * @type {boolean}
+ */
+ Globals.useKeyboardShortcuts = ko.observable(true);
+
+ /**
+ * @type {number}
+ */
+ Globals.iAjaxErrorCount = 0;
+
+ /**
+ * @type {number}
+ */
+ Globals.iTokenErrorCount = 0;
+
+ /**
+ * @type {number}
+ */
+ Globals.iMessageBodyCacheCount = 0;
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bUnload = false;
+
+ /**
+ * @type {string}
+ */
+ Globals.sUserAgent = 'navigator' in window && 'userAgent' in window.navigator &&
+ window.navigator.userAgent.toLowerCase() || '';
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bIE = Globals.sUserAgent.indexOf('msie') > -1;
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bChrome = Globals.sUserAgent.indexOf('chrome') > -1;
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bSafari = !Globals.bChrome && Globals.sUserAgent.indexOf('safari') > -1;
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bMobileDevice =
+ /android/i.test(Globals.sUserAgent) ||
+ /iphone/i.test(Globals.sUserAgent) ||
+ /ipod/i.test(Globals.sUserAgent) ||
+ /ipad/i.test(Globals.sUserAgent) ||
+ /blackberry/i.test(Globals.sUserAgent)
+ ;
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bDisableNanoScroll = Globals.bMobileDevice;
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bAllowPdfPreview = !Globals.bMobileDevice;
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bAnimationSupported = !Globals.bMobileDevice &&
+ Globals.$html.hasClass('csstransitions') &&
+ Globals.$html.hasClass('cssanimations');
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bXMLHttpRequestSupported = !!window.XMLHttpRequest;
+
+ /**
+ * @type {*}
+ */
+ Globals.__APP__ = null;
+
+ /**
+ * @type {Object}
+ */
+ Globals.oHtmlEditorDefaultConfig = {
+ 'title': false,
+ 'stylesSet': false,
+ 'customConfig': '',
+ 'contentsCss': '',
+ 'toolbarGroups': [
+ {name: 'spec'},
+ {name: 'styles'},
+ {name: 'basicstyles', groups: ['basicstyles', 'cleanup', 'bidi']},
+ {name: 'colors'},
+ Globals.bMobileDevice ? {} : {name: 'paragraph', groups: ['list', 'indent', 'blocks', 'align']},
+ {name: 'links'},
+ {name: 'insert'},
+ {name: 'document', groups: ['mode', 'document', 'doctools']},
+ {name: 'others'}
+ ],
+
+ 'removePlugins': 'liststyle',
+ 'removeButtons': 'Format,Undo,Redo,Cut,Copy,Paste,Anchor,Strike,Subscript,Superscript,Image,SelectAll,Source',
+ 'removeDialogTabs': 'link:advanced;link:target;image:advanced;images:advanced',
+
+ 'extraPlugins': 'plain,signature',
+
+ 'allowedContent': true,
+ 'extraAllowedContent': true,
+
+ 'fillEmptyBlocks': false,
+ 'ignoreEmptyParagraph': true,
+ 'disableNativeSpellChecker': false,
+
+ 'font_defaultLabel': 'Arial',
+ 'fontSize_defaultLabel': '13',
+ 'fontSize_sizes': '10/10px;12/12px;13/13px;14/14px;16/16px;18/18px;20/20px;24/24px;28/28px;36/36px;48/48px'
+ };
+
+ /**
+ * @type {Object}
+ */
+ Globals.oHtmlEditorLangsMap = {
+ 'bg_bg': 'bg',
+ 'de_de': 'de',
+ 'el_gr': 'el',
+ 'es_es': 'es',
+ 'fr_fr': 'fr',
+ 'hu_hu': 'hu',
+ 'is_is': 'is',
+ 'it_it': 'it',
+ 'ja_jp': 'ja',
+ 'ko_kr': 'ko',
+ 'lt_lt': 'lt',
+ 'lv_lv': 'lv',
+ 'nl_nl': 'nl',
+ 'bg_no': 'no',
+ 'pl_pl': 'pl',
+ 'pt_pt': 'pt',
+ 'pt_br': 'pt-br',
+ 'ro_ro': 'ro',
+ 'ru_ru': 'ru',
+ 'sk_sk': 'sk',
+ 'sl_si': 'sl',
+ 'sv_se': 'sv',
+ 'tr_tr': 'tr',
+ 'uk_ua': 'ru',
+ 'zh_tw': 'zh',
+ 'zh_cn': 'zh-cn'
+ };
+
+ if (Globals.bAllowPdfPreview && window.navigator && window.navigator.mimeTypes)
+ {
+ Globals.bAllowPdfPreview = !!_.find(window.navigator.mimeTypes, function (oType) {
+ return oType && 'application/pdf' === oType.type;
+ });
+
+ if (!Globals.bAllowPdfPreview)
+ {
+ Globals.bAllowPdfPreview = (typeof window.navigator.mimeTypes['application/pdf'] !== 'undefined');
+ }
+ }
+
+ Globals.aBootstrapDropdowns = [];
+
+ Globals.aViewModels = {
+ 'settings': [],
+ 'settings-removed': [],
+ 'settings-disabled': []
+ };
+
+ Globals.leftPanelDisabled = ko.observable(false);
+ Globals.leftPanelType = ko.observable('');
+ Globals.leftPanelWidth = ko.observable(0);
+
+ // popups
+ Globals.popupVisibilityNames = ko.observableArray([]);
+
+ Globals.popupVisibility = ko.computed(function () {
+ return 0 < Globals.popupVisibilityNames().length;
+ }, this);
+
+ Globals.popupVisibility.subscribe(function (bValue) {
+ Globals.$html.toggleClass('rl-modal', bValue);
+ });
+
+ // keys
+ Globals.keyScopeReal = ko.observable(Enums.KeyState.All);
+ Globals.keyScopeFake = ko.observable(Enums.KeyState.All);
+
+ Globals.keyScope = ko.computed({
+ 'owner': this,
+ 'read': function () {
+ return Globals.keyScopeFake();
+ },
+ 'write': function (sValue) {
+
+ if (Enums.KeyState.Menu !== sValue)
+ {
+ if (Enums.KeyState.Compose === sValue)
+ {
+ // disableKeyFilter
+ key.filter = function () {
+ return Globals.useKeyboardShortcuts();
+ };
+ }
+ else
+ {
+ // restoreKeyFilter
+ key.filter = function (event) {
+
+ if (Globals.useKeyboardShortcuts())
+ {
+ var
+ oElement = event.target || event.srcElement,
+ sTagName = oElement ? oElement.tagName : ''
+ ;
+
+ sTagName = sTagName.toUpperCase();
+ return !(sTagName === 'INPUT' || sTagName === 'SELECT' || sTagName === 'TEXTAREA' ||
+ (oElement && sTagName === 'DIV' && ('editorHtmlArea' === oElement.className || 'true' === '' + oElement.contentEditable))
+ );
+ }
+
+ return false;
+ };
+ }
+
+ Globals.keyScopeFake(sValue);
+ if (Globals.dropdownVisibility())
+ {
+ sValue = Enums.KeyState.Menu;
+ }
+ }
+
+ Globals.keyScopeReal(sValue);
+ }
+ });
+
+ Globals.keyScopeReal.subscribe(function (sValue) {
+ // window.console.log('keyScope=' + sValue); // DEBUG
+ key.setScope(sValue);
+ });
+
+ Globals.dropdownVisibility.subscribe(function (bValue) {
+ if (bValue)
+ {
+ Globals.keyScope(Enums.KeyState.Menu);
+ }
+ else if (Enums.KeyState.Menu === key.getScope())
+ {
+ Globals.keyScope(Globals.keyScopeFake());
+ }
+ });
+
+ module.exports = Globals;
+
+ }());
+
+/***/ },
+/* 9 */
+/*!**********************************!*\
+ !*** ./dev/Storage/Settings.jsx ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var SettingsStorage = function () {
+ function SettingsStorage() {
+ _classCallCheck(this, SettingsStorage);
+
+ this.settings = {};
+ this.appSettings = {};
+
+ this.settings = _common.window.rainloopAppData || {};
+ this.settings = _Utils2.default.isNormal(this.settings) ? this.settings : {};
+
+ this.appSettings = this.settings.System || null;
+ this.appSettings = _Utils2.default.isNormal(this.appSettings) ? this.appSettings : {};
+ }
+
+ /**
+ * @param {string} name
+ * @return {*}
+ */
+
+
+ SettingsStorage.prototype.settingsGet = function settingsGet(name) {
+ return _Utils2.default.isUnd(this.settings[name]) ? null : this.settings[name];
+ };
+
+ /**
+ * @param {string} name
+ * @param {*} value
+ */
+
+
+ SettingsStorage.prototype.settingsSet = function settingsSet(name, value) {
+ this.settings[name] = value;
+ };
+
+ /**
+ * @param {string} name
+ * @return {*}
+ */
+
+
+ SettingsStorage.prototype.appSettingsGet = function appSettingsGet(name) {
+ return _Utils2.default.isUnd(this.appSettings[name]) ? null : this.appSettings[name];
+ };
+
+ /**
+ * @param {string} name
+ * @return {boolean}
+ */
+
+
+ SettingsStorage.prototype.capa = function capa(name) {
+ var values = this.settingsGet('Capa');
+ return _Utils2.default.isArray(values) && _Utils2.default.isNormal(name) && -1 < _Utils2.default.inArray(name, values);
+ };
+
+ return SettingsStorage;
+ }();
+
+ module.exports = new SettingsStorage();
+
+/***/ },
+/* 10 */
+/*!***********************************!*\
+ !*** ./dev/Knoin/AbstractView.js ***!
+ \***********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Globals = __webpack_require__(/*! Common/Globals */ 8)
+ ;
+
+ /**
+ * @constructor
+ * @param {string=} sPosition = ''
+ * @param {string=} sTemplate = ''
+ */
+ function AbstractView(sPosition, sTemplate)
+ {
+ this.bDisabeCloseOnEsc = false;
+ this.sPosition = Utils.pString(sPosition);
+ this.sTemplate = Utils.pString(sTemplate);
+
+ this.sDefaultKeyScope = Enums.KeyState.None;
+ this.sCurrentKeyScope = this.sDefaultKeyScope;
+
+ this.viewModelVisibility = ko.observable(false);
+ this.modalVisibility = ko.observable(false).extend({'rateLimit': 0});
+
+ this.viewModelName = '';
+ this.viewModelNames = [];
+ this.viewModelDom = null;
+ }
+
+ /**
+ * @type {boolean}
+ */
+ AbstractView.prototype.bDisabeCloseOnEsc = false;
+
+ /**
+ * @type {string}
+ */
+ AbstractView.prototype.sPosition = '';
+
+ /**
+ * @type {string}
+ */
+ AbstractView.prototype.sTemplate = '';
+
+ /**
+ * @type {string}
+ */
+ AbstractView.prototype.sDefaultKeyScope = Enums.KeyState.None;
+
+ /**
+ * @type {string}
+ */
+ AbstractView.prototype.sCurrentKeyScope = Enums.KeyState.None;
+
+ /**
+ * @type {string}
+ */
+ AbstractView.prototype.viewModelName = '';
+
+ /**
+ * @type {Array}
+ */
+ AbstractView.prototype.viewModelNames = [];
+
+ /**
+ * @type {?}
+ */
+ AbstractView.prototype.viewModelDom = null;
+
+ /**
+ * @return {string}
+ */
+ AbstractView.prototype.viewModelTemplate = function ()
+ {
+ return this.sTemplate;
+ };
+
+ /**
+ * @return {string}
+ */
+ AbstractView.prototype.viewModelPosition = function ()
+ {
+ return this.sPosition;
+ };
+
+ AbstractView.prototype.cancelCommand = function () {};
+ AbstractView.prototype.closeCommand = function () {};
+
+ AbstractView.prototype.storeAndSetKeyScope = function ()
+ {
+ this.sCurrentKeyScope = Globals.keyScope();
+ Globals.keyScope(this.sDefaultKeyScope);
+ };
+
+ AbstractView.prototype.restoreKeyScope = function ()
+ {
+ Globals.keyScope(this.sCurrentKeyScope);
+ };
+
+ AbstractView.prototype.registerPopupKeyDown = function ()
+ {
+ var self = this;
+
+ Globals.$win.on('keydown', function (oEvent) {
+ if (oEvent && self.modalVisibility && self.modalVisibility())
+ {
+ if (!this.bDisabeCloseOnEsc && Enums.EventKeyCode.Esc === oEvent.keyCode)
+ {
+ Utils.delegateRun(self, 'cancelCommand');
+ return false;
+ }
+ else if (Enums.EventKeyCode.Backspace === oEvent.keyCode && !Utils.inFocus())
+ {
+ return false;
+ }
+ }
+
+ return true;
+ });
+ };
+
+ module.exports = AbstractView;
+
+ }());
+
+/***/ },
+/* 11 */
+/*!*************************!*\
+ !*** external "window" ***!
+ \*************************/
+/***/ function(module, exports) {
+
+ module.exports = window;
+
+/***/ },
+/* 12 */
+/*!******************************!*\
+ !*** ./dev/Common/Links.jsx ***!
+ \******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var Links = function () {
+ function Links() {
+ _classCallCheck(this, Links);
+
+ this.sBase = '#/';
+ this.sServer = './?';
+
+ this.sVersion = _Settings2.default.appSettingsGet('version');
+ this.sWebPrefix = _Settings2.default.appSettingsGet('webPath') || '';
+ this.sVersionPrefix = _Settings2.default.appSettingsGet('webVersionPath') || 'rainloop/v/' + this.sVersion + '/';
+ this.sAdminPath = _Settings2.default.appSettingsGet('adminPath') || 'admin';
+
+ this.sAuthSuffix = _Settings2.default.settingsGet('AuthAccountHash') || '0';
+
+ this.sStaticPrefix = this.sVersionPrefix + 'static/';
+ }
+
+ Links.prototype.populateAuthSuffix = function populateAuthSuffix() {
+ this.sAuthSuffix = _Settings2.default.settingsGet('AuthAccountHash') || '0';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.subQueryPrefix = function subQueryPrefix() {
+ return '&q[]=';
+ };
+
+ /**
+ * @param {string=} startupUrl
+ * @return {string}
+ */
+
+
+ Links.prototype.root = function root() {
+ var startupUrl = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
+
+ return this.sBase + _Utils2.default.pString(startupUrl);
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.rootAdmin = function rootAdmin() {
+ return this.sServer + this.sAdminPath;
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.rootUser = function rootUser() {
+ var mobile = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
+
+ return mobile ? './?/Mobile/' : './';
+ };
+
+ /**
+ * @param {string} type
+ * @param {string} download
+ * @param {string=} customSpecSuffix
+ * @return {string}
+ */
+
+
+ Links.prototype.attachmentRaw = function attachmentRaw(type, download, customSpecSuffix) {
+ customSpecSuffix = _Utils2.default.isUnd(customSpecSuffix) ? this.sAuthSuffix : customSpecSuffix;
+ return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + customSpecSuffix + '/' + type + '/' + this.subQueryPrefix() + '/' + download;
+ };
+
+ /**
+ * @param {string} download
+ * @param {string=} customSpecSuffix
+ * @return {string}
+ */
+
+
+ Links.prototype.attachmentDownload = function attachmentDownload(download, customSpecSuffix) {
+ return this.attachmentRaw('Download', download, customSpecSuffix);
+ };
+
+ /**
+ * @param {string} download
+ * @param {string=} customSpecSuffix
+ * @return {string}
+ */
+
+
+ Links.prototype.attachmentPreview = function attachmentPreview(download, customSpecSuffix) {
+ return this.attachmentRaw('View', download, customSpecSuffix);
+ };
+
+ /**
+ * @param {string} download
+ * @param {string=} customSpecSuffix
+ * @return {string}
+ */
+
+
+ Links.prototype.attachmentThumbnailPreview = function attachmentThumbnailPreview(download, customSpecSuffix) {
+ return this.attachmentRaw('ViewThumbnail', download, customSpecSuffix);
+ };
+
+ /**
+ * @param {string} download
+ * @param {string=} customSpecSuffix
+ * @return {string}
+ */
+
+
+ Links.prototype.attachmentPreviewAsPlain = function attachmentPreviewAsPlain(download, customSpecSuffix) {
+ return this.attachmentRaw('ViewAsPlain', download, customSpecSuffix);
+ };
+
+ /**
+ * @param {string} download
+ * @param {string=} customSpecSuffix
+ * @return {string}
+ */
+
+
+ Links.prototype.attachmentFramed = function attachmentFramed(download, customSpecSuffix) {
+ return this.attachmentRaw('FramedView', download, customSpecSuffix);
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.upload = function upload() {
+ return this.sServer + '/Upload/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.uploadContacts = function uploadContacts() {
+ return this.sServer + '/UploadContacts/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.uploadBackground = function uploadBackground() {
+ return this.sServer + '/UploadBackground/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.append = function append() {
+ return this.sServer + '/Append/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/';
+ };
+
+ /**
+ * @param {string} email
+ * @return {string}
+ */
+
+
+ Links.prototype.change = function change(email) {
+ return this.sServer + '/Change/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/' + _Utils2.default.encodeURIComponent(email) + '/';
+ };
+
+ /**
+ * @param {string} add
+ * @return {string}
+ */
+
+
+ Links.prototype.ajax = function ajax(add) {
+ return this.sServer + '/Ajax/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/' + add;
+ };
+
+ /**
+ * @param {string} requestHash
+ * @return {string}
+ */
+
+
+ Links.prototype.messageViewLink = function messageViewLink(requestHash) {
+ return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/ViewAsPlain/' + this.subQueryPrefix() + '/' + requestHash;
+ };
+
+ /**
+ * @param {string} requestHash
+ * @return {string}
+ */
+
+
+ Links.prototype.messageDownloadLink = function messageDownloadLink(requestHash) {
+ return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/Download/' + this.subQueryPrefix() + '/' + requestHash;
+ };
+
+ /**
+ * @param {string} email
+ * @return {string}
+ */
+
+
+ Links.prototype.avatarLink = function avatarLink(email) {
+ return this.sServer + '/Raw/0/Avatar/' + _Utils2.default.encodeURIComponent(email) + '/';
+ };
+
+ /**
+ * @param {string} hash
+ * @return {string}
+ */
+
+
+ Links.prototype.publicLink = function publicLink(hash) {
+ return this.sServer + '/Raw/0/Public/' + hash + '/';
+ };
+
+ /**
+ * @param {string} hash
+ * @return {string}
+ */
+
+
+ Links.prototype.userBackground = function userBackground(hash) {
+ return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/UserBackground/' + this.subQueryPrefix() + '/' + hash;
+ };
+
+ /**
+ * @param {string} inboxFolderName = 'INBOX'
+ * @return {string}
+ */
+
+
+ Links.prototype.inbox = function inbox() {
+ var inboxFolderName = arguments.length <= 0 || arguments[0] === undefined ? 'INBOX' : arguments[0];
+
+ return this.sBase + 'mailbox/' + inboxFolderName;
+ };
+
+ /**
+ * @param {string=} screenName
+ * @return {string}
+ */
+
+
+ Links.prototype.settings = function settings() {
+ var screenName = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
+
+ return this.sBase + 'settings' + (screenName ? '/' + screenName : '');
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.about = function about() {
+ return this.sBase + 'about';
+ };
+
+ /**
+ * @param {string} screenName
+ * @return {string}
+ */
+
+
+ Links.prototype.admin = function admin(screenName) {
+ var result = this.sBase;
+ switch (screenName) {
+ case 'AdminDomains':
+ result += 'domains';
+ break;
+ case 'AdminSecurity':
+ result += 'security';
+ break;
+ case 'AdminLicensing':
+ result += 'licensing';
+ break;
+ }
+
+ return result;
+ };
+
+ /**
+ * @param {string} folder
+ * @param {number=} page = 1
+ * @param {string=} search = ''
+ * @param {string=} threadUid = ''
+ * @return {string}
+ */
+
+
+ Links.prototype.mailBox = function mailBox(folder) {
+ var page = arguments.length <= 1 || arguments[1] === undefined ? 1 : arguments[1];
+ var search = arguments.length <= 2 || arguments[2] === undefined ? '' : arguments[2];
+ var threadUid = arguments.length <= 3 || arguments[3] === undefined ? '' : arguments[3];
+
+
+ page = _Utils2.default.isNormal(page) ? _Utils2.default.pInt(page) : 1;
+ search = _Utils2.default.pString(search);
+
+ var result = this.sBase + 'mailbox/';
+
+ if ('' !== folder) {
+ var resultThreadUid = _Utils2.default.pInt(threadUid);
+ result += _common.window.encodeURI(folder) + (0 < resultThreadUid ? '~' + resultThreadUid : '');
+ }
+
+ if (1 < page) {
+ result = result.replace(/[\/]+$/, '');
+ result += '/p' + page;
+ }
+
+ if ('' !== search) {
+ result = result.replace(/[\/]+$/, '');
+ result += '/' + _common.window.encodeURI(search);
+ }
+
+ return result;
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.phpInfo = function phpInfo() {
+ return this.sServer + 'Info';
+ };
+
+ /**
+ * @param {string} lang
+ * @param {boolean} admin
+ * @return {string}
+ */
+
+
+ Links.prototype.langLink = function langLink(lang, admin) {
+ return this.sServer + '/Lang/0/' + (admin ? 'Admin' : 'App') + '/' + _common.window.encodeURI(lang) + '/' + this.sVersion + '/';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.exportContactsVcf = function exportContactsVcf() {
+ return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/ContactsVcf/';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.exportContactsCsv = function exportContactsCsv() {
+ return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/ContactsCsv/';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.emptyContactPic = function emptyContactPic() {
+ return this.sStaticPrefix + 'css/images/empty-contact.png';
+ };
+
+ /**
+ * @param {string} fileName
+ * @return {string}
+ */
+
+
+ Links.prototype.sound = function sound(fileName) {
+ return this.sStaticPrefix + 'sounds/' + fileName;
+ };
+
+ /**
+ * @param {string} theme
+ * @return {string}
+ */
+
+
+ Links.prototype.themePreviewLink = function themePreviewLink(theme) {
+ var prefix = this.sVersionPrefix;
+ if ('@custom' === theme.substr(-7)) {
+ theme = _Utils2.default.trim(theme.substring(0, theme.length - 7));
+ prefix = this.sWebPrefix;
+ }
+
+ return prefix + 'themes/' + _common.window.encodeURI(theme) + '/images/preview.png';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.notificationMailIcon = function notificationMailIcon() {
+ return this.sStaticPrefix + 'css/images/icom-message-notification.png';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.openPgpJs = function openPgpJs() {
+ return this.sStaticPrefix + 'js/min/openpgp.min.js';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.openPgpWorkerJs = function openPgpWorkerJs() {
+ return this.sStaticPrefix + 'js/min/openpgp.worker.min.js';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.openPgpWorkerPath = function openPgpWorkerPath() {
+ return this.sStaticPrefix + 'js/min/';
+ };
+
+ /**
+ * @param {boolean} xauth = false
+ * @return {string}
+ */
+
+
+ Links.prototype.socialGoogle = function socialGoogle() {
+ var xauth = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
+
+ return this.sServer + 'SocialGoogle' + ('' !== this.sAuthSuffix ? '/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/' : '') + (xauth ? '&xauth=1' : '');
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.socialTwitter = function socialTwitter() {
+ return this.sServer + 'SocialTwitter' + ('' !== this.sAuthSuffix ? '/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/' : '');
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.socialFacebook = function socialFacebook() {
+ return this.sServer + 'SocialFacebook' + ('' !== this.sAuthSuffix ? '/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/' : '');
+ };
+
+ return Links;
+ }();
+
+ module.exports = new Links();
+
+/***/ },
+/* 13 */
+/*!************************!*\
+ !*** ./dev/common.jsx ***!
+ \************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.key = exports.moment = exports.Q = exports._ = exports.JSON = exports.$ = exports.window = undefined;
+
+ var _window = __webpack_require__(/*! window */ 11);
+
+ var _window2 = _interopRequireDefault(_window);
+
+ var _$ = __webpack_require__(/*! $ */ 14);
+
+ var _$2 = _interopRequireDefault(_$);
+
+ var _JSON = __webpack_require__(/*! JSON */ 36);
+
+ var _JSON2 = _interopRequireDefault(_JSON);
+
+ var _2 = __webpack_require__(/*! _ */ 3);
+
+ var _3 = _interopRequireDefault(_2);
+
+ var _Q = __webpack_require__(/*! Q */ 48);
+
+ var _Q2 = _interopRequireDefault(_Q);
+
+ var _moment = __webpack_require__(/*! moment */ 82);
+
+ var _moment2 = _interopRequireDefault(_moment);
+
+ var _key = __webpack_require__(/*! key */ 18);
+
+ var _key2 = _interopRequireDefault(_key);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ exports.window = _window2.default;
+ exports.$ = _$2.default;
+ exports.JSON = _JSON2.default;
+ exports._ = _3.default;
+ exports.Q = _Q2.default;
+ exports.moment = _moment2.default;
+ exports.key = _key2.default;
+
+/***/ },
+/* 14 */
+/*!********************************!*\
+ !*** external "window.jQuery" ***!
+ \********************************/
+/***/ function(module, exports) {
+
+ module.exports = window.jQuery;
+
+/***/ },
+/* 15 */,
+/* 16 */
+/*!************************************!*\
+ !*** ./dev/Component/Abstract.jsx ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.componentExportHelper = exports.AbstractComponent = undefined;
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var AbstractComponent = function () {
+ function AbstractComponent() {
+ _classCallCheck(this, AbstractComponent);
+
+ this.disposable = [];
+ }
+
+ AbstractComponent.prototype.dispose = function dispose() {
+ this.disposable.forEach(function (funcToDispose) {
+ if (funcToDispose && funcToDispose.dispose) {
+ funcToDispose.dispose();
+ }
+ });
+ };
+
+ return AbstractComponent;
+ }();
+
+ /**
+ * @param {*} ClassObject
+ * @param {string} templateID = ''
+ * @return {Object}
+ */
+
+
+ var componentExportHelper = function componentExportHelper(ClassObject) {
+ var templateID = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1];
+
+ return {
+ template: templateID ? { element: templateID } : '
',
+ viewModel: {
+ createViewModel: function createViewModel(params, componentInfo) {
+
+ params = params || {};
+ params.element = null;
+
+ if (componentInfo && componentInfo.element) {
+ params.component = componentInfo;
+ params.element = (0, _common.$)(componentInfo.element);
+
+ __webpack_require__(/*! Common/Translator */ 6).i18nToNodes(params.element);
+
+ if (!_Utils2.default.isUnd(params.inline) && _ko2.default.unwrap(params.inline)) {
+ params.element.css('display', 'inline-block');
+ }
+ }
+
+ return new ClassObject(params);
+ }
+ }
+ };
+ };
+
+ exports.AbstractComponent = AbstractComponent;
+ exports.componentExportHelper = componentExportHelper;
+
+/***/ },
+/* 17 */
+/*!*******************************!*\
+ !*** ./dev/Common/Consts.jsx ***!
+ \*******************************/
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ /* eslint max-len: 0 */
+
+ var MESSAGES_PER_PAGE = exports.MESSAGES_PER_PAGE = 20;
+
+ var MESSAGES_PER_PAGE_VALUES = exports.MESSAGES_PER_PAGE_VALUES = [10, 20, 30, 50, 100];
+
+ var CONTACTS_PER_PAGE = exports.CONTACTS_PER_PAGE = 50;
+
+ var DEFAULT_AJAX_TIMEOUT = exports.DEFAULT_AJAX_TIMEOUT = 30000;
+
+ var SEARCH_AJAX_TIMEOUT = exports.SEARCH_AJAX_TIMEOUT = 300000;
+
+ var SEND_MESSAGE_AJAX_TIMEOUT = exports.SEND_MESSAGE_AJAX_TIMEOUT = 300000;
+
+ var SAVE_MESSAGE_AJAX_TIMEOUT = exports.SAVE_MESSAGE_AJAX_TIMEOUT = 200000;
+
+ var CONTACTS_SYNC_AJAX_TIMEOUT = exports.CONTACTS_SYNC_AJAX_TIMEOUT = 200000;
+
+ var UNUSED_OPTION_VALUE = exports.UNUSED_OPTION_VALUE = '__UNUSE__';
+
+ var CLIENT_SIDE_STORAGE_INDEX_NAME = exports.CLIENT_SIDE_STORAGE_INDEX_NAME = 'rlcsc';
+
+ var IMAP_DEFAULT_PORT = exports.IMAP_DEFAULT_PORT = 143;
+
+ var IMAP_DEFAULT_SECURE_PORT = exports.IMAP_DEFAULT_SECURE_PORT = 993;
+
+ var SMTP_DEFAULT_PORT = exports.SMTP_DEFAULT_PORT = 25;
+
+ var SMTP_DEFAULT_SECURE_PORT = exports.SMTP_DEFAULT_SECURE_PORT = 465;
+
+ var SIEVE_DEFAULT_PORT = exports.SIEVE_DEFAULT_PORT = 4190;
+
+ var MESSAGE_BODY_CACHE_LIMIT = exports.MESSAGE_BODY_CACHE_LIMIT = 15;
+
+ var AJAX_ERROR_LIMIT = exports.AJAX_ERROR_LIMIT = 7;
+
+ var TOKEN_ERROR_LIMIT = exports.TOKEN_ERROR_LIMIT = 10;
+
+ var RAINLOOP_TRIAL_KEY = exports.RAINLOOP_TRIAL_KEY = 'RAINLOOP-TRIAL-KEY';
+
+ var DATA_IMAGE_USER_DOT_PIC = exports.DATA_IMAGE_USER_DOT_PIC = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAuCAYAAABXuSs3AAAHHklEQVRoQ7VZW08bVxCeXRuwIbTGXIwNtBBaqjwgVUiR8lDlbza9qe1DpVZ9aNQ/0KpPeaJK07SpcuEeCEmUAObm21bfrL9lONjexSYrWfbunj37zXdmvpkz9oIgCKTD0Wg0xPd94TDP83Q0zvWa50vzklSrdanVanqf4/D84GBGr+F+Op3S8fqoJxLOdnZgTvsO/nYhenHA+UC7CWF1uXwkb9++ldPTUwVerVbVqFQqpR8YPjQ0JCMjI5LNDijoRgP3PQVu5+5Eor2XGLg7IV4GkIdHJ/LmzRs5ODiIwNbrdR0O0GCcq4Xz4eFhmZyclP7+tDQaIik/BG5XKQn4SwG3zJTLZXn9+rUclI8UHD5YVoDDN8bSzXhONwL48fFxGR4eilzFZT1uFRIB5yT8BqCdnR3Z3d0VP9Un6XRawYJpggVrZBv38ME4XKtUKnLt2jUplUoy1PR/l3U7T6sVSAQcgMAkj8PDQ9ne3pajoyMRL7zeKsYZWHgWYDGmv78/mmdwcFA+mJlSgziHDWrERrsjEXDXegTi1tZW+DLxI2bxIrqFNYTXyDyCFweMAHCwb8e4RnTNuOsqe3t7sra21pTD0Kct666E8XlcZyzw9/RUUXK5nK5oUinUQI6TQ3cynO/v78vq6qrKXCNwlTiJJpyNGc3nZHp6uqV2dwrQWOCtZBDAV1ZWwsQk7f0wiQn5kffbAu/0/KWBYzIC1+XukfGx0RGZmppKlC2tIV0Bh4aDcZW7HhkfH8urLLZL7T2pihvlkMNnz56FiadHxicL41IsFpN41bkxsYxbRdFo9jwB8KdPn14J8KnSpBQKhQs63nPmbCVRcBUAR2Lq1VVmpksyMTFxAXjcEsQybiegESionjx5osCZOeNe1O4+EhCAX7bQSgQcxRHTMgAgcz5+/Dis/hL4uHU3/B4YGNASGHIKxuEql0k+l05AeIAF1vPnz5VxFFmdDlaJrMtZITJeSsXCOTlMunKxjLtMYOKNjQ158eJFuAuKkUOb5sEwgff19SkJUBVkThZUbnXZrtCKBQ6gbnWIkjZpyne3ejAWoGnA7Icz6irvBLgbOMicCM6TkxPx/LAkbXfgWcsazuE2kFRsKD5Z+CiqDumKncpZvieWcS6dDVD8xiYCNflpJdwcdwJOf9airLmVQ7DPzMxIYWLsXGXoVqLt5k0M3K3JUVPDZdbWNzsCp48TPFdvdnZWUz32nDha7bJ63kgAJPzSdRks9/Kf9xMJAQ1gq2NpaUmy2Yz4zar4nQC3xb99AQwCcGzLAAwuhG8YiWvcOKts+r4GOe5nMhm5efOm9lUA3E3vSZJRrKvE0fnPv//Jy5cvo5cTHIPQbSjhOoqq69evS19f6lxDKK4+sVhigZPtKJqbrQeqxd5+WR4+fKgqgT0k2XX3nhiPgETWXFhYkFzuPZ2yVq1GTSOXpE47/VjgNnD4m4GG7/LhsTx69EiwD4Vr2MwIIxgbAH18fKx1yfz8vEogNvGtWnCuhLZa9UTAreVWFsHy/b/+Vrbdl7E5REMQD2jDoUbByty+/ZnU64GkU2HzyJLhktU1cLv8nARgkYS2d3ajAgwG8qU2oLmDZ92CMaOjo7K4uCiZgbDWaRWgnZhPxLhrMUCvr69riwKZk1LHF7XqrWAO9hJxH6ozNzcnCx/PqztZg9mf6SQMscCtm2C5ke4BGMlHWTUp36036AJajDVrFMzBrhhWslQsSrFYiOqVpMriNYIgqFRq2j3FAb/zffT6zuxFXxsNzs3NTXn16lW4gYiW96w1FyedF+83xG/2FNGCRpU4NjamMsn+OZ9xE5RXqdaDdPpib6RWCzuwKF9RxqI2AVNQBwQYJoK0wdBejnqtEikP3pfP51XjUTESl12FqJEKxsEorARYDD44ONTeID7YpsEnrRvQfWAI2e8WfDaTUSIwJ0iBCmFOtOUAHvVMPp/TPwvYFVYFIuP8l+DBgwdaa2Miqwa0GgYwfeMltovbDfh6c1vIgMYcliSsKv4IWFr6VDHxvldvBAH+1sA+cnl5WYOPmmr9ir+1l9I0Cgz0yjhXjfJJ0JROnmezWbl165ayr/5fqwcBNr7IfhjMqKcvESSM4eRcCasQ3bDNObmKPLdGUGpZsN24cUNLBm9zazu4d++e6qpNBFaTuUS26U5dpuR1CxyA7J9ddrMRqlz4pwLLYawymPd++/2PADt2ugcGwq9gCCdhQ96C6xWwa6j1ceuq+I0EhW0i8MAIVJfeL3d/DVD8EKi12P6/2S2jV/EccVB54O/ejz/9HGCpoBBMta5rXMXLu53D1XAwjhXwvvv+h4BAXVe4bOu3O3ChxF08LiZFG3fel199G9CH3fLyqv24NcB44MRhpdK788U3CpyKwsCw590xmfSpzsBt0Fqc3ud3vtZigxWcVZCklVpSiN0w3q5E/h9TGMIUuA3+EQAAAABJRU5ErkJggg==';
+
+ var DATA_IMAGE_TRANSP_PIC = exports.DATA_IMAGE_TRANSP_PIC = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2NkAAIAAAoAAggA9GkAAAAASUVORK5CYII=';
+
+/***/ },
+/* 18 */
+/*!*****************************!*\
+ !*** external "window.key" ***!
+ \*****************************/
+/***/ function(module, exports) {
+
+ module.exports = window.key;
+
+/***/ },
+/* 19 */,
+/* 20 */
+/*!**********************************!*\
+ !*** ./dev/Remote/Admin/Ajax.js ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ AbstractAjaxRemote = __webpack_require__(/*! Remote/AbstractAjax */ 55)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractAjaxRemote
+ */
+ function RemoteAdminStorage()
+ {
+ AbstractAjaxRemote.call(this);
+
+ this.oRequests = {};
+ }
+
+ _.extend(RemoteAdminStorage.prototype, AbstractAjaxRemote.prototype);
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sLogin
+ * @param {string} sPassword
+ */
+ RemoteAdminStorage.prototype.adminLogin = function (fCallback, sLogin, sPassword)
+ {
+ this.defaultRequest(fCallback, 'AdminLogin', {
+ 'Login': sLogin,
+ 'Password': sPassword
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteAdminStorage.prototype.adminLogout = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'AdminLogout');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {?} oData
+ */
+ RemoteAdminStorage.prototype.saveAdminConfig = function (fCallback, oData)
+ {
+ this.defaultRequest(fCallback, 'AdminSettingsUpdate', oData);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteAdminStorage.prototype.domainList = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'AdminDomainList');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteAdminStorage.prototype.pluginList = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'AdminPluginList');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteAdminStorage.prototype.packagesList = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'AdminPackagesList');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteAdminStorage.prototype.coreData = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'AdminCoreData');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteAdminStorage.prototype.updateCoreData = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'AdminUpdateCoreData', {}, 90000);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {Object} oPackage
+ */
+ RemoteAdminStorage.prototype.packageInstall = function (fCallback, oPackage)
+ {
+ this.defaultRequest(fCallback, 'AdminPackageInstall', {
+ 'Id': oPackage.id,
+ 'Type': oPackage.type,
+ 'File': oPackage.file
+ }, 60000);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {Object} oPackage
+ */
+ RemoteAdminStorage.prototype.packageDelete = function (fCallback, oPackage)
+ {
+ this.defaultRequest(fCallback, 'AdminPackageDelete', {
+ 'Id': oPackage.id
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sName
+ */
+ RemoteAdminStorage.prototype.domain = function (fCallback, sName)
+ {
+ this.defaultRequest(fCallback, 'AdminDomainLoad', {
+ 'Name': sName
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sName
+ */
+ RemoteAdminStorage.prototype.plugin = function (fCallback, sName)
+ {
+ this.defaultRequest(fCallback, 'AdminPluginLoad', {
+ 'Name': sName
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sName
+ */
+ RemoteAdminStorage.prototype.domainDelete = function (fCallback, sName)
+ {
+ this.defaultRequest(fCallback, 'AdminDomainDelete', {
+ 'Name': sName
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sName
+ * @param {boolean} bDisabled
+ */
+ RemoteAdminStorage.prototype.domainDisable = function (fCallback, sName, bDisabled)
+ {
+ return this.defaultRequest(fCallback, 'AdminDomainDisable', {
+ 'Name': sName,
+ 'Disabled': !!bDisabled ? '1' : '0'
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {Object} oConfig
+ */
+ RemoteAdminStorage.prototype.pluginSettingsUpdate = function (fCallback, oConfig)
+ {
+ return this.defaultRequest(fCallback, 'AdminPluginSettingsUpdate', oConfig);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {boolean} bForce
+ */
+ RemoteAdminStorage.prototype.licensing = function (fCallback, bForce)
+ {
+ return this.defaultRequest(fCallback, 'AdminLicensing', {
+ 'Force' : bForce ? '1' : '0'
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sDomain
+ * @param {string} sKey
+ */
+ RemoteAdminStorage.prototype.licensingActivate = function (fCallback, sDomain, sKey)
+ {
+ return this.defaultRequest(fCallback, 'AdminLicensingActivate', {
+ 'Domain' : sDomain,
+ 'Key' : sKey
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sName
+ * @param {boolean} bDisabled
+ */
+ RemoteAdminStorage.prototype.pluginDisable = function (fCallback, sName, bDisabled)
+ {
+ return this.defaultRequest(fCallback, 'AdminPluginDisable', {
+ 'Name': sName,
+ 'Disabled': !!bDisabled ? '1' : '0'
+ });
+ };
+
+ RemoteAdminStorage.prototype.createOrUpdateDomain = function (fCallback,
+ bCreate, sName,
+ sIncHost, iIncPort, sIncSecure, bIncShortLogin,
+ bUseSieve, sSieveAllowRaw, sSieveHost, iSievePort, sSieveSecure,
+ sOutHost, iOutPort, sOutSecure, bOutShortLogin, bOutAuth, bOutPhpMail,
+ sWhiteList)
+ {
+ this.defaultRequest(fCallback, 'AdminDomainSave', {
+ 'Create': bCreate ? '1' : '0',
+ 'Name': sName,
+
+ 'IncHost': sIncHost,
+ 'IncPort': iIncPort,
+ 'IncSecure': sIncSecure,
+ 'IncShortLogin': bIncShortLogin ? '1' : '0',
+
+ 'UseSieve': bUseSieve ? '1' : '0',
+ 'SieveAllowRaw': sSieveAllowRaw ? '1' : '0',
+ 'SieveHost': sSieveHost,
+ 'SievePort': iSievePort,
+ 'SieveSecure': sSieveSecure,
+
+ 'OutHost': sOutHost,
+ 'OutPort': iOutPort,
+ 'OutSecure': sOutSecure,
+ 'OutShortLogin': bOutShortLogin ? '1' : '0',
+ 'OutAuth': bOutAuth ? '1' : '0',
+ 'OutUsePhpMail': bOutPhpMail ? '1' : '0',
+
+ 'WhiteList': sWhiteList
+ });
+ };
+
+ RemoteAdminStorage.prototype.testConnectionForDomain = function (fCallback, sName,
+ sIncHost, iIncPort, sIncSecure,
+ bUseSieve, sSieveHost, iSievePort, sSieveSecure,
+ sOutHost, iOutPort, sOutSecure, bOutAuth, bOutPhpMail)
+ {
+ this.defaultRequest(fCallback, 'AdminDomainTest', {
+ 'Name': sName,
+ 'IncHost': sIncHost,
+ 'IncPort': iIncPort,
+ 'IncSecure': sIncSecure,
+ 'UseSieve': bUseSieve ? '1' : '0',
+ 'SieveHost': sSieveHost,
+ 'SievePort': iSievePort,
+ 'SieveSecure': sSieveSecure,
+ 'OutHost': sOutHost,
+ 'OutPort': iOutPort,
+ 'OutSecure': sOutSecure,
+ 'OutAuth': bOutAuth ? '1' : '0',
+ 'OutUsePhpMail': bOutPhpMail ? '1' : '0'
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {?} oData
+ */
+ RemoteAdminStorage.prototype.testContacts = function (fCallback, oData)
+ {
+ this.defaultRequest(fCallback, 'AdminContactsTest', oData);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {?} oData
+ */
+ RemoteAdminStorage.prototype.saveNewAdminPassword = function (fCallback, oData)
+ {
+ this.defaultRequest(fCallback, 'AdminPasswordUpdate', oData);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteAdminStorage.prototype.adminPing = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'AdminPing');
+ };
+
+ module.exports = new RemoteAdminStorage();
+
+ }());
+
+/***/ },
+/* 21 */,
+/* 22 */
+/*!***************************!*\
+ !*** ./dev/App/Admin.jsx ***!
+ \***************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _progressJs = __webpack_require__(/*! progressJs */ 83);
+
+ var _progressJs2 = _interopRequireDefault(_progressJs);
+
+ var _Enums = __webpack_require__(/*! Common/Enums */ 4);
+
+ var Enums = _interopRequireWildcard(_Enums);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Links = __webpack_require__(/*! Common/Links */ 12);
+
+ var _Links2 = _interopRequireDefault(_Links);
+
+ var _Translator = __webpack_require__(/*! Common/Translator */ 6);
+
+ var _Translator2 = _interopRequireDefault(_Translator);
+
+ var _Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ var _App = __webpack_require__(/*! Stores/Admin/App */ 35);
+
+ var _App2 = _interopRequireDefault(_App);
+
+ var _Domain = __webpack_require__(/*! Stores/Admin/Domain */ 57);
+
+ var _Domain2 = _interopRequireDefault(_Domain);
+
+ var _Plugin = __webpack_require__(/*! Stores/Admin/Plugin */ 59);
+
+ var _Plugin2 = _interopRequireDefault(_Plugin);
+
+ var _License = __webpack_require__(/*! Stores/Admin/License */ 139);
+
+ var _License2 = _interopRequireDefault(_License);
+
+ var _Package = __webpack_require__(/*! Stores/Admin/Package */ 58);
+
+ var _Package2 = _interopRequireDefault(_Package);
+
+ var _Core = __webpack_require__(/*! Stores/Admin/Core */ 89);
+
+ var _Core2 = _interopRequireDefault(_Core);
+
+ var _Ajax = __webpack_require__(/*! Remote/Admin/Ajax */ 20);
+
+ var _Ajax2 = _interopRequireDefault(_Ajax);
+
+ var _Knoin = __webpack_require__(/*! Knoin/Knoin */ 5);
+
+ var _Knoin2 = _interopRequireDefault(_Knoin);
+
+ var _Abstract = __webpack_require__(/*! App/Abstract */ 64);
+
+ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var AdminApp = function (_AbstractApp) {
+ _inherits(AdminApp, _AbstractApp);
+
+ function AdminApp() {
+ _classCallCheck(this, AdminApp);
+
+ return _possibleConstructorReturn(this, _AbstractApp.call(this, _Ajax2.default));
+ }
+
+ AdminApp.prototype.remote = function remote() {
+ return _Ajax2.default;
+ };
+
+ AdminApp.prototype.reloadDomainList = function reloadDomainList() {
+ _Domain2.default.domains.loading(true);
+ _Ajax2.default.domainList(function (result, data) {
+ _Domain2.default.domains.loading(false);
+ if (Enums.StorageResultType.Success === result && data && data.Result) {
+ _Domain2.default.domains(_common._.map(data.Result, function (enabled, name) {
+ return {
+ name: name,
+ disabled: _ko2.default.observable(!enabled),
+ deleteAccess: _ko2.default.observable(false)
+ };
+ }));
+ }
+ });
+ };
+
+ AdminApp.prototype.reloadPluginList = function reloadPluginList() {
+ _Plugin2.default.plugins.loading(true);
+ _Ajax2.default.pluginList(function (result, data) {
+ _Plugin2.default.plugins.loading(false);
+ if (Enums.StorageResultType.Success === result && data && data.Result) {
+ _Plugin2.default.plugins(_common._.map(data.Result, function (item) {
+ return {
+ name: item.Name,
+ disabled: _ko2.default.observable(!item.Enabled),
+ configured: _ko2.default.observable(!!item.Configured)
+ };
+ }));
+ }
+ });
+ };
+
+ AdminApp.prototype.reloadPackagesList = function reloadPackagesList() {
+ _Package2.default.packages.loading(true);
+ _Package2.default.packagesReal(true);
+ _Ajax2.default.packagesList(function (result, data) {
+ _Package2.default.packages.loading(false);
+ if (Enums.StorageResultType.Success === result && data && data.Result) {
+ (function () {
+ _Package2.default.packagesReal(!!data.Result.Real);
+ _Package2.default.packagesMainUpdatable(!!data.Result.MainUpdatable);
+
+ var list = [],
+ loading = {};
+
+ _common._.each(_Package2.default.packages(), function (item) {
+ if (item && item.loading()) {
+ loading[item.file] = item;
+ }
+ });
+
+ if (_Utils2.default.isArray(data.Result.List)) {
+ list = _common._.compact(_common._.map(data.Result.List, function (item) {
+ if (item) {
+ item.loading = _ko2.default.observable(!_Utils2.default.isUnd(loading[item.file]));
+ return 'core' === item.type && !item.canBeInstalled ? null : item;
+ }
+ return null;
+ }));
+ }
+
+ _Package2.default.packages(list);
+ })();
+ } else {
+ _Package2.default.packagesReal(false);
+ }
+ });
+ };
+
+ AdminApp.prototype.updateCoreData = function updateCoreData() {
+ _Core2.default.coreUpdating(true);
+ _Ajax2.default.updateCoreData(function (result, data) {
+ _Core2.default.coreUpdating(false);
+ _Core2.default.coreVersion('');
+ _Core2.default.coreRemoteVersion('');
+ _Core2.default.coreRemoteRelease('');
+ _Core2.default.coreVersionCompare(-2);
+ if (Enums.StorageResultType.Success === result && data && data.Result) {
+ _Core2.default.coreReal(true);
+ _common.window.location.reload();
+ } else {
+ _Core2.default.coreReal(false);
+ }
+ });
+ };
+
+ AdminApp.prototype.reloadCoreData = function reloadCoreData() {
+ _Core2.default.coreChecking(true);
+ _Core2.default.coreReal(true);
+ _Ajax2.default.coreData(function (result, data) {
+ _Core2.default.coreChecking(false);
+ if (Enums.StorageResultType.Success === result && data && data.Result) {
+ _Core2.default.coreReal(!!data.Result.Real);
+ _Core2.default.coreChannel(data.Result.Channel || 'stable');
+ _Core2.default.coreType(data.Result.Type || 'stable');
+ _Core2.default.coreUpdatable(!!data.Result.Updatable);
+ _Core2.default.coreAccess(!!data.Result.Access);
+ _Core2.default.coreWarning(!!data.Result.Warning);
+ _Core2.default.coreVersion(data.Result.Version || '');
+ _Core2.default.coreRemoteVersion(data.Result.RemoteVersion || '');
+ _Core2.default.coreRemoteRelease(data.Result.RemoteRelease || '');
+ _Core2.default.coreVersionCompare(_Utils2.default.pInt(data.Result.VersionCompare));
+ } else {
+ _Core2.default.coreReal(false);
+ _Core2.default.coreChannel('stable');
+ _Core2.default.coreType('stable');
+ _Core2.default.coreWarning(false);
+ _Core2.default.coreVersion('');
+ _Core2.default.coreRemoteVersion('');
+ _Core2.default.coreRemoteRelease('');
+ _Core2.default.coreVersionCompare(-2);
+ }
+ });
+ };
+
+ /**
+ * @param {boolean=} force = false
+ */
+
+
+ AdminApp.prototype.reloadLicensing = function reloadLicensing() {
+ var force = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
+
+ _License2.default.licensingProcess(true);
+ _License2.default.licenseError('');
+ _Ajax2.default.licensing(function (result, data) {
+ _License2.default.licensingProcess(false);
+ if (Enums.StorageResultType.Success === result && data && data.Result && _Utils2.default.isNormal(data.Result.Expired)) {
+ _License2.default.licenseValid(true);
+ _License2.default.licenseExpired(_Utils2.default.pInt(data.Result.Expired));
+ _License2.default.licenseError('');
+ _License2.default.licensing(true);
+ _App2.default.prem(true);
+ } else {
+ if (data && data.ErrorCode && -1 < _Utils2.default.inArray(_Utils2.default.pInt(data.ErrorCode), [Enums.Notification.LicensingServerIsUnavailable, Enums.Notification.LicensingExpired])) {
+ _License2.default.licenseError(_Translator2.default.getNotification(_Utils2.default.pInt(data.ErrorCode)));
+ _License2.default.licensing(true);
+ } else {
+ if (Enums.StorageResultType.Abort === result) {
+ _License2.default.licenseError(_Translator2.default.getNotification(Enums.Notification.LicensingServerIsUnavailable));
+ _License2.default.licensing(true);
+ } else {
+ _License2.default.licensing(false);
+ }
+ }
+ }
+ }, force);
+ };
+
+ AdminApp.prototype.bootend = function bootend() {
+ var callback = arguments.length <= 0 || arguments[0] === undefined ? null : arguments[0];
+
+ if (_progressJs2.default) {
+ _progressJs2.default.end();
+ }
+
+ if (callback) {
+ callback();
+ }
+ };
+
+ AdminApp.prototype.bootstart = function bootstart() {
+
+ _AbstractApp.prototype.bootstart.call(this);
+
+ __webpack_require__(/*! Stores/Admin/App */ 35).populate();
+ __webpack_require__(/*! Stores/Admin/Capa */ 50).populate();
+
+ _Knoin2.default.hideLoading();
+
+ if (!_Settings2.default.appSettingsGet('allowAdminPanel')) {
+ _Knoin2.default.routeOff();
+ _Knoin2.default.setHash(_Links2.default.root(), true);
+ _Knoin2.default.routeOff();
+
+ _common._.defer(function () {
+ _common.window.location.href = '/';
+ });
+ } else {
+ if (_Settings2.default.settingsGet('Auth')) {
+ _Knoin2.default.startScreens([__webpack_require__(/*! Screen/Admin/Settings */ 114)]);
+ } else {
+ _Knoin2.default.startScreens([__webpack_require__(/*! Screen/Admin/Login */ 113)]);
+ }
+ }
+
+ this.bootend();
+ };
+
+ return AdminApp;
+ }(_Abstract.AbstractApp);
+
+ var App = new AdminApp();
+ exports.default = App;
+
+/***/ },
+/* 23 */
+/*!********************************!*\
+ !*** ./dev/Common/Plugins.jsx ***!
+ \********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ var _Globals2 = _interopRequireDefault(_Globals);
+
+ var _Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var Plugins = function () {
+ function Plugins() {
+ _classCallCheck(this, Plugins);
+
+ this.oSimpleHooks = {};
+ this.aUserViewModelsHooks = [];
+ this.aAdminViewModelsHooks = [];
+ }
+
+ /**
+ * @param {string} name
+ * @param {Function} callback
+ */
+
+
+ Plugins.prototype.addHook = function addHook(name, callback) {
+ if (_Utils2.default.isFunc(callback)) {
+ if (!_Utils2.default.isArray(this.oSimpleHooks[name])) {
+ this.oSimpleHooks[name] = [];
+ }
+
+ this.oSimpleHooks[name].push(callback);
+ }
+ };
+
+ /**
+ * @param {string} name
+ * @param {Array=} args
+ */
+
+
+ Plugins.prototype.runHook = function runHook(name) {
+ var args = arguments.length <= 1 || arguments[1] === undefined ? [] : arguments[1];
+
+ if (_Utils2.default.isArray(this.oSimpleHooks[name])) {
+ _common._.each(this.oSimpleHooks[name], function (callback) {
+ callback.apply(null, args);
+ });
+ }
+ };
+
+ /**
+ * @param {string} name
+ * @return {?}
+ */
+
+
+ Plugins.prototype.mainSettingsGet = function mainSettingsGet(name) {
+ return _Settings2.default.settingsGet(name);
+ };
+
+ /**
+ * @param {Function} callback
+ * @param {string} action
+ * @param {Object=} parameters
+ * @param {?number=} timeout
+ */
+
+
+ Plugins.prototype.remoteRequest = function remoteRequest(callback, action, parameters, timeout) {
+ if (_Globals2.default.__APP__) {
+ _Globals2.default.__APP__.remote().defaultRequest(callback, 'Plugin' + action, parameters, timeout);
+ }
+ };
+
+ /**
+ * @param {Function} SettingsViewModelClass
+ * @param {string} labelName
+ * @param {string} template
+ * @param {string} route
+ */
+
+
+ Plugins.prototype.addSettingsViewModel = function addSettingsViewModel(SettingsViewModelClass, template, labelName, route) {
+ this.aUserViewModelsHooks.push([SettingsViewModelClass, template, labelName, route]);
+ };
+
+ /**
+ * @param {Function} SettingsViewModelClass
+ * @param {string} labelName
+ * @param {string} template
+ * @param {string} route
+ */
+
+
+ Plugins.prototype.addSettingsViewModelForAdmin = function addSettingsViewModelForAdmin(SettingsViewModelClass, template, labelName, route) {
+ this.aAdminViewModelsHooks.push([SettingsViewModelClass, template, labelName, route]);
+ };
+
+ /**
+ * @param {boolean} admin
+ */
+
+
+ Plugins.prototype.runSettingsViewModelHooks = function runSettingsViewModelHooks(admin) {
+ var Knoin = __webpack_require__(/*! Knoin/Knoin */ 5);
+ _common._.each(admin ? this.aAdminViewModelsHooks : this.aUserViewModelsHooks, function (view) {
+ Knoin.addSettingsViewModel(view[0], view[1], view[2], view[3]);
+ });
+ };
+
+ /**
+ * @param {string} pluginSection
+ * @param {string} name
+ * @return {?}
+ */
+
+
+ Plugins.prototype.settingsGet = function settingsGet(pluginSection, name) {
+ var plugins = _Settings2.default.settingsGet('Plugins');
+ plugins = plugins && !_Utils2.default.isUnd(plugins[pluginSection]) ? plugins[pluginSection] : null;
+ return plugins ? _Utils2.default.isUnd(plugins[name]) ? null : plugins[name] : null;
+ };
+
+ return Plugins;
+ }();
+
+ module.exports = new Plugins();
+
+/***/ },
+/* 24 */,
+/* 25 */
+/*!*******************************!*\
+ !*** ./dev/Common/Events.jsx ***!
+ \*******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Plugins = __webpack_require__(/*! Common/Plugins */ 23);
+
+ var _Plugins2 = _interopRequireDefault(_Plugins);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var Events = function () {
+ function Events() {
+ _classCallCheck(this, Events);
+
+ this.subs = {};
+ }
+
+ /**
+ * @param {string|Object} name
+ * @param {Function} func
+ * @param {Object=} context
+ * @return {Events}
+ */
+
+
+ Events.prototype.sub = function sub(name, func, context) {
+ var _this = this;
+
+ if (_Utils2.default.isObject(name)) {
+ context = func || null;
+ func = null;
+
+ _common._.each(name, function (subFunc, subName) {
+ _this.sub(subName, subFunc, context);
+ }, this);
+ } else {
+ if (_Utils2.default.isUnd(this.subs[name])) {
+ this.subs[name] = [];
+ }
+
+ this.subs[name].push([func, context]);
+ }
+
+ return this;
+ };
+
+ /**
+ * @param {string} name
+ * @param {Array=} args
+ * @return {Events}
+ */
+
+
+ Events.prototype.pub = function pub(name, args) {
+
+ _Plugins2.default.runHook('rl-pub', [name, args]);
+
+ if (!_Utils2.default.isUnd(this.subs[name])) {
+ _common._.each(this.subs[name], function (items) {
+ if (items[0]) {
+ items[0].apply(items[1] || null, args || []);
+ }
+ });
+ }
+
+ return this;
+ };
+
+ return Events;
+ }();
+
+ module.exports = new Events();
+
+/***/ },
+/* 26 */
+/*!*********************************!*\
+ !*** ./dev/Common/Momentor.jsx ***!
+ \*********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Translator = __webpack_require__(/*! Common/Translator */ 6);
+
+ var _Translator2 = _interopRequireDefault(_Translator);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var Momentor = function () {
+ function Momentor() {
+ var _this = this;
+
+ _classCallCheck(this, Momentor);
+
+ this._moment = null;
+ this._momentNow = 0;
+
+ this.updateMomentNow = _common._.debounce(function () {
+ _this._moment = (0, _common.moment)();
+ }, 500, true);
+
+ this.updateMomentNowUnix = _common._.debounce(function () {
+ _this._momentNow = (0, _common.moment)().unix();
+ }, 500, true);
+
+ this.format = _common._.bind(this.format, this);
+ }
+
+ Momentor.prototype.momentNow = function momentNow() {
+ this.updateMomentNow();
+ return this._moment || (0, _common.moment)();
+ };
+
+ Momentor.prototype.momentNowUnix = function momentNowUnix() {
+ this.updateMomentNowUnix();
+ return this._momentNow || 0;
+ };
+
+ /**
+ * @param {number} date
+ * @return {string}
+ */
+
+
+ Momentor.prototype.searchSubtractFormatDateHelper = function searchSubtractFormatDateHelper(date) {
+ return this.momentNow().clone().subtract('days', date).format('YYYY.MM.DD');
+ };
+
+ /**
+ * @param {Object} m
+ * @return {string}
+ */
+
+
+ Momentor.prototype.formatCustomShortDate = function formatCustomShortDate(m) {
+
+ var now = this.momentNow();
+ if (m && now) {
+ switch (true) {
+ case 4 >= now.diff(m, 'hours'):
+ return m.fromNow();
+ case now.format('L') === m.format('L'):
+ return _Translator2.default.i18n('MESSAGE_LIST/TODAY_AT', {
+ TIME: m.format('LT')
+ });
+ case now.clone().subtract('days', 1).format('L') === m.format('L'):
+ return _Translator2.default.i18n('MESSAGE_LIST/YESTERDAY_AT', {
+ TIME: m.format('LT')
+ });
+ case now.year() === m.year():
+ return m.format('D MMM.');
+ }
+ }
+
+ return m ? m.format('LL') : '';
+ };
+
+ /**
+ * @param {number} timeStampInUTC
+ * @param {string} format
+ * @return {string}
+ */
+
+
+ Momentor.prototype.format = function format(timeStampInUTC, _format) {
+
+ var m = null,
+ result = '';
+
+ var now = this.momentNowUnix();
+
+ timeStampInUTC = 0 < timeStampInUTC ? timeStampInUTC : 0 === timeStampInUTC ? now : 0;
+ timeStampInUTC = now < timeStampInUTC ? now : timeStampInUTC;
+
+ m = 0 < timeStampInUTC ? _common.moment.unix(timeStampInUTC) : null;
+
+ if (m && 1970 === m.year()) {
+ m = null;
+ }
+
+ if (m) {
+ switch (_format) {
+ case 'FROMNOW':
+ result = m.fromNow();
+ break;
+ case 'SHORT':
+ result = this.formatCustomShortDate(m);
+ break;
+ case 'FULL':
+ result = m.format('LLL');
+ break;
+ default:
+ result = m.format(_format);
+ break;
+ }
+ }
+
+ return result;
+ };
+
+ /**
+ * @param {Object} element
+ */
+
+
+ Momentor.prototype.momentToNode = function momentToNode(element) {
+
+ var key = '',
+ time = 0,
+ $el = (0, _common.$)(element);
+
+ time = $el.data('moment-time');
+ if (time) {
+ key = $el.data('moment-format');
+ if (key) {
+ $el.text(this.format(time, key));
+ }
+
+ key = $el.data('moment-format-title');
+ if (key) {
+ $el.attr('title', this.format(time, key));
+ }
+ }
+ };
+
+ /**
+ * @param {Object} elements
+ */
+
+
+ Momentor.prototype.momentToNodes = function momentToNodes(elements) {
+ var _this2 = this;
+
+ _common._.defer(function () {
+ (0, _common.$)('.moment', elements).each(function (index, item) {
+ _this2.momentToNode(item);
+ });
+ });
+ };
+
+ Momentor.prototype.reload = function reload() {
+ this.momentToNodes(_common.window.document);
+ };
+
+ return Momentor;
+ }();
+
+ module.exports = new Momentor();
+
+/***/ },
+/* 27 */,
+/* 28 */,
+/* 29 */,
+/* 30 */
+/*!****************************!*\
+ !*** ./dev/Model/Email.js ***!
+ \****************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ Utils = __webpack_require__(/*! Common/Utils */ 1)
+ ;
+
+ /**
+ * @param {string=} sEmail
+ * @param {string=} sName
+ * @param {string=} sDkimStatus
+ * @param {string=} sDkimValue
+ *
+ * @constructor
+ */
+ function EmailModel(sEmail, sName, sDkimStatus, sDkimValue)
+ {
+ this.email = sEmail || '';
+ this.name = sName || '';
+ this.dkimStatus = sDkimStatus || 'none';
+ this.dkimValue = sDkimValue || '';
+
+ this.clearDuplicateName();
+ }
+
+ /**
+ * @static
+ * @param {AjaxJsonEmail} oJsonEmail
+ * @return {?EmailModel}
+ */
+ EmailModel.newInstanceFromJson = function (oJsonEmail)
+ {
+ var oEmailModel = new EmailModel();
+ return oEmailModel.initByJson(oJsonEmail) ? oEmailModel : null;
+ };
+
+ /**
+ * @static
+ * @param {string} sLine
+ * @param {string=} sDelimiter = ';'
+ * @return {Array}
+ */
+ EmailModel.splitHelper = function (sLine, sDelimiter)
+ {
+ sDelimiter = sDelimiter || ';';
+
+ sLine = sLine.replace(/[\r\n]+/g, '; ').replace(/[\s]+/g, ' ');
+
+ var
+ iIndex = 0,
+ iLen = sLine.length,
+ bAt = false,
+ sChar = '',
+ sResult = ''
+ ;
+
+ for (; iIndex < iLen; iIndex++)
+ {
+ sChar = sLine.charAt(iIndex);
+ switch (sChar)
+ {
+ case '@':
+ bAt = true;
+ break;
+ case ' ':
+ if (bAt)
+ {
+ bAt = false;
+ sResult += sDelimiter;
+ }
+ break;
+ }
+
+ sResult += sChar;
+ }
+
+ return sResult.split(sDelimiter);
+ };
+
+ /**
+ * @type {string}
+ */
+ EmailModel.prototype.name = '';
+
+ /**
+ * @type {string}
+ */
+ EmailModel.prototype.email = '';
+
+ /**
+ * @type {string}
+ */
+ EmailModel.prototype.dkimStatus = 'none';
+
+ /**
+ * @type {string}
+ */
+ EmailModel.prototype.dkimValue = '';
+
+ EmailModel.prototype.clear = function ()
+ {
+ this.email = '';
+ this.name = '';
+
+ this.dkimStatus = 'none';
+ this.dkimValue = '';
+ };
+
+ /**
+ * @return {boolean}
+ */
+ EmailModel.prototype.validate = function ()
+ {
+ return '' !== this.name || '' !== this.email;
+ };
+
+ /**
+ * @param {boolean} bWithoutName = false
+ * @return {string}
+ */
+ EmailModel.prototype.hash = function (bWithoutName)
+ {
+ return '#' + (bWithoutName ? '' : this.name) + '#' + this.email + '#';
+ };
+
+ EmailModel.prototype.clearDuplicateName = function ()
+ {
+ if (this.name === this.email)
+ {
+ this.name = '';
+ }
+ };
+
+ /**
+ * @param {string} sQuery
+ * @return {boolean}
+ */
+ EmailModel.prototype.search = function (sQuery)
+ {
+ return -1 < (this.name + ' ' + this.email).toLowerCase().indexOf(sQuery.toLowerCase());
+ };
+
+ /**
+ * @param {string} sString
+ */
+ EmailModel.prototype.parse = function (sString)
+ {
+ this.clear();
+
+ sString = Utils.trim(sString);
+
+ var
+ mRegex = /(?:"([^"]+)")? ?[<]?(.*?@[^>,]+)>?,? ?/g,
+ mMatch = mRegex.exec(sString)
+ ;
+
+ if (mMatch)
+ {
+ this.name = mMatch[1] || '';
+ this.email = mMatch[2] || '';
+
+ this.clearDuplicateName();
+ }
+ else if ((/^[^@]+@[^@]+$/).test(sString))
+ {
+ this.name = '';
+ this.email = sString;
+ }
+ };
+
+ /**
+ * @param {AjaxJsonEmail} oJsonEmail
+ * @return {boolean}
+ */
+ EmailModel.prototype.initByJson = function (oJsonEmail)
+ {
+ var bResult = false;
+ if (oJsonEmail && 'Object/Email' === oJsonEmail['@Object'])
+ {
+ this.name = Utils.trim(oJsonEmail.Name);
+ this.email = Utils.trim(oJsonEmail.Email);
+ this.dkimStatus = Utils.trim(oJsonEmail.DkimStatus || '');
+ this.dkimValue = Utils.trim(oJsonEmail.DkimValue || '');
+
+ bResult = '' !== this.email;
+ this.clearDuplicateName();
+ }
+
+ return bResult;
+ };
+
+ /**
+ * @param {boolean} bFriendlyView
+ * @param {boolean=} bWrapWithLink = false
+ * @param {boolean=} bEncodeHtml = false
+ * @return {string}
+ */
+ EmailModel.prototype.toLine = function (bFriendlyView, bWrapWithLink, bEncodeHtml)
+ {
+ var sResult = '';
+ if ('' !== this.email)
+ {
+ bWrapWithLink = Utils.isUnd(bWrapWithLink) ? false : !!bWrapWithLink;
+ bEncodeHtml = Utils.isUnd(bEncodeHtml) ? false : !!bEncodeHtml;
+
+ if (bFriendlyView && '' !== this.name)
+ {
+ sResult = bWrapWithLink ? '
') +
+ '" target="_blank" tabindex="-1">' + Utils.encodeHtml(this.name) + ' ' :
+ (bEncodeHtml ? Utils.encodeHtml(this.name) : this.name);
+ }
+ else
+ {
+ sResult = this.email;
+ if ('' !== this.name)
+ {
+ if (bWrapWithLink)
+ {
+ sResult = Utils.encodeHtml('"' + this.name + '" <') +
+ '
') + '" target="_blank" tabindex="-1">' + Utils.encodeHtml(sResult) + ' ' + Utils.encodeHtml('>');
+ }
+ else
+ {
+ sResult = '"' + this.name + '" <' + sResult + '>';
+ if (bEncodeHtml)
+ {
+ sResult = Utils.encodeHtml(sResult);
+ }
+ }
+ }
+ else if (bWrapWithLink)
+ {
+ sResult = '
' + Utils.encodeHtml(this.email) + ' ';
+ }
+ }
+ }
+
+ return sResult;
+ };
+
+ /**
+ * @param {string} $sEmailAddress
+ * @return {boolean}
+ */
+ EmailModel.prototype.mailsoParse = function ($sEmailAddress)
+ {
+ $sEmailAddress = Utils.trim($sEmailAddress);
+ if ('' === $sEmailAddress)
+ {
+ return false;
+ }
+
+ var
+ substr = function (str, start, len) {
+ str += '';
+ var end = str.length;
+
+ if (start < 0) {
+ start += end;
+ }
+
+ end = typeof len === 'undefined' ? end : (len < 0 ? len + end : len + start);
+
+ return start >= str.length || start < 0 || start > end ? false : str.slice(start, end);
+ },
+
+ substr_replace = function (str, replace, start, length) {
+ if (start < 0) {
+ start = start + str.length;
+ }
+ length = length !== undefined ? length : str.length;
+ if (length < 0) {
+ length = length + str.length - start;
+ }
+ return str.slice(0, start) + replace.substr(0, length) + replace.slice(length) + str.slice(start + length);
+ },
+
+ $sName = '',
+ $sEmail = '',
+ $sComment = '',
+
+ $bInName = false,
+ $bInAddress = false,
+ $bInComment = false,
+
+ $aRegs = null,
+
+ $iStartIndex = 0,
+ $iEndIndex = 0,
+ $iCurrentIndex = 0
+ ;
+
+ while ($iCurrentIndex < $sEmailAddress.length)
+ {
+ switch ($sEmailAddress.substr($iCurrentIndex, 1))
+ {
+ case '"':
+ if ((!$bInName) && (!$bInAddress) && (!$bInComment))
+ {
+ $bInName = true;
+ $iStartIndex = $iCurrentIndex;
+ }
+ else if ((!$bInAddress) && (!$bInComment))
+ {
+ $iEndIndex = $iCurrentIndex;
+ $sName = substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
+ $sEmailAddress = substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+ $iStartIndex = 0;
+ $bInName = false;
+ }
+ break;
+ case '<':
+ if ((!$bInName) && (!$bInAddress) && (!$bInComment))
+ {
+ if ($iCurrentIndex > 0 && $sName.length === 0)
+ {
+ $sName = substr($sEmailAddress, 0, $iCurrentIndex);
+ }
+
+ $bInAddress = true;
+ $iStartIndex = $iCurrentIndex;
+ }
+ break;
+ case '>':
+ if ($bInAddress)
+ {
+ $iEndIndex = $iCurrentIndex;
+ $sEmail = substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
+ $sEmailAddress = substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+ $iStartIndex = 0;
+ $bInAddress = false;
+ }
+ break;
+ case '(':
+ if ((!$bInName) && (!$bInAddress) && (!$bInComment))
+ {
+ $bInComment = true;
+ $iStartIndex = $iCurrentIndex;
+ }
+ break;
+ case ')':
+ if ($bInComment)
+ {
+ $iEndIndex = $iCurrentIndex;
+ $sComment = substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
+ $sEmailAddress = substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+ $iStartIndex = 0;
+ $bInComment = false;
+ }
+ break;
+ case '\\':
+ $iCurrentIndex++;
+ break;
+ }
+
+ $iCurrentIndex++;
+ }
+
+ if ($sEmail.length === 0)
+ {
+ $aRegs = $sEmailAddress.match(/[^@\s]+@\S+/i);
+ if ($aRegs && $aRegs[0])
+ {
+ $sEmail = $aRegs[0];
+ }
+ else
+ {
+ $sName = $sEmailAddress;
+ }
+ }
+
+ if ($sEmail.length > 0 && $sName.length === 0 && $sComment.length === 0)
+ {
+ $sName = $sEmailAddress.replace($sEmail, '');
+ }
+
+ $sEmail = Utils.trim($sEmail).replace(/^[<]+/, '').replace(/[>]+$/, '');
+ $sName = Utils.trim($sName).replace(/^["']+/, '').replace(/["']+$/, '');
+ $sComment = Utils.trim($sComment).replace(/^[(]+/, '').replace(/[)]+$/, '');
+
+ // Remove backslash
+ $sName = $sName.replace(/\\\\(.)/g, '$1');
+ $sComment = $sComment.replace(/\\\\(.)/g, '$1');
+
+ this.name = $sName;
+ this.email = $sEmail;
+
+ this.clearDuplicateName();
+ return true;
+ };
+
+ module.exports = EmailModel;
+
+ }());
+
+/***/ },
+/* 31 */,
+/* 32 */,
+/* 33 */,
+/* 34 */
+/*!******************************!*\
+ !*** ./dev/Stores/Social.js ***!
+ \******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2)
+ ;
+
+ /**
+ * @constructor
+ */
+ function SocialStore()
+ {
+ this.google = {};
+ this.twitter = {};
+ this.facebook = {};
+ this.dropbox = {};
+
+ // Google
+ this.google.enabled = ko.observable(false);
+
+ this.google.clientID = ko.observable('');
+ this.google.clientSecret = ko.observable('');
+ this.google.apiKey = ko.observable('');
+
+ this.google.loading = ko.observable(false);
+ this.google.userName = ko.observable('');
+
+ this.google.loggined = ko.computed(function () {
+ return '' !== this.google.userName();
+ }, this);
+
+ this.google.capa = {};
+ this.google.capa.auth = ko.observable(false);
+ this.google.capa.authFast = ko.observable(false);
+ this.google.capa.drive = ko.observable(false);
+ this.google.capa.preview = ko.observable(false);
+
+ this.google.require = {};
+ this.google.require.clientSettings = ko.computed(function () {
+ return this.google.enabled() && (this.google.capa.auth() || this.google.capa.drive());
+ }, this);
+
+ this.google.require.apiKeySettings = ko.computed(function () {
+ return this.google.enabled() && this.google.capa.drive();
+ }, this);
+
+ // Facebook
+ this.facebook.enabled = ko.observable(false);
+ this.facebook.appID = ko.observable('');
+ this.facebook.appSecret = ko.observable('');
+ this.facebook.loading = ko.observable(false);
+ this.facebook.userName = ko.observable('');
+ this.facebook.supported = ko.observable(false);
+
+ this.facebook.loggined = ko.computed(function () {
+ return '' !== this.facebook.userName();
+ }, this);
+
+ // Twitter
+ this.twitter.enabled = ko.observable(false);
+ this.twitter.consumerKey = ko.observable('');
+ this.twitter.consumerSecret = ko.observable('');
+ this.twitter.loading = ko.observable(false);
+ this.twitter.userName = ko.observable('');
+
+ this.twitter.loggined = ko.computed(function () {
+ return '' !== this.twitter.userName();
+ }, this);
+
+ // Dropbox
+ this.dropbox.enabled = ko.observable(false);
+ this.dropbox.apiKey = ko.observable('');
+ }
+
+ SocialStore.prototype.google = {};
+ SocialStore.prototype.twitter = {};
+ SocialStore.prototype.facebook = {};
+ SocialStore.prototype.dropbox = {};
+
+ SocialStore.prototype.populate = function ()
+ {
+ var Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ this.google.enabled(!!Settings.settingsGet('AllowGoogleSocial'));
+ this.google.clientID(Settings.settingsGet('GoogleClientID'));
+ this.google.clientSecret(Settings.settingsGet('GoogleClientSecret'));
+ this.google.apiKey(Settings.settingsGet('GoogleApiKey'));
+
+ this.google.capa.auth(!!Settings.settingsGet('AllowGoogleSocialAuth'));
+ this.google.capa.authFast(!!Settings.settingsGet('AllowGoogleSocialAuthFast'));
+ this.google.capa.drive(!!Settings.settingsGet('AllowGoogleSocialDrive'));
+ this.google.capa.preview(!!Settings.settingsGet('AllowGoogleSocialPreview'));
+
+ this.facebook.enabled(!!Settings.settingsGet('AllowFacebookSocial'));
+ this.facebook.appID(Settings.settingsGet('FacebookAppID'));
+ this.facebook.appSecret(Settings.settingsGet('FacebookAppSecret'));
+ this.facebook.supported(!!Settings.settingsGet('SupportedFacebookSocial'));
+
+ this.twitter.enabled = ko.observable(!!Settings.settingsGet('AllowTwitterSocial'));
+ this.twitter.consumerKey = ko.observable(Settings.settingsGet('TwitterConsumerKey'));
+ this.twitter.consumerSecret = ko.observable(Settings.settingsGet('TwitterConsumerSecret'));
+
+ this.dropbox.enabled(!!Settings.settingsGet('AllowDropboxSocial'));
+ this.dropbox.apiKey(Settings.settingsGet('DropboxApiKey'));
+ };
+
+ module.exports = new SocialStore();
+
+ }());
+
+
+/***/ },
+/* 35 */
+/*!**********************************!*\
+ !*** ./dev/Stores/Admin/App.jsx ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ var _AbstractApp = __webpack_require__(/*! Stores/AbstractApp */ 76);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var AppAdminStore = function (_AbstractAppStore) {
+ _inherits(AppAdminStore, _AbstractAppStore);
+
+ function AppAdminStore() {
+ _classCallCheck(this, AppAdminStore);
+
+ var _this = _possibleConstructorReturn(this, _AbstractAppStore.call(this));
+
+ _this.determineUserLanguage = _ko2.default.observable(false);
+ _this.determineUserDomain = _ko2.default.observable(false);
+
+ _this.weakPassword = _ko2.default.observable(false);
+ _this.useLocalProxyForExternalImages = _ko2.default.observable(false);
+ return _this;
+ }
+
+ AppAdminStore.prototype.populate = function populate() {
+
+ _AbstractAppStore.prototype.populate.call(this);
+
+ this.determineUserLanguage(!!_Settings2.default.settingsGet('DetermineUserLanguage'));
+ this.determineUserDomain(!!_Settings2.default.settingsGet('DetermineUserDomain'));
+
+ this.weakPassword(!!_Settings2.default.settingsGet('WeakPassword'));
+ this.useLocalProxyForExternalImages(!!_Settings2.default.settingsGet('UseLocalProxyForExternalImages'));
+ };
+
+ return AppAdminStore;
+ }(_AbstractApp.AbstractAppStore);
+
+ module.exports = new AppAdminStore();
+
+/***/ },
+/* 36 */
+/*!******************************!*\
+ !*** external "window.JSON" ***!
+ \******************************/
+/***/ function(module, exports) {
+
+ module.exports = window.JSON;
+
+/***/ },
+/* 37 */
+/*!*****************************************!*\
+ !*** ./dev/Component/AbstractInput.jsx ***!
+ \*****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.AbstractInput = undefined;
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Enums = __webpack_require__(/*! Common/Enums */ 4);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var AbstractInput = function (_AbstractComponent) {
+ _inherits(AbstractInput, _AbstractComponent);
+
+ /**
+ * @param {Object} params
+ */
+
+ function AbstractInput(params) {
+ _classCallCheck(this, AbstractInput);
+
+ var _this = _possibleConstructorReturn(this, _AbstractComponent.call(this));
+
+ _this.value = params.value || '';
+ _this.size = params.size || 0;
+ _this.label = params.label || '';
+ _this.preLabel = params.preLabel || '';
+ _this.enable = _Utils2.default.isUnd(params.enable) ? true : params.enable;
+ _this.trigger = params.trigger && params.trigger.subscribe ? params.trigger : null;
+ _this.placeholder = params.placeholder || '';
+
+ _this.labeled = !_Utils2.default.isUnd(params.label);
+ _this.preLabeled = !_Utils2.default.isUnd(params.preLabel);
+ _this.triggered = !_Utils2.default.isUnd(params.trigger) && !!_this.trigger;
+
+ _this.classForTrigger = _ko2.default.observable('');
+
+ _this.className = _ko2.default.computed(function () {
+
+ var size = _ko2.default.unwrap(_this.size),
+ suffixValue = _this.trigger ? ' ' + _Utils2.default.trim('settings-saved-trigger-input ' + _this.classForTrigger()) : '';
+
+ return (size > 0 ? 'span' + size : '') + suffixValue;
+ }, _this);
+
+ if (!_Utils2.default.isUnd(params.width) && params.element) {
+ params.element.find('input,select,textarea').css('width', params.width);
+ }
+
+ _this.disposable.push(_this.className);
+
+ if (_this.trigger) {
+ _this.setTriggerState(_this.trigger());
+
+ _this.disposable.push(_this.trigger.subscribe(_this.setTriggerState, _this));
+ }
+ return _this;
+ }
+
+ AbstractInput.prototype.setTriggerState = function setTriggerState(value) {
+ switch (_Utils2.default.pInt(value)) {
+ case _Enums.SaveSettingsStep.TrueResult:
+ this.classForTrigger('success');
+ break;
+ case _Enums.SaveSettingsStep.FalseResult:
+ this.classForTrigger('error');
+ break;
+ default:
+ this.classForTrigger('');
+ break;
+ }
+ };
+
+ return AbstractInput;
+ }(_Abstract.AbstractComponent);
+
+ exports.AbstractInput = AbstractInput;
+ exports.default = AbstractInput;
+
+/***/ },
+/* 38 */
+/*!************************************!*\
+ !*** ./dev/Component/Checkbox.jsx ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ var _AbstracCheckbox2 = __webpack_require__(/*! Component/AbstracCheckbox */ 46);
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var CheckboxComponent = function (_AbstracCheckbox) {
+ _inherits(CheckboxComponent, _AbstracCheckbox);
+
+ function CheckboxComponent() {
+ _classCallCheck(this, CheckboxComponent);
+
+ return _possibleConstructorReturn(this, _AbstracCheckbox.apply(this, arguments));
+ }
+
+ return CheckboxComponent;
+ }(_AbstracCheckbox2.AbstracCheckbox);
+
+ module.exports = (0, _Abstract.componentExportHelper)(CheckboxComponent, 'CheckboxComponent');
+
+/***/ },
+/* 39 */
+/*!*************************************!*\
+ !*** ./dev/Knoin/AbstractScreen.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ crossroads = __webpack_require__(/*! crossroads */ 49),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1)
+ ;
+
+ /**
+ * @param {string} sScreenName
+ * @param {?=} aViewModels = []
+ * @constructor
+ */
+ function AbstractScreen(sScreenName, aViewModels)
+ {
+ this.sScreenName = sScreenName;
+ this.aViewModels = Utils.isArray(aViewModels) ? aViewModels : [];
+ }
+
+ /**
+ * @type {Array}
+ */
+ AbstractScreen.prototype.oCross = null;
+
+ /**
+ * @type {string}
+ */
+ AbstractScreen.prototype.sScreenName = '';
+
+ /**
+ * @type {Array}
+ */
+ AbstractScreen.prototype.aViewModels = [];
+
+ /**
+ * @return {Array}
+ */
+ AbstractScreen.prototype.viewModels = function ()
+ {
+ return this.aViewModels;
+ };
+
+ /**
+ * @return {string}
+ */
+ AbstractScreen.prototype.screenName = function ()
+ {
+ return this.sScreenName;
+ };
+
+ AbstractScreen.prototype.routes = function ()
+ {
+ return null;
+ };
+
+ /**
+ * @return {?Object}
+ */
+ AbstractScreen.prototype.__cross = function ()
+ {
+ return this.oCross;
+ };
+
+ AbstractScreen.prototype.__start = function ()
+ {
+ var
+ aRoutes = this.routes(),
+ oRoute = null,
+ fMatcher = null
+ ;
+
+ if (Utils.isNonEmptyArray(aRoutes))
+ {
+ fMatcher = _.bind(this.onRoute || Utils.emptyFunction, this);
+ oRoute = crossroads.create();
+
+ _.each(aRoutes, function (aItem) {
+ oRoute.addRoute(aItem[0], fMatcher).rules = aItem[1];
+ });
+
+ this.oCross = oRoute;
+ }
+ };
+
+ module.exports = AbstractScreen;
+
+ }());
+
+/***/ },
+/* 40 */
+/*!********************************!*\
+ !*** ./dev/Stores/Language.js ***!
+ \********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function LanguageStore()
+ {
+ this.languages = ko.observableArray([]);
+ this.languagesAdmin = ko.observableArray([]);
+
+ this.language = ko.observable('')
+ .extend({'limitedList': this.languages});
+
+ this.languageAdmin = ko.observable('')
+ .extend({'limitedList': this.languagesAdmin});
+
+ this.userLanguage = ko.observable('');
+ this.userLanguageAdmin = ko.observable('');
+ }
+
+ LanguageStore.prototype.populate = function ()
+ {
+ var
+ aLanguages = Settings.appSettingsGet('languages'),
+ aLanguagesAdmin = Settings.appSettingsGet('languagesAdmin')
+ ;
+
+ this.languages(Utils.isArray(aLanguages) ? aLanguages : []);
+ this.languagesAdmin(Utils.isArray(aLanguagesAdmin) ? aLanguagesAdmin : []);
+
+ this.language(Settings.settingsGet('Language'));
+ this.languageAdmin(Settings.settingsGet('LanguageAdmin'));
+
+ this.userLanguage(Settings.settingsGet('UserLanguage'));
+ this.userLanguageAdmin(Settings.settingsGet('UserLanguageAdmin'));
+ };
+
+ module.exports = new LanguageStore();
+
+ }());
+
+
+/***/ },
+/* 41 */,
+/* 42 */
+/*!*****************************!*\
+ !*** ./dev/Stores/Theme.js ***!
+ \*****************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function ThemeStore()
+ {
+ this.themes = ko.observableArray([]);
+ this.themeBackgroundName = ko.observable('');
+ this.themeBackgroundHash = ko.observable('');
+
+ this.theme = ko.observable('')
+ .extend({'limitedList': this.themes});
+ }
+
+ ThemeStore.prototype.populate = function ()
+ {
+ var aThemes = Settings.appSettingsGet('themes');
+
+ this.themes(Utils.isArray(aThemes) ? aThemes : []);
+ this.theme(Settings.settingsGet('Theme'));
+ this.themeBackgroundName(Settings.settingsGet('UserBackgroundName'));
+ this.themeBackgroundHash(Settings.settingsGet('UserBackgroundHash'));
+ };
+
+ module.exports = new ThemeStore();
+
+ }());
+
+
+/***/ },
+/* 43 */
+/*!*******************************!*\
+ !*** ./dev/View/Popup/Ask.js ***!
+ \*******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+ key = __webpack_require__(/*! key */ 18),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function AskPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsAsk');
+
+ this.askDesc = ko.observable('');
+ this.yesButton = ko.observable('');
+ this.noButton = ko.observable('');
+
+ this.yesFocus = ko.observable(false);
+ this.noFocus = ko.observable(false);
+
+ this.fYesAction = null;
+ this.fNoAction = null;
+
+ this.bFocusYesOnShow = true;
+ this.bDisabeCloseOnEsc = true;
+ this.sDefaultKeyScope = Enums.KeyState.PopupAsk;
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/Ask', 'PopupsAskViewModel'], AskPopupView);
+ _.extend(AskPopupView.prototype, AbstractView.prototype);
+
+ AskPopupView.prototype.clearPopup = function ()
+ {
+ this.askDesc('');
+ this.yesButton(Translator.i18n('POPUPS_ASK/BUTTON_YES'));
+ this.noButton(Translator.i18n('POPUPS_ASK/BUTTON_NO'));
+
+ this.yesFocus(false);
+ this.noFocus(false);
+
+ this.fYesAction = null;
+ this.fNoAction = null;
+ };
+
+ AskPopupView.prototype.yesClick = function ()
+ {
+ this.cancelCommand();
+
+ if (Utils.isFunc(this.fYesAction))
+ {
+ this.fYesAction.call(null);
+ }
+ };
+
+ AskPopupView.prototype.noClick = function ()
+ {
+ this.cancelCommand();
+
+ if (Utils.isFunc(this.fNoAction))
+ {
+ this.fNoAction.call(null);
+ }
+ };
+
+ /**
+ * @param {string} sAskDesc
+ * @param {Function=} fYesFunc
+ * @param {Function=} fNoFunc
+ * @param {string=} sYesButton
+ * @param {string=} sNoButton
+ * @param {boolean=} bFocusYesOnShow
+ */
+ AskPopupView.prototype.onShow = function (sAskDesc, fYesFunc, fNoFunc, sYesButton, sNoButton, bFocusYesOnShow)
+ {
+ this.clearPopup();
+
+ this.fYesAction = fYesFunc || null;
+ this.fNoAction = fNoFunc || null;
+
+ this.askDesc(sAskDesc || '');
+ if (sYesButton)
+ {
+ this.yesButton(sYesButton);
+ }
+
+ if (sYesButton)
+ {
+ this.yesButton(sNoButton);
+ }
+
+ this.bFocusYesOnShow = Utils.isUnd(bFocusYesOnShow) ? true : !!bFocusYesOnShow;
+ };
+
+ AskPopupView.prototype.onShowWithDelay = function ()
+ {
+ if (this.bFocusYesOnShow)
+ {
+ this.yesFocus(true);
+ }
+ };
+
+ AskPopupView.prototype.onBuild = function ()
+ {
+ key('tab, shift+tab, right, left', Enums.KeyState.PopupAsk, _.bind(function () {
+ if (this.yesFocus())
+ {
+ this.noFocus(true);
+ }
+ else
+ {
+ this.yesFocus(true);
+ }
+ return false;
+ }, this));
+
+ key('esc', Enums.KeyState.PopupAsk, _.bind(function () {
+ this.noClick();
+ return false;
+ }, this));
+ };
+
+ module.exports = AskPopupView;
+
+ }());
+
+/***/ },
+/* 44 */
+/*!*************************************!*\
+ !*** ./dev/View/Popup/Languages.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function LanguagesPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsLanguages');
+
+ var self = this;
+
+ this.fLang = null;
+ this.userLanguage = ko.observable('');
+
+ this.langs = ko.observableArray([]);
+
+ this.languages = ko.computed(function () {
+ var sUserLanguage = self.userLanguage();
+ return _.map(self.langs(), function (sLanguage) {
+ return {
+ 'key': sLanguage,
+ 'user': sLanguage === sUserLanguage,
+ 'selected': ko.observable(false),
+ 'fullName': Utils.convertLangName(sLanguage)
+ };
+ });
+ });
+
+ this.langs.subscribe(function () {
+ this.setLanguageSelection();
+ }, this);
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/Languages', 'PopupsLanguagesViewModel'], LanguagesPopupView);
+ _.extend(LanguagesPopupView.prototype, AbstractView.prototype);
+
+ LanguagesPopupView.prototype.languageTooltipName = function (sLanguage)
+ {
+ var sResult = Utils.convertLangName(sLanguage, true);
+ return Utils.convertLangName(sLanguage, false) === sResult ? '' : sResult;
+ };
+
+ LanguagesPopupView.prototype.setLanguageSelection = function ()
+ {
+ var sCurrent = this.fLang ? ko.unwrap(this.fLang) : '';
+ _.each(this.languages(), function (oItem) {
+ oItem['selected'](oItem['key'] === sCurrent);
+ });
+ };
+
+ LanguagesPopupView.prototype.onBeforeShow = function ()
+ {
+ this.fLang = null;
+ this.userLanguage('');
+
+ this.langs([]);
+ };
+
+ LanguagesPopupView.prototype.onShow = function (fLanguage, aLangs, sUserLanguage)
+ {
+ this.fLang = fLanguage;
+ this.userLanguage(sUserLanguage || '');
+
+ this.langs(aLangs);
+ };
+
+ LanguagesPopupView.prototype.changeLanguage = function (sLang)
+ {
+ if (this.fLang)
+ {
+ this.fLang(sLang);
+ }
+
+ this.cancelCommand();
+ };
+
+ module.exports = LanguagesPopupView;
+
+ }());
+
+/***/ },
+/* 45 */
+/*!***********************************!*\
+ !*** ./dev/Common/HtmlEditor.jsx ***!
+ \***********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.HtmlEditor = undefined;
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ var _Globals2 = _interopRequireDefault(_Globals);
+
+ var _Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var HtmlEditor = function () {
+
+ /**
+ * @param {Object} element
+ * @param {Function=} onBlur
+ * @param {Function=} onReady
+ * @param {Function=} onModeChange
+ */
+
+ function HtmlEditor(element) {
+ var onBlur = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1];
+ var onReady = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2];
+ var onModeChange = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3];
+
+ _classCallCheck(this, HtmlEditor);
+
+ this.editor = null;
+ this.$element = null;
+ this.blurTimer = 0;
+ this.onBlur = null;
+ this.onReady = null;
+ this.onModeChange = null;
+ this.__inited = null;
+
+ this.onBlur = onBlur;
+ this.onReady = onReady;
+ this.onModeChange = onModeChange;
+
+ this.$element = (0, _common.$)(element);
+
+ this.resize = _common._.throttle(_common._.bind(this.resize, this), 100);
+
+ this.__inited = false;
+
+ this.init();
+ }
+
+ HtmlEditor.prototype.blurTrigger = function blurTrigger() {
+ var _this = this;
+
+ if (this.onBlur) {
+ _common.window.clearTimeout(this.blurTimer);
+ this.blurTimer = _common.window.setTimeout(function () {
+ _this.onBlur();
+ }, 200);
+ }
+ };
+
+ HtmlEditor.prototype.focusTrigger = function focusTrigger() {
+ if (this.onBlur) {
+ _common.window.clearTimeout(this.blurTimer);
+ }
+ };
+
+ /**
+ * @return {boolean}
+ */
+
+
+ HtmlEditor.prototype.isHtml = function isHtml() {
+ return this.editor ? 'wysiwyg' === this.editor.mode : false;
+ };
+
+ /**
+ * @param {string} signature
+ * @param {bool} html
+ * @param {bool} insertBefore
+ */
+
+
+ HtmlEditor.prototype.setSignature = function setSignature(signature, html, insertBefore) {
+ if (this.editor) {
+ this.editor.execCommand('insertSignature', {
+ isHtml: html,
+ insertBefore: insertBefore,
+ signature: signature
+ });
+ }
+ };
+
+ /**
+ * @return {boolean}
+ */
+
+
+ HtmlEditor.prototype.checkDirty = function checkDirty() {
+ return this.editor ? this.editor.checkDirty() : false;
+ };
+
+ HtmlEditor.prototype.resetDirty = function resetDirty() {
+ if (this.editor) {
+ this.editor.resetDirty();
+ }
+ };
+
+ /**
+ * @param {string} text
+ * @return {string}
+ */
+
+
+ HtmlEditor.prototype.clearSignatureSigns = function clearSignatureSigns(text) {
+ return text.replace(/(\u200C|\u0002)/g, '');
+ };
+
+ /**
+ * @param {boolean=} wrapIsHtml = false
+ * @param {boolean=} clearSignatureSigns = false
+ * @return {string}
+ */
+
+
+ HtmlEditor.prototype.getData = function getData() {
+ var wrapIsHtml = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
+ var clearSignatureSigns = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
+
+
+ var result = '';
+ if (this.editor) {
+ try {
+ if ('plain' === this.editor.mode && this.editor.plugins.plain && this.editor.__plain) {
+ result = this.editor.__plain.getRawData();
+ } else {
+ result = wrapIsHtml ? '
' + this.editor.getData() + '
' : this.editor.getData();
+ }
+ } catch (e) {/* eslint-disable-line no-empty */}
+
+ if (clearSignatureSigns) {
+ result = this.clearSignatureSigns(result);
+ }
+ }
+
+ return result;
+ };
+
+ /**
+ * @param {boolean=} wrapIsHtml = false
+ * @param {boolean=} clearSignatureSigns = false
+ * @return {string}
+ */
+
+
+ HtmlEditor.prototype.getDataWithHtmlMark = function getDataWithHtmlMark() {
+ var wrapIsHtml = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
+ var clearSignatureSigns = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
+
+ return (this.isHtml() ? ':HTML:' : '') + this.getData(wrapIsHtml, clearSignatureSigns);
+ };
+
+ HtmlEditor.prototype.modeToggle = function modeToggle(plain, resize) {
+ if (this.editor) {
+ try {
+ if (plain) {
+ if ('plain' === this.editor.mode) {
+ this.editor.setMode('wysiwyg');
+ }
+ } else {
+ if ('wysiwyg' === this.editor.mode) {
+ this.editor.setMode('plain');
+ }
+ }
+ } catch (e) {/* eslint-disable-line no-empty */}
+
+ if (resize) {
+ this.resize();
+ }
+ }
+ };
+
+ HtmlEditor.prototype.setHtmlOrPlain = function setHtmlOrPlain(text, focus) {
+ if (':HTML:' === text.substr(0, 6)) {
+ this.setHtml(text.substr(6), focus);
+ } else {
+ this.setPlain(text, focus);
+ }
+ };
+
+ HtmlEditor.prototype.setHtml = function setHtml(html, focus) {
+ if (this.editor && this.__inited) {
+ this.modeToggle(true);
+
+ html = html.replace(/
]*><\/p>/ig, '');
+
+ try {
+ this.editor.setData(html);
+ } catch (e) {/* eslint-disable-line no-empty */}
+
+ if (focus) {
+ this.focus();
+ }
+ }
+ };
+
+ HtmlEditor.prototype.replaceHtml = function replaceHtml(find, _replaceHtml) {
+ if (this.editor && this.__inited && 'wysiwyg' === this.editor.mode) {
+ try {
+ this.editor.setData(this.editor.getData().replace(find, _replaceHtml));
+ } catch (e) {/* eslint-disable-line no-empty */}
+ }
+ };
+
+ HtmlEditor.prototype.setPlain = function setPlain(plain, focus) {
+ if (this.editor && this.__inited) {
+ this.modeToggle(false);
+ if ('plain' === this.editor.mode && this.editor.plugins.plain && this.editor.__plain) {
+ this.editor.__plain.setRawData(plain);
+ } else {
+ try {
+ this.editor.setData(plain);
+ } catch (e) {/* eslint-disable-line no-empty */}
+ }
+
+ if (focus) {
+ this.focus();
+ }
+ }
+ };
+
+ HtmlEditor.prototype.init = function init() {
+ var _this2 = this;
+
+ if (this.$element && this.$element[0] && !this.editor) {
+ var initFunc = function initFunc() {
+
+ var config = _Globals2.default.oHtmlEditorDefaultConfig,
+ language = _Settings2.default.settingsGet('Language'),
+ allowSource = !!_Settings2.default.appSettingsGet('allowHtmlEditorSourceButton'),
+ biti = !!_Settings2.default.appSettingsGet('allowHtmlEditorBitiButtons');
+
+ if ((allowSource || !biti) && !config.toolbarGroups.__cfgInited) {
+ config.toolbarGroups.__cfgInited = true;
+
+ if (allowSource) {
+ config.removeButtons = config.removeButtons.replace(',Source', '');
+ }
+
+ if (!biti) {
+ config.removePlugins += (config.removePlugins ? ',' : '') + 'bidi';
+ }
+ }
+
+ config.enterMode = _common.window.CKEDITOR.ENTER_BR;
+ config.shiftEnterMode = _common.window.CKEDITOR.ENTER_P;
+
+ config.language = _Globals2.default.oHtmlEditorLangsMap[language] || 'en';
+ if (_common.window.CKEDITOR.env) {
+ _common.window.CKEDITOR.env.isCompatible = true;
+ }
+
+ _this2.editor = _common.window.CKEDITOR.appendTo(_this2.$element[0], config);
+
+ _this2.editor.on('key', function (event) {
+ if (event && event.data && 9 /* Tab */ === event.data.keyCode) {
+ return false;
+ }
+ });
+
+ _this2.editor.on('blur', function () {
+ _this2.blurTrigger();
+ });
+
+ _this2.editor.on('mode', function () {
+ _this2.blurTrigger();
+ if (_this2.onModeChange) {
+ _this2.onModeChange('plain' !== _this2.editor.mode);
+ }
+ });
+
+ _this2.editor.on('focus', function () {
+ _this2.focusTrigger();
+ });
+
+ if (_common.window.FileReader) {
+ _this2.editor.on('drop', function (event) {
+ if (0 < event.data.dataTransfer.getFilesCount()) {
+ var file = event.data.dataTransfer.getFile(0);
+ if (file && _common.window.FileReader && event.data.dataTransfer.id && file.type && file.type.match(/^image/i)) {
+ var id = event.data.dataTransfer.id,
+ imageId = '[img=' + id + ']',
+ reader = new _common.window.FileReader();
+
+ reader.onloadend = function () {
+ if (reader.result) {
+ _this2.replaceHtml(imageId, ' ');
+ }
+ };
+
+ reader.readAsDataURL(file);
+
+ event.data.dataTransfer.setData('text/html', imageId);
+ }
+ }
+ });
+ }
+
+ _this2.editor.on('instanceReady', function () {
+
+ if (_this2.editor.removeMenuItem) {
+ _this2.editor.removeMenuItem('cut');
+ _this2.editor.removeMenuItem('copy');
+ _this2.editor.removeMenuItem('paste');
+ }
+
+ _this2.__resizable = true;
+ _this2.__inited = true;
+
+ _this2.resize();
+
+ if (_this2.onReady) {
+ _this2.onReady();
+ }
+ });
+ };
+
+ if (_common.window.CKEDITOR) {
+ initFunc();
+ } else {
+ _common.window.__initEditor = initFunc;
+ }
+ }
+ };
+
+ HtmlEditor.prototype.focus = function focus() {
+ if (this.editor) {
+ try {
+ this.editor.focus();
+ } catch (e) {/* eslint-disable-line no-empty */}
+ }
+ };
+
+ HtmlEditor.prototype.hasFocus = function hasFocus() {
+ if (this.editor) {
+ try {
+ return !!this.editor.focusManager.hasFocus;
+ } catch (e) {/* eslint-disable-line no-empty */}
+ }
+
+ return false;
+ };
+
+ HtmlEditor.prototype.blur = function blur() {
+ if (this.editor) {
+ try {
+ this.editor.focusManager.blur(true);
+ } catch (e) {/* eslint-disable-line no-empty */}
+ }
+ };
+
+ HtmlEditor.prototype.resize = function resize() {
+ if (this.editor && this.__resizable) {
+ try {
+ this.editor.resize(this.$element.width(), this.$element.innerHeight());
+ } catch (e) {/* eslint-disable-line no-empty */}
+ }
+ };
+
+ HtmlEditor.prototype.setReadOnly = function setReadOnly(value) {
+ if (this.editor) {
+ try {
+ this.editor.setReadOnly(!!value);
+ } catch (e) {/* eslint-disable-line no-empty */}
+ }
+ };
+
+ HtmlEditor.prototype.clear = function clear(focus) {
+ this.setHtml('', focus);
+ };
+
+ return HtmlEditor;
+ }();
+
+ exports.HtmlEditor = HtmlEditor;
+ exports.default = HtmlEditor;
+
+ module.exports = HtmlEditor;
+
+/***/ },
+/* 46 */
+/*!*******************************************!*\
+ !*** ./dev/Component/AbstracCheckbox.jsx ***!
+ \*******************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.AbstracCheckbox = undefined;
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var AbstracCheckbox = function (_AbstractComponent) {
+ _inherits(AbstracCheckbox, _AbstractComponent);
+
+ /**
+ * @param {Object} params = {}
+ */
+
+ function AbstracCheckbox() {
+ var params = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
+
+ _classCallCheck(this, AbstracCheckbox);
+
+ var _this = _possibleConstructorReturn(this, _AbstractComponent.call(this));
+
+ _this.value = params.value;
+ if (_Utils2.default.isUnd(_this.value) || !_this.value.subscribe) {
+ _this.value = _ko2.default.observable(_Utils2.default.isUnd(_this.value) ? false : !!_this.value);
+ }
+
+ _this.enable = params.enable;
+ if (_Utils2.default.isUnd(_this.enable) || !_this.enable.subscribe) {
+ _this.enable = _ko2.default.observable(_Utils2.default.isUnd(_this.enable) ? true : !!_this.enable);
+ }
+
+ _this.disable = params.disable;
+ if (_Utils2.default.isUnd(_this.disable) || !_this.disable.subscribe) {
+ _this.disable = _ko2.default.observable(_Utils2.default.isUnd(_this.disable) ? false : !!_this.disable);
+ }
+
+ _this.label = params.label || '';
+ _this.inline = _Utils2.default.isUnd(params.inline) ? false : params.inline;
+
+ _this.readOnly = _Utils2.default.isUnd(params.readOnly) ? false : !!params.readOnly;
+ _this.inverted = _Utils2.default.isUnd(params.inverted) ? false : !!params.inverted;
+
+ _this.labeled = !_Utils2.default.isUnd(params.label);
+ _this.labelAnimated = !!params.labelAnimated;
+ return _this;
+ }
+
+ AbstracCheckbox.prototype.click = function click() {
+ if (!this.readOnly && this.enable() && !this.disable()) {
+ this.value(!this.value());
+ }
+ };
+
+ return AbstracCheckbox;
+ }(_Abstract.AbstractComponent);
+
+ exports.AbstracCheckbox = AbstracCheckbox;
+ exports.default = AbstracCheckbox;
+
+/***/ },
+/* 47 */,
+/* 48 */
+/*!***************************!*\
+ !*** external "window.Q" ***!
+ \***************************/
+/***/ function(module, exports) {
+
+ module.exports = window.Q;
+
+/***/ },
+/* 49 */
+/*!************************************!*\
+ !*** external "window.crossroads" ***!
+ \************************************/
+/***/ function(module, exports) {
+
+ module.exports = window.crossroads;
+
+/***/ },
+/* 50 */
+/*!**********************************!*\
+ !*** ./dev/Stores/Admin/Capa.js ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function CapaAdminStore()
+ {
+ this.additionalAccounts = ko.observable(false);
+ this.identities = ko.observable(false);
+ this.gravatar = ko.observable(false);
+ this.attachmentThumbnails = ko.observable(false);
+ this.sieve = ko.observable(false);
+ this.filters = ko.observable(false);
+ this.themes = ko.observable(true);
+ this.userBackground = ko.observable(false);
+ this.openPGP = ko.observable(false);
+ this.twoFactorAuth = ko.observable(false);
+ this.twoFactorAuthForce = ko.observable(false);
+ this.templates = ko.observable(false);
+ }
+
+ CapaAdminStore.prototype.populate = function()
+ {
+ this.additionalAccounts(Settings.capa(Enums.Capa.AdditionalAccounts));
+ this.identities(Settings.capa(Enums.Capa.Identities));
+ this.gravatar(Settings.capa(Enums.Capa.Gravatar));
+ this.attachmentThumbnails(Settings.capa(Enums.Capa.AttachmentThumbnails));
+ this.sieve(Settings.capa(Enums.Capa.Sieve));
+ this.filters(Settings.capa(Enums.Capa.Filters));
+ this.themes(Settings.capa(Enums.Capa.Themes));
+ this.userBackground(Settings.capa(Enums.Capa.UserBackground));
+ this.openPGP(Settings.capa(Enums.Capa.OpenPGP));
+ this.twoFactorAuth(Settings.capa(Enums.Capa.TwoFactor));
+ this.twoFactorAuthForce(Settings.capa(Enums.Capa.TwoFactorForce));
+ this.templates(Settings.capa(Enums.Capa.Templates));
+ };
+
+ module.exports = new CapaAdminStore();
+
+ }());
+
+
+/***/ },
+/* 51 */,
+/* 52 */,
+/* 53 */,
+/* 54 */
+/*!*********************************!*\
+ !*** ./dev/External/Opentip.js ***!
+ \*********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ Opentip = window.Opentip
+ ;
+
+ Opentip.styles.rainloop = {
+
+ 'extends': 'standard',
+
+ 'fixed': true,
+ 'target': true,
+
+ 'delay': 0.2,
+ 'hideDelay': 0,
+
+ 'hideEffect': 'fade',
+ 'hideEffectDuration': 0.2,
+
+ 'showEffect': 'fade',
+ 'showEffectDuration': 0.2,
+
+ 'showOn': 'mouseover click',
+ 'removeElementsOnHide': true,
+
+ 'background': '#fff',
+ 'shadow': false,
+
+ 'borderColor': '#999',
+ 'borderRadius': 2,
+ 'borderWidth': 1
+ };
+
+ Opentip.styles.rainloopTip = {
+ 'extends': 'rainloop',
+ 'delay': 0.4,
+ 'group': 'rainloopTips'
+ };
+
+ Opentip.styles.rainloopErrorTip = {
+ 'extends': 'rainloop',
+ 'className': 'rainloopErrorTip'
+ };
+
+ module.exports = Opentip;
+
+ }());
+
+
+/***/ },
+/* 55 */
+/*!************************************!*\
+ !*** ./dev/Remote/AbstractAjax.js ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Plugins = __webpack_require__(/*! Common/Plugins */ 23),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function AbstractAjaxRemote()
+ {
+ this.oRequests = {};
+ }
+
+ AbstractAjaxRemote.prototype.oRequests = {};
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sRequestAction
+ * @param {string} sType
+ * @param {?AjaxJsonDefaultResponse} oData
+ * @param {boolean} bCached
+ * @param {*=} oRequestParameters
+ */
+ AbstractAjaxRemote.prototype.defaultResponse = function (fCallback, sRequestAction, sType, oData, bCached, oRequestParameters)
+ {
+ var
+ fCall = function () {
+ if (Enums.StorageResultType.Success !== sType && Globals.bUnload)
+ {
+ sType = Enums.StorageResultType.Unload;
+ }
+
+ if (Enums.StorageResultType.Success === sType && oData && !oData.Result)
+ {
+ if (oData && -1 < Utils.inArray(oData.ErrorCode, [
+ Enums.Notification.AuthError, Enums.Notification.AccessError,
+ Enums.Notification.ConnectionError, Enums.Notification.DomainNotAllowed, Enums.Notification.AccountNotAllowed,
+ Enums.Notification.MailServerError, Enums.Notification.UnknownNotification, Enums.Notification.UnknownError
+ ]))
+ {
+ Globals.iAjaxErrorCount++;
+ }
+
+ if (oData && Enums.Notification.InvalidToken === oData.ErrorCode)
+ {
+ Globals.iTokenErrorCount++;
+ }
+
+ if (Consts.TOKEN_ERROR_LIMIT < Globals.iTokenErrorCount)
+ {
+ if (Globals.__APP__ && Globals.__APP__.loginAndLogoutReload)
+ {
+ Globals.__APP__.loginAndLogoutReload(false, true);
+ }
+ }
+
+ if (oData.ClearAuth || oData.Logout || Consts.AJAX_ERROR_LIMIT < Globals.iAjaxErrorCount)
+ {
+ if (Globals.__APP__ && Globals.__APP__.clearClientSideToken)
+ {
+ Globals.__APP__.clearClientSideToken();
+
+ if (!oData.ClearAuth && Globals.__APP__.loginAndLogoutReload)
+ {
+ Globals.__APP__.loginAndLogoutReload(false, true);
+ }
+ }
+ }
+ }
+ else if (Enums.StorageResultType.Success === sType && oData && oData.Result)
+ {
+ Globals.iAjaxErrorCount = 0;
+ Globals.iTokenErrorCount = 0;
+ }
+
+ if (fCallback)
+ {
+ Plugins.runHook('ajax-default-response', [sRequestAction, Enums.StorageResultType.Success === sType ? oData : null, sType, bCached, oRequestParameters]);
+
+ fCallback(
+ sType,
+ Enums.StorageResultType.Success === sType ? oData : null,
+ bCached,
+ sRequestAction,
+ oRequestParameters
+ );
+ }
+ }
+ ;
+
+ switch (sType)
+ {
+ case 'success':
+ sType = Enums.StorageResultType.Success;
+ break;
+ case 'abort':
+ sType = Enums.StorageResultType.Abort;
+ break;
+ default:
+ sType = Enums.StorageResultType.Error;
+ break;
+ }
+
+ if (Enums.StorageResultType.Error === sType)
+ {
+ _.delay(fCall, 300);
+ }
+ else
+ {
+ fCall();
+ }
+ };
+
+ /**
+ * @param {?Function} fResultCallback
+ * @param {Object} oParameters
+ * @param {?number=} iTimeOut = 20000
+ * @param {string=} sGetAdd = ''
+ * @param {Array=} aAbortActions = []
+ * @return {jQuery.jqXHR}
+ */
+ AbstractAjaxRemote.prototype.ajaxRequest = function (fResultCallback, oParameters, iTimeOut, sGetAdd, aAbortActions)
+ {
+ var
+ self = this,
+ bPost = '' === sGetAdd,
+ oHeaders = {},
+ iStart = (new window.Date()).getTime(),
+ oDefAjax = null,
+ sAction = ''
+ ;
+
+ oParameters = oParameters || {};
+ iTimeOut = Utils.isNormal(iTimeOut) ? iTimeOut : 20000;
+ sGetAdd = Utils.isUnd(sGetAdd) ? '' : Utils.pString(sGetAdd);
+ aAbortActions = Utils.isArray(aAbortActions) ? aAbortActions : [];
+
+ sAction = oParameters.Action || '';
+
+ if (sAction && 0 < aAbortActions.length)
+ {
+ _.each(aAbortActions, function (sActionToAbort) {
+ if (self.oRequests[sActionToAbort])
+ {
+ self.oRequests[sActionToAbort].__aborted = true;
+ if (self.oRequests[sActionToAbort].abort)
+ {
+ self.oRequests[sActionToAbort].abort();
+ }
+ self.oRequests[sActionToAbort] = null;
+ }
+ });
+ }
+
+ if (bPost)
+ {
+ oParameters['XToken'] = Settings.appSettingsGet('token');
+ }
+
+ oDefAjax = $.ajax({
+ 'type': bPost ? 'POST' : 'GET',
+ 'url': Links.ajax(sGetAdd),
+ 'async': true,
+ 'dataType': 'json',
+ 'data': bPost ? oParameters : {},
+ 'headers': oHeaders,
+ 'timeout': iTimeOut,
+ 'global': true
+ });
+
+ oDefAjax.always(function (oData, sType) {
+
+ var bCached = false;
+ if (oData && oData['Time'])
+ {
+ bCached = Utils.pInt(oData['Time']) > (new window.Date()).getTime() - iStart;
+ }
+
+ if (sAction && self.oRequests[sAction])
+ {
+ if (self.oRequests[sAction].__aborted)
+ {
+ sType = 'abort';
+ }
+
+ self.oRequests[sAction] = null;
+ }
+
+ self.defaultResponse(fResultCallback, sAction, sType, oData, bCached, oParameters);
+ });
+
+ if (sAction && 0 < aAbortActions.length && -1 < Utils.inArray(sAction, aAbortActions))
+ {
+ if (this.oRequests[sAction])
+ {
+ this.oRequests[sAction].__aborted = true;
+ if (this.oRequests[sAction].abort)
+ {
+ this.oRequests[sAction].abort();
+ }
+ this.oRequests[sAction] = null;
+ }
+
+ this.oRequests[sAction] = oDefAjax;
+ }
+
+ return oDefAjax;
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sAction
+ * @param {Object=} oParameters
+ * @param {?number=} iTimeout
+ * @param {string=} sGetAdd = ''
+ * @param {Array=} aAbortActions = []
+ */
+ AbstractAjaxRemote.prototype.defaultRequest = function (fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions)
+ {
+ oParameters = oParameters || {};
+ oParameters.Action = sAction;
+
+ sGetAdd = Utils.pString(sGetAdd);
+
+ Plugins.runHook('ajax-default-request', [sAction, oParameters, sGetAdd]);
+
+ return this.ajaxRequest(fCallback, oParameters,
+ Utils.isUnd(iTimeout) ? Consts.DEFAULT_AJAX_TIMEOUT : Utils.pInt(iTimeout), sGetAdd, aAbortActions);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ AbstractAjaxRemote.prototype.noop = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'Noop');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sMessage
+ * @param {string} sFileName
+ * @param {number} iLineNo
+ * @param {string} sLocation
+ * @param {string} sHtmlCapa
+ * @param {number} iTime
+ */
+ AbstractAjaxRemote.prototype.jsError = function (fCallback, sMessage, sFileName, iLineNo, sLocation, sHtmlCapa, iTime)
+ {
+ this.defaultRequest(fCallback, 'JsError', {
+ 'Message': sMessage,
+ 'FileName': sFileName,
+ 'LineNo': iLineNo,
+ 'Location': sLocation,
+ 'HtmlCapa': sHtmlCapa,
+ 'TimeOnPage': iTime
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sType
+ * @param {Array=} mData = null
+ * @param {boolean=} bIsError = false
+ */
+ AbstractAjaxRemote.prototype.jsInfo = function (fCallback, sType, mData, bIsError)
+ {
+ this.defaultRequest(fCallback, 'JsInfo', {
+ 'Type': sType,
+ 'Data': mData,
+ 'IsError': (Utils.isUnd(bIsError) ? false : !!bIsError) ? '1' : '0'
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ AbstractAjaxRemote.prototype.getPublicKey = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'GetPublicKey');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sVersion
+ */
+ AbstractAjaxRemote.prototype.jsVersion = function (fCallback, sVersion)
+ {
+ this.defaultRequest(fCallback, 'Version', {
+ 'Version': sVersion
+ });
+ };
+
+ module.exports = AbstractAjaxRemote;
+
+ }());
+
+/***/ },
+/* 56 */
+/*!****************************************!*\
+ !*** ./dev/Screen/AbstractSettings.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractScreen = __webpack_require__(/*! Knoin/AbstractScreen */ 39)
+ ;
+
+ /**
+ * @constructor
+ * @param {Array} aViewModels
+ * @extends AbstractScreen
+ */
+ function AbstractSettingsScreen(aViewModels)
+ {
+ AbstractScreen.call(this, 'settings', aViewModels);
+
+ this.menu = ko.observableArray([]);
+
+ this.oCurrentSubScreen = null;
+ this.oViewModelPlace = null;
+
+ this.setupSettings();
+ }
+
+ _.extend(AbstractSettingsScreen.prototype, AbstractScreen.prototype);
+
+ /**
+ * @param {Function=} fCallback
+ */
+ AbstractSettingsScreen.prototype.setupSettings = function (fCallback)
+ {
+ if (fCallback)
+ {
+ fCallback();
+ }
+ };
+
+ AbstractSettingsScreen.prototype.onRoute = function (sSubName)
+ {
+ var
+ self = this,
+ oSettingsScreen = null,
+ RoutedSettingsViewModel = null,
+ oViewModelPlace = null,
+ oViewModelDom = null
+ ;
+
+ RoutedSettingsViewModel = _.find(Globals.aViewModels['settings'], function (SettingsViewModel) {
+ return SettingsViewModel && SettingsViewModel.__rlSettingsData &&
+ sSubName === SettingsViewModel.__rlSettingsData.Route;
+ });
+
+ if (RoutedSettingsViewModel)
+ {
+ if (_.find(Globals.aViewModels['settings-removed'], function (DisabledSettingsViewModel) {
+ return DisabledSettingsViewModel && DisabledSettingsViewModel === RoutedSettingsViewModel;
+ }))
+ {
+ RoutedSettingsViewModel = null;
+ }
+
+ if (RoutedSettingsViewModel && _.find(Globals.aViewModels['settings-disabled'], function (DisabledSettingsViewModel) {
+ return DisabledSettingsViewModel && DisabledSettingsViewModel === RoutedSettingsViewModel;
+ }))
+ {
+ RoutedSettingsViewModel = null;
+ }
+ }
+
+ if (RoutedSettingsViewModel)
+ {
+ if (RoutedSettingsViewModel.__builded && RoutedSettingsViewModel.__vm)
+ {
+ oSettingsScreen = RoutedSettingsViewModel.__vm;
+ }
+ else
+ {
+ oViewModelPlace = this.oViewModelPlace;
+ if (oViewModelPlace && 1 === oViewModelPlace.length)
+ {
+ oSettingsScreen = new RoutedSettingsViewModel();
+
+ oViewModelDom = $('
').addClass('rl-settings-view-model').hide();
+ oViewModelDom.appendTo(oViewModelPlace);
+
+ oSettingsScreen.viewModelDom = oViewModelDom;
+
+ oSettingsScreen.__rlSettingsData = RoutedSettingsViewModel.__rlSettingsData;
+
+ RoutedSettingsViewModel.__dom = oViewModelDom;
+ RoutedSettingsViewModel.__builded = true;
+ RoutedSettingsViewModel.__vm = oSettingsScreen;
+
+ ko.applyBindingAccessorsToNode(oViewModelDom[0], {
+ 'translatorInit': true,
+ 'template': function () { return {'name': RoutedSettingsViewModel.__rlSettingsData.Template}; }
+ }, oSettingsScreen);
+
+ Utils.delegateRun(oSettingsScreen, 'onBuild', [oViewModelDom]);
+ }
+ else
+ {
+ Utils.log('Cannot find sub settings view model position: SettingsSubScreen');
+ }
+ }
+
+ if (oSettingsScreen)
+ {
+ _.defer(function () {
+ // hide
+ if (self.oCurrentSubScreen)
+ {
+ Utils.delegateRun(self.oCurrentSubScreen, 'onHide');
+ self.oCurrentSubScreen.viewModelDom.hide();
+ }
+ // --
+
+ self.oCurrentSubScreen = oSettingsScreen;
+
+ // show
+ if (self.oCurrentSubScreen)
+ {
+ Utils.delegateRun(self.oCurrentSubScreen, 'onBeforeShow');
+ self.oCurrentSubScreen.viewModelDom.show();
+ Utils.delegateRun(self.oCurrentSubScreen, 'onShow');
+ Utils.delegateRun(self.oCurrentSubScreen, 'onShowWithDelay', [], 200);
+
+ _.each(self.menu(), function (oItem) {
+ oItem.selected(oSettingsScreen && oSettingsScreen.__rlSettingsData && oItem.route === oSettingsScreen.__rlSettingsData.Route);
+ });
+
+ $('#rl-content .b-settings .b-content .content').scrollTop(0);
+ }
+ // --
+
+ Utils.windowResize();
+ });
+ }
+ }
+ else
+ {
+ kn.setHash(Links.settings(), false, true);
+ }
+ };
+
+ AbstractSettingsScreen.prototype.onHide = function ()
+ {
+ if (this.oCurrentSubScreen && this.oCurrentSubScreen.viewModelDom)
+ {
+ Utils.delegateRun(this.oCurrentSubScreen, 'onHide');
+ this.oCurrentSubScreen.viewModelDom.hide();
+ }
+ };
+
+ AbstractSettingsScreen.prototype.onBuild = function ()
+ {
+ _.each(Globals.aViewModels['settings'], function (SettingsViewModel) {
+ if (SettingsViewModel && SettingsViewModel.__rlSettingsData &&
+ !_.find(Globals.aViewModels['settings-removed'], function (RemoveSettingsViewModel) {
+ return RemoveSettingsViewModel && RemoveSettingsViewModel === SettingsViewModel;
+ }))
+ {
+ this.menu.push({
+ 'route': SettingsViewModel.__rlSettingsData.Route,
+ 'label': SettingsViewModel.__rlSettingsData.Label,
+ 'selected': ko.observable(false),
+ 'disabled': !!_.find(Globals.aViewModels['settings-disabled'], function (DisabledSettingsViewModel) {
+ return DisabledSettingsViewModel && DisabledSettingsViewModel === SettingsViewModel;
+ })
+ });
+ }
+ }, this);
+
+ this.oViewModelPlace = $('#rl-content #rl-settings-subscreen');
+ };
+
+ AbstractSettingsScreen.prototype.routes = function ()
+ {
+ var
+ DefaultViewModel = _.find(Globals.aViewModels['settings'], function (SettingsViewModel) {
+ return SettingsViewModel && SettingsViewModel.__rlSettingsData && SettingsViewModel.__rlSettingsData['IsDefault'];
+ }),
+ sDefaultRoute = DefaultViewModel ? DefaultViewModel.__rlSettingsData['Route'] : 'general',
+ oRules = {
+ 'subname': /^(.*)$/,
+ 'normalize_': function (oRequest, oVals) {
+ oVals.subname = Utils.isUnd(oVals.subname) ? sDefaultRoute : Utils.pString(oVals.subname);
+ return [oVals.subname];
+ }
+ }
+ ;
+
+ return [
+ ['{subname}/', oRules],
+ ['{subname}', oRules],
+ ['', oRules]
+ ];
+ };
+
+ module.exports = AbstractSettingsScreen;
+
+ }());
+
+/***/ },
+/* 57 */
+/*!************************************!*\
+ !*** ./dev/Stores/Admin/Domain.js ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2)
+ ;
+
+ /**
+ * @constructor
+ */
+ function DomainAdminStore()
+ {
+ this.domains = ko.observableArray([]);
+ this.domains.loading = ko.observable(false).extend({'throttle': 100});
+ }
+
+ module.exports = new DomainAdminStore();
+
+ }());
+
+
+/***/ },
+/* 58 */
+/*!*************************************!*\
+ !*** ./dev/Stores/Admin/Package.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2)
+ ;
+
+ /**
+ * @constructor
+ */
+ function PackageAdminStore()
+ {
+ this.packages = ko.observableArray([]);
+ this.packages.loading = ko.observable(false).extend({'throttle': 100});
+
+ this.packagesReal = ko.observable(true);
+ this.packagesMainUpdatable = ko.observable(true);
+ }
+
+ module.exports = new PackageAdminStore();
+
+ }());
+
+
+/***/ },
+/* 59 */
+/*!************************************!*\
+ !*** ./dev/Stores/Admin/Plugin.js ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2)
+ ;
+
+ /**
+ * @constructor
+ */
+ function PluginAdminStore()
+ {
+ this.plugins = ko.observableArray([]);
+ this.plugins.loading = ko.observable(false).extend({'throttle': 100});
+ this.plugins.error = ko.observable('');
+ }
+
+ module.exports = new PluginAdminStore();
+
+ }());
+
+
+/***/ },
+/* 60 */,
+/* 61 */,
+/* 62 */,
+/* 63 */,
+/* 64 */
+/*!******************************!*\
+ !*** ./dev/App/Abstract.jsx ***!
+ \******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.AbstractApp = undefined;
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ var _Globals2 = _interopRequireDefault(_Globals);
+
+ var _Enums = __webpack_require__(/*! Common/Enums */ 4);
+
+ var Enums = _interopRequireWildcard(_Enums);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Links = __webpack_require__(/*! Common/Links */ 12);
+
+ var _Links2 = _interopRequireDefault(_Links);
+
+ var _Events = __webpack_require__(/*! Common/Events */ 25);
+
+ var _Events2 = _interopRequireDefault(_Events);
+
+ var _Translator = __webpack_require__(/*! Common/Translator */ 6);
+
+ var _Translator2 = _interopRequireDefault(_Translator);
+
+ var _Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ var _AbstractBoot2 = __webpack_require__(/*! Knoin/AbstractBoot */ 75);
+
+ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var AbstractApp = function (_AbstractBoot) {
+ _inherits(AbstractApp, _AbstractBoot);
+
+ /**
+ * @param {RemoteStorage|AdminRemoteStorage} Remote
+ */
+
+ function AbstractApp(Remote) {
+ _classCallCheck(this, AbstractApp);
+
+ var _this = _possibleConstructorReturn(this, _AbstractBoot.call(this));
+
+ _this.googlePreviewSupportedCache = null;
+ _this.isLocalAutocomplete = true;
+ _this.iframe = null;
+
+
+ _this.iframe = (0, _common.$)('
').appendTo('body');
+
+ _Globals2.default.$win.on('error', function (oEvent) {
+ if (oEvent && oEvent.originalEvent && oEvent.originalEvent.message && -1 === _Utils2.default.inArray(oEvent.originalEvent.message, ['Script error.', 'Uncaught Error: Error calling method on NPObject.'])) {
+ Remote.jsError(_Utils2.default.emptyFunction, oEvent.originalEvent.message, oEvent.originalEvent.filename, oEvent.originalEvent.lineno, _common.window.location && _common.window.location.toString ? _common.window.location.toString() : '', _Globals2.default.$html.attr('class'), _Utils2.default.microtime() - _Globals2.default.startMicrotime);
+ }
+ });
+
+ _Globals2.default.$win.on('resize', function () {
+ _Events2.default.pub('window.resize');
+ });
+
+ _Events2.default.sub('window.resize', _common._.throttle(function () {
+
+ var iH = _Globals2.default.$win.height(),
+ iW = _Globals2.default.$win.height();
+
+ if (_Globals2.default.$win.__sizes[0] !== iH || _Globals2.default.$win.__sizes[1] !== iW) {
+ _Globals2.default.$win.__sizes[0] = iH;
+ _Globals2.default.$win.__sizes[1] = iW;
+
+ _Events2.default.pub('window.resize.real');
+ }
+ }, 50));
+
+ // DEBUG
+ // Events.sub({
+ // 'window.resize': function () {
+ // window.console.log('window.resize');
+ // },
+ // 'window.resize.real': function () {
+ // window.console.log('window.resize.real');
+ // }
+ // });
+
+ _Globals2.default.$doc.on('keydown', function (oEvent) {
+ if (oEvent && oEvent.ctrlKey) {
+ _Globals2.default.$html.addClass('rl-ctrl-key-pressed');
+ }
+ }).on('keyup', function (oEvent) {
+ if (oEvent && !oEvent.ctrlKey) {
+ _Globals2.default.$html.removeClass('rl-ctrl-key-pressed');
+ }
+ });
+
+ _Globals2.default.$doc.on('mousemove keypress click', _common._.debounce(function () {
+ _Events2.default.pub('rl.auto-logout-refresh');
+ }, 5000));
+
+ (0, _common.key)('esc, enter', Enums.KeyState.All, _common._.bind(function () {
+ _Utils2.default.detectDropdownVisibility();
+ }, _this));
+ return _this;
+ }
+
+ AbstractApp.prototype.remote = function remote() {
+ return null;
+ };
+
+ AbstractApp.prototype.data = function data() {
+ return null;
+ };
+
+ AbstractApp.prototype.getApplicationConfiguration = function getApplicationConfiguration(name, default_) {
+ return this.applicationConfiguration[name] || default_;
+ };
+
+ /**
+ * @param {string} link
+ * @return {boolean}
+ */
+
+
+ AbstractApp.prototype.download = function download(link) {
+
+ if (_Globals2.default.sUserAgent && (_Globals2.default.sUserAgent.indexOf('chrome') > -1 || _Globals2.default.sUserAgent.indexOf('chrome') > -1)) {
+ var oLink = _common.window.document.createElement('a');
+ oLink.href = link;
+
+ if (_common.window.document && _common.window.document.createEvent) {
+ var oE = _common.window.document.createEvent.MouseEvents;
+ if (oE && oE.initEvent && oLink.dispatchEvent) {
+ oE.initEvent('click', true, true);
+ oLink.dispatchEvent(oE);
+ return true;
+ }
+ }
+ }
+
+ if (_Globals2.default.bMobileDevice) {
+ _common.window.open(link, '_self');
+ _common.window.focus();
+ } else {
+ this.iframe.attr('src', link);
+ // window.document.location.href = link;
+ }
+
+ return true;
+ };
+
+ /**
+ * @return {boolean}
+ */
+
+
+ AbstractApp.prototype.googlePreviewSupported = function googlePreviewSupported() {
+ if (null === this.googlePreviewSupportedCache) {
+ this.googlePreviewSupportedCache = !!_Settings2.default.settingsGet('AllowGoogleSocial') && !!_Settings2.default.settingsGet('AllowGoogleSocialPreview');
+ }
+
+ return this.googlePreviewSupportedCache;
+ };
+
+ /**
+ * @param {string} title
+ */
+
+
+ AbstractApp.prototype.setWindowTitle = function setWindowTitle(title) {
+ title = _Utils2.default.isNormal(title) && 0 < title.length ? '' + title : '';
+ if (_Settings2.default.settingsGet('Title')) {
+ title += (title ? ' - ' : '') + _Settings2.default.settingsGet('Title');
+ }
+
+ _common.window.document.title = title + ' ...';
+ _common.window.document.title = title;
+ };
+
+ AbstractApp.prototype.redirectToAdminPanel = function redirectToAdminPanel() {
+ _common._.delay(function () {
+ return _common.window.location.href = _Links2.default.rootAdmin();
+ }, 100);
+ };
+
+ AbstractApp.prototype.clearClientSideToken = function clearClientSideToken() {
+ if (_common.window.__rlah_clear) {
+ _common.window.__rlah_clear();
+ }
+ };
+
+ /**
+ * @param {string} token
+ */
+
+
+ AbstractApp.prototype.setClientSideToken = function setClientSideToken(token) {
+ if (_common.window.__rlah_set) {
+ _common.window.__rlah_set(token);
+
+ __webpack_require__(/*! Storage/Settings */ 9).settingsSet('AuthAccountHash', token);
+ __webpack_require__(/*! Common/Links */ 12).populateAuthSuffix();
+ }
+ };
+
+ /**
+ * @param {boolean=} admin = false
+ * @param {boolean=} logout = false
+ * @param {boolean=} close = false
+ */
+
+
+ AbstractApp.prototype.loginAndLogoutReload = function loginAndLogoutReload() {
+ var admin = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
+ var logout = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
+ var close = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2];
+
+
+ var kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ mobile = _Settings2.default.appSettingsGet('mobile'),
+ inIframe = !!_Settings2.default.appSettingsGet('inIframe');
+
+ var customLogoutLink = _Utils2.default.pString(_Settings2.default.appSettingsGet('customLogoutLink'));
+
+ if (logout) {
+ this.clearClientSideToken();
+ }
+
+ if (logout && close && _common.window.close) {
+ _common.window.close();
+ }
+
+ customLogoutLink = customLogoutLink || (admin ? _Links2.default.rootAdmin(mobile) : _Links2.default.rootUser(mobile));
+
+ if (logout && _common.window.location.href !== customLogoutLink) {
+ _common._.delay(function () {
+ if (inIframe && _common.window.parent) {
+ _common.window.parent.location.href = customLogoutLink;
+ } else {
+ _common.window.location.href = customLogoutLink;
+ }
+ }, 100);
+ } else {
+ kn.routeOff();
+ kn.setHash(_Links2.default.root(), true);
+ kn.routeOff();
+
+ _common._.delay(function () {
+ if (inIframe && _common.window.parent) {
+ _common.window.parent.location.reload();
+ } else {
+ _common.window.location.reload();
+ }
+ }, 100);
+ }
+ };
+
+ AbstractApp.prototype.historyBack = function historyBack() {
+ _common.window.history.back();
+ };
+
+ AbstractApp.prototype.bootstart = function bootstart() {
+
+ // Utils.log('Ps' + 'ss, hac' + 'kers! The' + 're\'s not' + 'hing inte' + 'resting :' + ')');
+
+ _Events2.default.pub('rl.bootstart');
+
+ var mobile = _Settings2.default.appSettingsGet('mobile'),
+ ssm = __webpack_require__(/*! ssm */ 84),
+ ko = __webpack_require__(/*! ko */ 2);
+
+ ko.components.register('SaveTrigger', __webpack_require__(/*! Component/SaveTrigger */ 71));
+ ko.components.register('Input', __webpack_require__(/*! Component/Input */ 68));
+ ko.components.register('Select', __webpack_require__(/*! Component/Select */ 73));
+ ko.components.register('Radio', __webpack_require__(/*! Component/Radio */ 70));
+ ko.components.register('TextArea', __webpack_require__(/*! Component/TextArea */ 74));
+
+ ko.components.register('x-script', __webpack_require__(/*! Component/Script */ 72));
+ // ko.components.register('svg-icon', require('Component/SvgIcon'));
+
+ if (_Settings2.default.appSettingsGet('materialDesign') && _Globals2.default.bAnimationSupported) {
+ ko.components.register('Checkbox', __webpack_require__(/*! Component/MaterialDesign/Checkbox */ 69));
+ ko.components.register('CheckboxSimple', __webpack_require__(/*! Component/Checkbox */ 38));
+ } else {
+ // ko.components.register('Checkbox', require('Component/Classic/Checkbox'));
+ // ko.components.register('CheckboxSimple', require('Component/Classic/Checkbox'));
+ ko.components.register('Checkbox', __webpack_require__(/*! Component/Checkbox */ 38));
+ ko.components.register('CheckboxSimple', __webpack_require__(/*! Component/Checkbox */ 38));
+ }
+
+ _Translator2.default.initOnStartOrLangChange(_Translator2.default.initNotificationLanguage, _Translator2.default);
+
+ _common._.delay(_Utils2.default.windowResizeCallback, 1000);
+
+ _Events2.default.sub('ssm.mobile-enter', function () {
+ _Globals2.default.leftPanelDisabled(true);
+ });
+
+ _Events2.default.sub('ssm.mobile-leave', function () {
+ _Globals2.default.leftPanelDisabled(false);
+ });
+
+ if (!mobile) {
+ ssm.addState({
+ id: 'mobile',
+ maxWidth: 767,
+ onEnter: function onEnter() {
+ _Globals2.default.$html.addClass('ssm-state-mobile');
+ _Events2.default.pub('ssm.mobile-enter');
+ },
+ onLeave: function onLeave() {
+ _Globals2.default.$html.removeClass('ssm-state-mobile');
+ _Events2.default.pub('ssm.mobile-leave');
+ }
+ });
+
+ ssm.addState({
+ id: 'tablet',
+ minWidth: 768,
+ maxWidth: 999,
+ onEnter: function onEnter() {
+ _Globals2.default.$html.addClass('ssm-state-tablet');
+ },
+ onLeave: function onLeave() {
+ _Globals2.default.$html.removeClass('ssm-state-tablet');
+ }
+ });
+
+ ssm.addState({
+ id: 'desktop',
+ minWidth: 1000,
+ maxWidth: 1400,
+ onEnter: function onEnter() {
+ _Globals2.default.$html.addClass('ssm-state-desktop');
+ },
+ onLeave: function onLeave() {
+ _Globals2.default.$html.removeClass('ssm-state-desktop');
+ }
+ });
+
+ ssm.addState({
+ id: 'desktop-large',
+ minWidth: 1400,
+ onEnter: function onEnter() {
+ _Globals2.default.$html.addClass('ssm-state-desktop-large');
+ },
+ onLeave: function onLeave() {
+ _Globals2.default.$html.removeClass('ssm-state-desktop-large');
+ }
+ });
+ } else {
+ _Globals2.default.$html.addClass('ssm-state-mobile').addClass('rl-mobile');
+ _Events2.default.pub('ssm.mobile-enter');
+ }
+
+ _Globals2.default.leftPanelDisabled.subscribe(function (bValue) {
+ _Globals2.default.$html.toggleClass('rl-left-panel-disabled', bValue);
+ _Globals2.default.$html.toggleClass('rl-left-panel-enabled', !bValue);
+ });
+
+ _Globals2.default.leftPanelType.subscribe(function (sValue) {
+ _Globals2.default.$html.toggleClass('rl-left-panel-none', 'none' === sValue);
+ _Globals2.default.$html.toggleClass('rl-left-panel-short', 'short' === sValue);
+ });
+
+ _Globals2.default.leftPanelDisabled.valueHasMutated();
+
+ ssm.ready();
+
+ __webpack_require__(/*! Stores/Language */ 40).populate();
+ __webpack_require__(/*! Stores/Theme */ 42).populate();
+ __webpack_require__(/*! Stores/Social */ 34).populate();
+ };
+
+ return AbstractApp;
+ }(_AbstractBoot2.AbstractBoot);
+
+ exports.AbstractApp = AbstractApp;
+ exports.default = AbstractApp;
+
+/***/ },
+/* 65 */,
+/* 66 */
+/*!*****************************!*\
+ !*** ./dev/Common/Mime.jsx ***!
+ \*****************************/
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ /* eslint key-spacing: 0 */
+ /* eslint quote-props: 0 */
+
+ module.exports = {
+ 'eml': 'message/rfc822',
+ 'mime': 'message/rfc822',
+ 'txt': 'text/plain',
+ 'text': 'text/plain',
+ 'def': 'text/plain',
+ 'list': 'text/plain',
+ 'in': 'text/plain',
+ 'ini': 'text/plain',
+ 'log': 'text/plain',
+ 'sql': 'text/plain',
+ 'cfg': 'text/plain',
+ 'conf': 'text/plain',
+ 'asc': 'text/plain',
+ 'rtx': 'text/richtext',
+ 'vcard': 'text/vcard',
+ 'vcf': 'text/vcard',
+ 'htm': 'text/html',
+ 'html': 'text/html',
+ 'csv': 'text/csv',
+ 'ics': 'text/calendar',
+ 'ifb': 'text/calendar',
+ 'xml': 'text/xml',
+ 'json': 'application/json',
+ 'swf': 'application/x-shockwave-flash',
+ 'hlp': 'application/winhlp',
+ 'wgt': 'application/widget',
+ 'chm': 'application/vnd.ms-htmlhelp',
+ 'p10': 'application/pkcs10',
+ 'p7c': 'application/pkcs7-mime',
+ 'p7m': 'application/pkcs7-mime',
+ 'p7s': 'application/pkcs7-signature',
+ 'torrent': 'application/x-bittorrent',
+
+ // scripts
+ 'js': 'application/javascript',
+ 'pl': 'text/perl',
+ 'css': 'text/css',
+ 'asp': 'text/asp',
+ 'php': 'application/x-httpd-php',
+ 'php3': 'application/x-httpd-php',
+ 'php4': 'application/x-httpd-php',
+ 'php5': 'application/x-httpd-php',
+ 'phtml': 'application/x-httpd-php',
+
+ // images
+ 'png': 'image/png',
+ 'jpg': 'image/jpeg',
+ 'jpeg': 'image/jpeg',
+ 'jpe': 'image/jpeg',
+ 'jfif': 'image/jpeg',
+ 'gif': 'image/gif',
+ 'bmp': 'image/bmp',
+ 'cgm': 'image/cgm',
+ 'ief': 'image/ief',
+ 'ico': 'image/x-icon',
+ 'tif': 'image/tiff',
+ 'tiff': 'image/tiff',
+ 'svg': 'image/svg+xml',
+ 'svgz': 'image/svg+xml',
+ 'djv': 'image/vnd.djvu',
+ 'djvu': 'image/vnd.djvu',
+ 'webp': 'image/webp',
+
+ // archives
+ 'zip': 'application/zip',
+ '7z': 'application/x-7z-compressed',
+ 'rar': 'application/x-rar-compressed',
+ 'exe': 'application/x-msdownload',
+ 'dll': 'application/x-msdownload',
+ 'scr': 'application/x-msdownload',
+ 'com': 'application/x-msdownload',
+ 'bat': 'application/x-msdownload',
+ 'msi': 'application/x-msdownload',
+ 'cab': 'application/vnd.ms-cab-compressed',
+ 'gz': 'application/x-gzip',
+ 'tgz': 'application/x-gzip',
+ 'bz': 'application/x-bzip',
+ 'bz2': 'application/x-bzip2',
+ 'deb': 'application/x-debian-package',
+
+ // fonts
+ 'psf': 'application/x-font-linux-psf',
+ 'otf': 'application/x-font-otf',
+ 'pcf': 'application/x-font-pcf',
+ 'snf': 'application/x-font-snf',
+ 'ttf': 'application/x-font-ttf',
+ 'ttc': 'application/x-font-ttf',
+
+ // audio
+ 'mp3': 'audio/mpeg',
+ 'amr': 'audio/amr',
+ 'aac': 'audio/x-aac',
+ 'aif': 'audio/x-aiff',
+ 'aifc': 'audio/x-aiff',
+ 'aiff': 'audio/x-aiff',
+ 'wav': 'audio/x-wav',
+ 'wma': 'audio/x-ms-wma',
+ 'wax': 'audio/x-ms-wax',
+ 'midi': 'audio/midi',
+ 'mp4a': 'audio/mp4',
+ 'ogg': 'audio/ogg',
+ 'weba': 'audio/webm',
+ 'ra': 'audio/x-pn-realaudio',
+ 'ram': 'audio/x-pn-realaudio',
+ 'rmp': 'audio/x-pn-realaudio-plugin',
+ 'm3u': 'audio/x-mpegurl',
+
+ // video
+ 'flv': 'video/x-flv',
+ 'qt': 'video/quicktime',
+ 'mov': 'video/quicktime',
+ 'wmv': 'video/windows-media',
+ 'avi': 'video/x-msvideo',
+ 'mpg': 'video/mpeg',
+ 'mpeg': 'video/mpeg',
+ 'mpe': 'video/mpeg',
+ 'm1v': 'video/mpeg',
+ 'm2v': 'video/mpeg',
+ '3gp': 'video/3gpp',
+ '3g2': 'video/3gpp2',
+ 'h261': 'video/h261',
+ 'h263': 'video/h263',
+ 'h264': 'video/h264',
+ 'jpgv': 'video/jpgv',
+ 'mp4': 'video/mp4',
+ 'mp4v': 'video/mp4',
+ 'mpg4': 'video/mp4',
+ 'ogv': 'video/ogg',
+ 'webm': 'video/webm',
+ 'm4v': 'video/x-m4v',
+ 'asf': 'video/x-ms-asf',
+ 'asx': 'video/x-ms-asf',
+ 'wm': 'video/x-ms-wm',
+ 'wmx': 'video/x-ms-wmx',
+ 'wvx': 'video/x-ms-wvx',
+ 'movie': 'video/x-sgi-movie',
+
+ // adobe
+ 'pdf': 'application/pdf',
+ 'psd': 'image/vnd.adobe.photoshop',
+ 'ai': 'application/postscript',
+ 'eps': 'application/postscript',
+ 'ps': 'application/postscript',
+
+ // ms office
+ 'doc': 'application/msword',
+ 'dot': 'application/msword',
+ 'rtf': 'application/rtf',
+ 'xls': 'application/vnd.ms-excel',
+ 'ppt': 'application/vnd.ms-powerpoint',
+ 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'dotx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+ 'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+
+ // open office
+ 'odt': 'application/vnd.oasis.opendocument.text',
+ 'ods': 'application/vnd.oasis.opendocument.spreadsheet'
+ };
+
+/***/ },
+/* 67 */
+/*!****************************************!*\
+ !*** ./dev/Component/AbstracRadio.jsx ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.AbstracRadio = undefined;
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var AbstracRadio = function (_AbstractComponent) {
+ _inherits(AbstracRadio, _AbstractComponent);
+
+ /**
+ * @param {Object} params
+ */
+
+ function AbstracRadio(params) {
+ _classCallCheck(this, AbstracRadio);
+
+ var _this = _possibleConstructorReturn(this, _AbstractComponent.call(this));
+
+ _this.values = _ko2.default.observableArray([]);
+
+ _this.value = params.value;
+ if (_Utils2.default.isUnd(_this.value) || !_this.value.subscribe) {
+ _this.value = _ko2.default.observable('');
+ }
+
+ _this.inline = _Utils2.default.isUnd(params.inline) ? false : params.inline;
+ _this.readOnly = _Utils2.default.isUnd(params.readOnly) ? false : !!params.readOnly;
+
+ if (params.values) {
+ _this.values(_common._.map(params.values, function (label, value) {
+ return { label: label, value: value };
+ }));
+ }
+
+ _this.click = _common._.bind(_this.click, _this);
+ return _this;
+ }
+
+ AbstracRadio.prototype.click = function click(value) {
+ if (!this.readOnly && value) {
+ this.value(value.value);
+ }
+ };
+
+ return AbstracRadio;
+ }(_Abstract.AbstractComponent);
+
+ exports.AbstracRadio = AbstracRadio;
+ exports.default = AbstracRadio;
+
+/***/ },
+/* 68 */
+/*!*********************************!*\
+ !*** ./dev/Component/Input.jsx ***!
+ \*********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ var _AbstractInput2 = __webpack_require__(/*! Component/AbstractInput */ 37);
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var InputComponent = function (_AbstractInput) {
+ _inherits(InputComponent, _AbstractInput);
+
+ function InputComponent() {
+ _classCallCheck(this, InputComponent);
+
+ return _possibleConstructorReturn(this, _AbstractInput.apply(this, arguments));
+ }
+
+ return InputComponent;
+ }(_AbstractInput2.AbstractInput);
+
+ module.exports = (0, _Abstract.componentExportHelper)(InputComponent, 'InputComponent');
+
+/***/ },
+/* 69 */
+/*!***************************************************!*\
+ !*** ./dev/Component/MaterialDesign/Checkbox.jsx ***!
+ \***************************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ var _AbstracCheckbox2 = __webpack_require__(/*! Component/AbstracCheckbox */ 46);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var CheckboxMaterialDesignComponent = function (_AbstracCheckbox) {
+ _inherits(CheckboxMaterialDesignComponent, _AbstracCheckbox);
+
+ /**
+ * @param {Object} params
+ */
+
+ function CheckboxMaterialDesignComponent(params) {
+ _classCallCheck(this, CheckboxMaterialDesignComponent);
+
+ var _this = _possibleConstructorReturn(this, _AbstracCheckbox.call(this, params));
+
+ _this.animationBox = _ko2.default.observable(false).extend({ falseTimeout: 200 });
+ _this.animationCheckmark = _ko2.default.observable(false).extend({ falseTimeout: 200 });
+
+ _this.animationBoxSetTrue = _common._.bind(_this.animationBoxSetTrue, _this);
+ _this.animationCheckmarkSetTrue = _common._.bind(_this.animationCheckmarkSetTrue, _this);
+
+ _this.disposable.push(_this.value.subscribe(function (value) {
+ _this.triggerAnimation(value);
+ }, _this));
+ return _this;
+ }
+
+ CheckboxMaterialDesignComponent.prototype.animationBoxSetTrue = function animationBoxSetTrue() {
+ this.animationBox(true);
+ };
+
+ CheckboxMaterialDesignComponent.prototype.animationCheckmarkSetTrue = function animationCheckmarkSetTrue() {
+ this.animationCheckmark(true);
+ };
+
+ CheckboxMaterialDesignComponent.prototype.triggerAnimation = function triggerAnimation(box) {
+ if (box) {
+ this.animationBoxSetTrue();
+ _common._.delay(this.animationCheckmarkSetTrue, 200);
+ } else {
+ this.animationCheckmarkSetTrue();
+ _common._.delay(this.animationBoxSetTrue, 200);
+ }
+ };
+
+ return CheckboxMaterialDesignComponent;
+ }(_AbstracCheckbox2.AbstracCheckbox);
+
+ module.exports = (0, _Abstract.componentExportHelper)(CheckboxMaterialDesignComponent, 'CheckboxMaterialDesignComponent');
+
+/***/ },
+/* 70 */
+/*!*********************************!*\
+ !*** ./dev/Component/Radio.jsx ***!
+ \*********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ var _AbstracRadio2 = __webpack_require__(/*! Component/AbstracRadio */ 67);
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var RadioComponent = function (_AbstracRadio) {
+ _inherits(RadioComponent, _AbstracRadio);
+
+ function RadioComponent() {
+ _classCallCheck(this, RadioComponent);
+
+ return _possibleConstructorReturn(this, _AbstracRadio.apply(this, arguments));
+ }
+
+ return RadioComponent;
+ }(_AbstracRadio2.AbstracRadio);
+
+ module.exports = (0, _Abstract.componentExportHelper)(RadioComponent, 'RadioComponent');
+
+/***/ },
+/* 71 */
+/*!***************************************!*\
+ !*** ./dev/Component/SaveTrigger.jsx ***!
+ \***************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Enums = __webpack_require__(/*! Common/Enums */ 4);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var SaveTriggerComponent = function (_AbstractComponent) {
+ _inherits(SaveTriggerComponent, _AbstractComponent);
+
+ /**
+ * @param {Object} params
+ */
+
+ function SaveTriggerComponent(params) {
+ _classCallCheck(this, SaveTriggerComponent);
+
+ var _this = _possibleConstructorReturn(this, _AbstractComponent.call(this));
+
+ _this.element = params.element || null;
+ _this.value = params.value && params.value.subscribe ? params.value : null;
+
+ if (_this.element) {
+ if (_this.value) {
+ _this.element.css('display', 'inline-block');
+
+ if (params.verticalAlign) {
+ _this.element.css('vertical-align', params.verticalAlign);
+ }
+
+ _this.setState(_this.value());
+
+ _this.disposable.push(_this.value.subscribe(_this.setState, _this));
+ } else {
+ _this.element.hide();
+ }
+ }
+ return _this;
+ }
+
+ SaveTriggerComponent.prototype.setState = function setState(value) {
+
+ switch (_Utils2.default.pInt(value)) {
+ case _Enums.SaveSettingsStep.TrueResult:
+ this.element.find('.animated,.error').hide().removeClass('visible').end().find('.success').show().addClass('visible');
+ break;
+ case _Enums.SaveSettingsStep.FalseResult:
+ this.element.find('.animated,.success').hide().removeClass('visible').end().find('.error').show().addClass('visible');
+ break;
+ case _Enums.SaveSettingsStep.Animate:
+ this.element.find('.error,.success').hide().removeClass('visible').end().find('.animated').show().addClass('visible');
+ break;
+ default:
+ case _Enums.SaveSettingsStep.Idle:
+ this.element.find('.animated').hide().end().find('.error,.success').removeClass('visible');
+ break;
+ }
+ };
+
+ return SaveTriggerComponent;
+ }(_Abstract.AbstractComponent);
+
+ module.exports = (0, _Abstract.componentExportHelper)(SaveTriggerComponent, 'SaveTriggerComponent');
+
+/***/ },
+/* 72 */
+/*!**********************************!*\
+ !*** ./dev/Component/Script.jsx ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var ScriptComponent = function (_AbstractComponent) {
+ _inherits(ScriptComponent, _AbstractComponent);
+
+ /**
+ * @param {Object} params
+ */
+
+ function ScriptComponent(params) {
+ _classCallCheck(this, ScriptComponent);
+
+ var _this = _possibleConstructorReturn(this, _AbstractComponent.call(this));
+
+ if (params.component && params.component.templateNodes && params.element && params.element[0] && params.element[0].outerHTML) {
+ var script = params.element[0].outerHTML;
+ script = !script ? '' : script.replace(/
<\/b><\/x-script>/i, '');
+
+ if (script) {
+ params.element.text('');
+ params.element.replaceWith((0, _common.$)(script).text(params.component.templateNodes[0] && params.component.templateNodes[0].nodeValue ? params.component.templateNodes[0].nodeValue : ''));
+ } else {
+ params.element.remove();
+ }
+ }
+ return _this;
+ }
+
+ return ScriptComponent;
+ }(_Abstract.AbstractComponent);
+
+ module.exports = (0, _Abstract.componentExportHelper)(ScriptComponent, 'ScriptComponent');
+
+/***/ },
+/* 73 */
+/*!**********************************!*\
+ !*** ./dev/Component/Select.jsx ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Translator = __webpack_require__(/*! Common/Translator */ 6);
+
+ var _Translator2 = _interopRequireDefault(_Translator);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ var _AbstractInput2 = __webpack_require__(/*! Component/AbstractInput */ 37);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var SelectComponent = function (_AbstractInput) {
+ _inherits(SelectComponent, _AbstractInput);
+
+ /**
+ * @param {Object} params
+ */
+
+ function SelectComponent(params) {
+ _classCallCheck(this, SelectComponent);
+
+ var _this = _possibleConstructorReturn(this, _AbstractInput.call(this, params));
+
+ _this.options = params.options || '';
+
+ _this.optionsText = params.optionsText || null;
+ _this.optionsValue = params.optionsValue || null;
+ _this.optionsCaption = params.optionsCaption || null;
+
+ if (_this.optionsCaption) {
+ _this.optionsCaption = _Translator2.default.i18n(_this.optionsCaption);
+ }
+
+ _this.defautOptionsAfterRender = _Utils2.default.defautOptionsAfterRender;
+ return _this;
+ }
+
+ return SelectComponent;
+ }(_AbstractInput2.AbstractInput);
+
+ module.exports = (0, _Abstract.componentExportHelper)(SelectComponent, 'SelectComponent');
+
+/***/ },
+/* 74 */
+/*!************************************!*\
+ !*** ./dev/Component/TextArea.jsx ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ var _AbstractInput2 = __webpack_require__(/*! Component/AbstractInput */ 37);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var TextAreaComponent = function (_AbstractInput) {
+ _inherits(TextAreaComponent, _AbstractInput);
+
+ /**
+ * @param {Object} params
+ */
+
+ function TextAreaComponent(params) {
+ _classCallCheck(this, TextAreaComponent);
+
+ var _this = _possibleConstructorReturn(this, _AbstractInput.call(this, params));
+
+ _this.rows = params.rows || 5;
+ _this.spellcheck = _Utils2.default.isUnd(params.spellcheck) ? false : !!params.spellcheck;
+ return _this;
+ }
+
+ return TextAreaComponent;
+ }(_AbstractInput2.AbstractInput);
+
+ module.exports = (0, _Abstract.componentExportHelper)(TextAreaComponent, 'TextAreaComponent');
+
+/***/ },
+/* 75 */
+/*!************************************!*\
+ !*** ./dev/Knoin/AbstractBoot.jsx ***!
+ \************************************/
+/***/ function(module, exports) {
+
+ "use strict";
+
+ exports.__esModule = true;
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var AbstractBoot = function () {
+ function AbstractBoot() {
+ _classCallCheck(this, AbstractBoot);
+ }
+
+ AbstractBoot.prototype.bootstart = function bootstart() {
+ // eslint-disable-line no-empty
+ };
+
+ return AbstractBoot;
+ }();
+
+ exports.AbstractBoot = AbstractBoot;
+ exports.default = AbstractBoot;
+
+/***/ },
+/* 76 */
+/*!************************************!*\
+ !*** ./dev/Stores/AbstractApp.jsx ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.AbstractAppStore = undefined;
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ var _Globals2 = _interopRequireDefault(_Globals);
+
+ var _Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var AbstractAppStore = function () {
+ function AbstractAppStore() {
+ _classCallCheck(this, AbstractAppStore);
+
+ this.allowLanguagesOnSettings = _ko2.default.observable(true);
+ this.allowLanguagesOnLogin = _ko2.default.observable(true);
+
+ this.interfaceAnimation = _ko2.default.observable(true);
+
+ this.interfaceAnimation.subscribe(function (bValue) {
+ var bAnim = _Globals2.default.bMobileDevice || !bValue;
+ _Globals2.default.$html.toggleClass('rl-anim', !bAnim).toggleClass('no-rl-anim', bAnim);
+ });
+
+ this.interfaceAnimation.valueHasMutated();
+
+ this.prem = _ko2.default.observable(false);
+ this.community = _ko2.default.observable(true);
+ }
+
+ AbstractAppStore.prototype.populate = function populate() {
+ this.allowLanguagesOnLogin(!!_Settings2.default.settingsGet('AllowLanguagesOnLogin'));
+ this.allowLanguagesOnSettings(!!_Settings2.default.settingsGet('AllowLanguagesOnSettings'));
+
+ this.interfaceAnimation(!!_Settings2.default.settingsGet('InterfaceAnimation'));
+
+ this.prem(!!_Settings2.default.settingsGet('PremType'));
+ this.community(!!_Settings2.default.settingsGet('Community'));
+ };
+
+ return AbstractAppStore;
+ }();
+
+ exports.AbstractAppStore = AbstractAppStore;
+ exports.default = AbstractAppStore;
+
+/***/ },
+/* 77 */
+/*!***************************!*\
+ !*** ./dev/bootstrap.jsx ***!
+ \***************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ exports.default = function (App) {
+
+ var window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Plugins = __webpack_require__(/*! Common/Plugins */ 23),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+ EmailModel = __webpack_require__(/*! Model/Email */ 30);
+
+ Globals.__APP__ = App;
+
+ Globals.$win.keydown(Utils.kill_CtrlA_CtrlS).unload(function () {
+ Globals.bUnload = true;
+ });
+
+ Globals.$html.addClass(Globals.bMobileDevice ? 'mobile' : 'no-mobile').on('click.dropdown.data-api', function () {
+ Utils.detectDropdownVisibility();
+ });
+
+ // export
+ /* eslint dot-notation: 0 */
+ window['rl'] = window['rl'] || {};
+ window['rl']['i18n'] = _.bind(Translator.i18n, Translator);
+
+ window['rl']['addHook'] = _.bind(Plugins.addHook, Plugins);
+ window['rl']['settingsGet'] = _.bind(Plugins.mainSettingsGet, Plugins);
+ window['rl']['createCommand'] = Utils.createCommand;
+
+ window['rl']['addSettingsViewModel'] = _.bind(Plugins.addSettingsViewModel, Plugins);
+
+ window['rl']['pluginRemoteRequest'] = _.bind(Plugins.remoteRequest, Plugins);
+ window['rl']['pluginSettingsGet'] = _.bind(Plugins.settingsGet, Plugins);
+
+ window['rl']['EmailModel'] = EmailModel;
+ window['rl']['Enums'] = Enums;
+
+ window['__APP_BOOT'] = function (fCall) {
+
+ $(_.delay(function () {
+
+ if (!$('#rl-check').is(':visible')) {
+ Globals.$html.addClass('no-css');
+ }
+
+ $('#rl-check').remove();
+
+ if (window['rainloopTEMPLATES'] && window['rainloopTEMPLATES'][0]) {
+ $('#rl-templates').html(window['rainloopTEMPLATES'][0]);
+
+ _.delay(function () {
+
+ App.bootstart();
+
+ Globals.$html.removeClass('no-js rl-booted-trigger').addClass('rl-booted');
+ }, 10);
+ } else {
+ fCall(false);
+ }
+
+ window['__APP_BOOT'] = null;
+ }, 10));
+ };
+ };
+
+/***/ },
+/* 78 */
+/*!************************************!*\
+ !*** external "window.Autolinker" ***!
+ \************************************/
+/***/ function(module, exports) {
+
+ module.exports = window.Autolinker;
+
+/***/ },
+/* 79 */
+/*!***********************************!*\
+ !*** external "window.JSEncrypt" ***!
+ \***********************************/
+/***/ function(module, exports) {
+
+ module.exports = window.JSEncrypt;
+
+/***/ },
+/* 80 */,
+/* 81 */
+/*!********************************!*\
+ !*** external "window.hasher" ***!
+ \********************************/
+/***/ function(module, exports) {
+
+ module.exports = window.hasher;
+
+/***/ },
+/* 82 */
+/*!********************************!*\
+ !*** external "window.moment" ***!
+ \********************************/
+/***/ function(module, exports) {
+
+ module.exports = window.moment;
+
+/***/ },
+/* 83 */
+/*!********************************************!*\
+ !*** external "window.rainloopProgressJs" ***!
+ \********************************************/
+/***/ function(module, exports) {
+
+ module.exports = window.rainloopProgressJs;
+
+/***/ },
+/* 84 */
+/*!*****************************!*\
+ !*** external "window.ssm" ***!
+ \*****************************/
+/***/ function(module, exports) {
+
+ module.exports = window.ssm;
+
+/***/ },
+/* 85 */,
+/* 86 */,
+/* 87 */,
+/* 88 */,
+/* 89 */
+/*!**********************************!*\
+ !*** ./dev/Stores/Admin/Core.js ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2)
+ ;
+
+ /**
+ * @constructor
+ */
+ function CoreAdminStore()
+ {
+ this.coreReal = ko.observable(true);
+ this.coreChannel = ko.observable('stable');
+ this.coreType = ko.observable('stable');
+ this.coreUpdatable = ko.observable(true);
+ this.coreAccess = ko.observable(true);
+ this.coreWarning = ko.observable(false);
+ this.coreChecking = ko.observable(false).extend({'throttle': 100});
+ this.coreUpdating = ko.observable(false).extend({'throttle': 100});
+ this.coreVersion = ko.observable('');
+ this.coreRemoteVersion = ko.observable('');
+ this.coreRemoteRelease = ko.observable('');
+ this.coreVersionCompare = ko.observable(-2);
+ }
+
+ module.exports = new CoreAdminStore();
+
+ }());
+
+
+/***/ },
+/* 90 */,
+/* 91 */,
+/* 92 */,
+/* 93 */
+/*!**********************************!*\
+ !*** ./dev/View/Popup/Domain.js ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ CapaAdminStore = __webpack_require__(/*! Stores/Admin/Capa */ 50),
+
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function DomainPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsDomain');
+
+ this.edit = ko.observable(false);
+ this.saving = ko.observable(false);
+ this.savingError = ko.observable('');
+ this.page = ko.observable('main');
+ this.sieveSettings = ko.observable(false);
+
+ this.testing = ko.observable(false);
+ this.testingDone = ko.observable(false);
+ this.testingImapError = ko.observable(false);
+ this.testingSieveError = ko.observable(false);
+ this.testingSmtpError = ko.observable(false);
+ this.testingImapErrorDesc = ko.observable('');
+ this.testingSieveErrorDesc = ko.observable('');
+ this.testingSmtpErrorDesc = ko.observable('');
+
+ this.testingImapError.subscribe(function (bValue) {
+ if (!bValue)
+ {
+ this.testingImapErrorDesc('');
+ }
+ }, this);
+
+ this.testingSieveError.subscribe(function (bValue) {
+ if (!bValue)
+ {
+ this.testingSieveErrorDesc('');
+ }
+ }, this);
+
+ this.testingSmtpError.subscribe(function (bValue) {
+ if (!bValue)
+ {
+ this.testingSmtpErrorDesc('');
+ }
+ }, this);
+
+ this.imapServerFocus = ko.observable(false);
+ this.sieveServerFocus = ko.observable(false);
+ this.smtpServerFocus = ko.observable(false);
+
+ this.name = ko.observable('');
+ this.name.focused = ko.observable(false);
+
+ this.imapServer = ko.observable('');
+ this.imapPort = ko.observable('' + Consts.IMAP_DEFAULT_PORT);
+ this.imapSecure = ko.observable(Enums.ServerSecure.None);
+ this.imapShortLogin = ko.observable(false);
+ this.useSieve = ko.observable(false);
+ this.sieveAllowRaw = ko.observable(false);
+ this.sieveServer = ko.observable('');
+ this.sievePort = ko.observable('' + Consts.SIEVE_DEFAULT_PORT);
+ this.sieveSecure = ko.observable(Enums.ServerSecure.None);
+ this.smtpServer = ko.observable('');
+ this.smtpPort = ko.observable('' + Consts.SMTP_DEFAULT_PORT);
+ this.smtpSecure = ko.observable(Enums.ServerSecure.None);
+ this.smtpShortLogin = ko.observable(false);
+ this.smtpAuth = ko.observable(true);
+ this.smtpPhpMail = ko.observable(false);
+ this.whiteList = ko.observable('');
+
+ this.enableSmartPorts = ko.observable(false);
+
+ this.allowSieve = ko.computed(function () {
+ return CapaAdminStore.filters() && CapaAdminStore.sieve();
+ }, this);
+
+ this.headerText = ko.computed(function () {
+ var sName = this.name();
+ return this.edit() ? Translator.i18n('POPUPS_DOMAIN/TITLE_EDIT_DOMAIN', {'NAME': sName}) :
+ ('' === sName ? Translator.i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN') :
+ Translator.i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN_WITH_NAME', {'NAME': sName}));
+ }, this);
+
+ this.domainDesc = ko.computed(function () {
+ var sName = this.name();
+ return !this.edit() && sName ? Translator.i18n('POPUPS_DOMAIN/NEW_DOMAIN_DESC', {'NAME': '*@' + sName}) : '';
+ }, this);
+
+ this.domainIsComputed = ko.computed(function () {
+
+ var
+ bPhpMail = this.smtpPhpMail(),
+ bAllowSieve = this.allowSieve(),
+ bUseSieve = this.useSieve()
+ ;
+
+ return '' !== this.name() &&
+ '' !== this.imapServer() &&
+ '' !== this.imapPort() &&
+ (bAllowSieve && bUseSieve ? ('' !== this.sieveServer() && '' !== this.sievePort()) : true) &&
+ (('' !== this.smtpServer() && '' !== this.smtpPort()) || bPhpMail);
+
+ }, this);
+
+ this.canBeTested = ko.computed(function () {
+ return !this.testing() && this.domainIsComputed();
+ }, this);
+
+ this.canBeSaved = ko.computed(function () {
+ return !this.saving() && this.domainIsComputed();
+ }, this);
+
+ this.createOrAddCommand = Utils.createCommand(this, function () {
+ this.saving(true);
+ Remote.createOrUpdateDomain(
+ _.bind(this.onDomainCreateOrSaveResponse, this),
+ !this.edit(),
+ this.name(),
+
+ this.imapServer(),
+ Utils.pInt(this.imapPort()),
+ this.imapSecure(),
+ this.imapShortLogin(),
+
+ this.useSieve(),
+ this.sieveAllowRaw(),
+ this.sieveServer(),
+ Utils.pInt(this.sievePort()),
+ this.sieveSecure(),
+
+ this.smtpServer(),
+ Utils.pInt(this.smtpPort()),
+ this.smtpSecure(),
+ this.smtpShortLogin(),
+ this.smtpAuth(),
+ this.smtpPhpMail(),
+
+ this.whiteList()
+ );
+ }, this.canBeSaved);
+
+ this.testConnectionCommand = Utils.createCommand(this, function () {
+
+ this.page('main');
+
+ this.testingDone(false);
+ this.testingImapError(false);
+ this.testingSieveError(false);
+ this.testingSmtpError(false);
+ this.testing(true);
+
+ Remote.testConnectionForDomain(
+ _.bind(this.onTestConnectionResponse, this),
+ this.name(),
+
+ this.imapServer(),
+ Utils.pInt(this.imapPort()),
+ this.imapSecure(),
+
+ this.useSieve(),
+ this.sieveServer(),
+ Utils.pInt(this.sievePort()),
+ this.sieveSecure(),
+
+ this.smtpServer(),
+ Utils.pInt(this.smtpPort()),
+ this.smtpSecure(),
+ this.smtpAuth(),
+ this.smtpPhpMail()
+ );
+ }, this.canBeTested);
+
+ this.whiteListCommand = Utils.createCommand(this, function () {
+ this.page('white-list');
+ });
+
+ this.backCommand = Utils.createCommand(this, function () {
+ this.page('main');
+ });
+
+ this.sieveCommand = Utils.createCommand(this, function () {
+ this.sieveSettings(!this.sieveSettings());
+ this.clearTesting();
+ });
+
+ this.page.subscribe(function () {
+ this.sieveSettings(false);
+ }, this);
+
+ // smart form improvements
+ this.imapServerFocus.subscribe(function (bValue) {
+ if (bValue && '' !== this.name() && '' === this.imapServer())
+ {
+ this.imapServer(this.name().replace(/[.]?[*][.]?/g, ''));
+ }
+ }, this);
+
+ this.sieveServerFocus.subscribe(function (bValue) {
+ if (bValue && '' !== this.imapServer() && '' === this.sieveServer())
+ {
+ this.sieveServer(this.imapServer());
+ }
+ }, this);
+
+ this.smtpServerFocus.subscribe(function (bValue) {
+ if (bValue && '' !== this.imapServer() && '' === this.smtpServer())
+ {
+ this.smtpServer(this.imapServer().replace(/imap/ig, 'smtp'));
+ }
+ }, this);
+
+ this.imapSecure.subscribe(function (sValue) {
+ if (this.enableSmartPorts())
+ {
+ var iPort = Utils.pInt(this.imapPort());
+ sValue = Utils.pString(sValue);
+ switch (sValue)
+ {
+ case '0':
+ if (993 === iPort)
+ {
+ this.imapPort('143');
+ }
+ break;
+ case '1':
+ if (143 === iPort)
+ {
+ this.imapPort('993');
+ }
+ break;
+ }
+ }
+ }, this);
+
+ this.smtpSecure.subscribe(function (sValue) {
+ if (this.enableSmartPorts())
+ {
+ var iPort = Utils.pInt(this.smtpPort());
+ sValue = Utils.pString(sValue);
+ switch (sValue)
+ {
+ case '0':
+ if (465 === iPort || 587 === iPort)
+ {
+ this.smtpPort('25');
+ }
+ break;
+ case '1':
+ if (25 === iPort || 587 === iPort)
+ {
+ this.smtpPort('465');
+ }
+ break;
+ case '2':
+ if (25 === iPort || 465 === iPort)
+ {
+ this.smtpPort('587');
+ }
+ break;
+ }
+ }
+ }, this);
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/Domain', 'PopupsDomainViewModel'], DomainPopupView);
+ _.extend(DomainPopupView.prototype, AbstractView.prototype);
+
+ DomainPopupView.prototype.onTestConnectionResponse = function (sResult, oData)
+ {
+ this.testing(false);
+ if (Enums.StorageResultType.Success === sResult && oData.Result)
+ {
+ var
+ bImap = false,
+ bSieve = false
+ ;
+
+ this.testingDone(true);
+ this.testingImapError(true !== oData.Result.Imap);
+ this.testingSieveError(true !== oData.Result.Sieve);
+ this.testingSmtpError(true !== oData.Result.Smtp);
+
+ if (this.testingImapError() && oData.Result.Imap)
+ {
+ bImap = true;
+ this.testingImapErrorDesc('');
+ this.testingImapErrorDesc(oData.Result.Imap);
+ }
+
+ if (this.testingSieveError() && oData.Result.Sieve)
+ {
+ bSieve = true;
+ this.testingSieveErrorDesc('');
+ this.testingSieveErrorDesc(oData.Result.Sieve);
+ }
+
+ if (this.testingSmtpError() && oData.Result.Smtp)
+ {
+ this.testingSmtpErrorDesc('');
+ this.testingSmtpErrorDesc(oData.Result.Smtp);
+ }
+
+ if (this.sieveSettings())
+ {
+ if (!bSieve && bImap)
+ {
+ this.sieveSettings(false);
+ }
+ }
+ else
+ {
+ if (bSieve && !bImap)
+ {
+ this.sieveSettings(true);
+ }
+ }
+ }
+ else
+ {
+ this.testingImapError(true);
+ this.testingSieveError(true);
+ this.testingSmtpError(true);
+ this.sieveSettings(false);
+ }
+ };
+
+ DomainPopupView.prototype.onDomainCreateOrSaveResponse = function (sResult, oData)
+ {
+ this.saving(false);
+ if (Enums.StorageResultType.Success === sResult && oData)
+ {
+ if (oData.Result)
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.reloadDomainList();
+ this.closeCommand();
+ }
+ else if (Enums.Notification.DomainAlreadyExists === oData.ErrorCode)
+ {
+ this.savingError(Translator.i18n('ERRORS/DOMAIN_ALREADY_EXISTS'));
+ }
+ }
+ else
+ {
+ this.savingError(Translator.i18n('ERRORS/UNKNOWN_ERROR'));
+ }
+ };
+
+ DomainPopupView.prototype.clearTesting = function ()
+ {
+ this.testing(false);
+ this.testingDone(false);
+ this.testingImapError(false);
+ this.testingSieveError(false);
+ this.testingSmtpError(false);
+ };
+
+ DomainPopupView.prototype.onHide = function ()
+ {
+ this.page('main');
+ this.sieveSettings(false);
+ };
+
+
+ DomainPopupView.prototype.onShow = function (oDomain)
+ {
+ this.saving(false);
+
+ this.page('main');
+ this.sieveSettings(false);
+
+ this.clearTesting();
+
+ this.clearForm();
+ if (oDomain)
+ {
+ this.enableSmartPorts(false);
+
+ this.edit(true);
+
+ this.name(Utils.trim(oDomain.Name));
+ this.imapServer(Utils.trim(oDomain.IncHost));
+ this.imapPort('' + Utils.pInt(oDomain.IncPort));
+ this.imapSecure(Utils.trim(oDomain.IncSecure));
+ this.imapShortLogin(!!oDomain.IncShortLogin);
+ this.useSieve(!!oDomain.UseSieve);
+ this.sieveAllowRaw(!!oDomain.SieveAllowRaw);
+ this.sieveServer(Utils.trim(oDomain.SieveHost));
+ this.sievePort('' + Utils.pInt(oDomain.SievePort));
+ this.sieveSecure(Utils.trim(oDomain.SieveSecure));
+ this.smtpServer(Utils.trim(oDomain.OutHost));
+ this.smtpPort('' + Utils.pInt(oDomain.OutPort));
+ this.smtpSecure(Utils.trim(oDomain.OutSecure));
+ this.smtpShortLogin(!!oDomain.OutShortLogin);
+ this.smtpAuth(!!oDomain.OutAuth);
+ this.smtpPhpMail(!!oDomain.OutUsePhpMail);
+ this.whiteList(Utils.trim(oDomain.WhiteList));
+
+ this.enableSmartPorts(true);
+ }
+ };
+
+ DomainPopupView.prototype.onShowWithDelay = function ()
+ {
+ if ('' === this.name() && !Globals.bMobile)
+ {
+ this.name.focused(true);
+ }
+ };
+
+ DomainPopupView.prototype.clearForm = function ()
+ {
+ this.edit(false);
+
+ this.page('main');
+ this.sieveSettings(false);
+
+ this.enableSmartPorts(false);
+
+ this.savingError('');
+
+ this.name('');
+ this.name.focused(false);
+
+ this.imapServer('');
+ this.imapPort('' + Consts.IMAP_DEFAULT_PORT);
+ this.imapSecure(Enums.ServerSecure.None);
+ this.imapShortLogin(false);
+
+ this.useSieve(false);
+ this.sieveAllowRaw(false);
+ this.sieveServer('');
+ this.sievePort('' + Consts.SIEVE_DEFAULT_PORT);
+ this.sieveSecure(Enums.ServerSecure.None);
+
+ this.smtpServer('');
+ this.smtpPort('' + Consts.SMTP_DEFAULT_PORT);
+ this.smtpSecure(Enums.ServerSecure.None);
+ this.smtpShortLogin(false);
+ this.smtpAuth(true);
+ this.smtpPhpMail(false);
+
+ this.whiteList('');
+ this.enableSmartPorts(true);
+ };
+
+ module.exports = DomainPopupView;
+
+ }());
+
+/***/ },
+/* 94 */,
+/* 95 */,
+/* 96 */,
+/* 97 */,
+/* 98 */,
+/* 99 */,
+/* 100 */,
+/* 101 */,
+/* 102 */,
+/* 103 */,
+/* 104 */,
+/* 105 */,
+/* 106 */,
+/* 107 */,
+/* 108 */,
+/* 109 */,
+/* 110 */,
+/* 111 */,
+/* 112 */,
+/* 113 */
+/*!***********************************!*\
+ !*** ./dev/Screen/Admin/Login.js ***!
+ \***********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ AbstractScreen = __webpack_require__(/*! Knoin/AbstractScreen */ 39)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractScreen
+ */
+ function LoginAdminScreen()
+ {
+ AbstractScreen.call(this, 'login', [
+ __webpack_require__(/*! View/Admin/Login */ 140)
+ ]);
+ }
+
+ _.extend(LoginAdminScreen.prototype, AbstractScreen.prototype);
+
+ LoginAdminScreen.prototype.onShow = function ()
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.setWindowTitle('');
+ };
+
+ module.exports = LoginAdminScreen;
+
+ }());
+
+/***/ },
+/* 114 */
+/*!**************************************!*\
+ !*** ./dev/Screen/Admin/Settings.js ***!
+ \**************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+
+ Plugins = __webpack_require__(/*! Common/Plugins */ 23),
+
+ AbstractSettings = __webpack_require__(/*! Screen/AbstractSettings */ 56)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractSettings
+ */
+ function SettingsAdminScreen()
+ {
+ AbstractSettings.call(this, [
+ __webpack_require__(/*! View/Admin/Settings/Menu */ 141),
+ __webpack_require__(/*! View/Admin/Settings/Pane */ 142)
+ ]);
+ }
+
+ _.extend(SettingsAdminScreen.prototype, AbstractSettings.prototype);
+
+ /**
+ * @param {Function=} fCallback
+ */
+ SettingsAdminScreen.prototype.setupSettings = function (fCallback)
+ {
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/General */ 122),
+ 'AdminSettingsGeneral', 'TABS_LABELS/LABEL_GENERAL_NAME', 'general', true);
+
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Login */ 123),
+ 'AdminSettingsLogin', 'TABS_LABELS/LABEL_LOGIN_NAME', 'login');
+
+ if (true)
+ {
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Branding */ 119),
+ 'AdminSettingsBranding', 'TABS_LABELS/LABEL_BRANDING_NAME', 'branding');
+ }
+ else
+ {
+ kn.addSettingsViewModel(require('Settings/Admin/Prem/Branding'),
+ 'AdminSettingsBranding', 'TABS_LABELS/LABEL_BRANDING_NAME', 'branding');
+ }
+
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Contacts */ 120),
+ 'AdminSettingsContacts', 'TABS_LABELS/LABEL_CONTACTS_NAME', 'contacts');
+
+ //kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Domains */ 121),
+ // 'AdminSettingsDomains', 'TABS_LABELS/LABEL_DOMAINS_NAME', 'domains');
+
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Security */ 126),
+ 'AdminSettingsSecurity', 'TABS_LABELS/LABEL_SECURITY_NAME', 'security');
+
+ //kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Social */ 127),
+ // 'AdminSettingsSocial', 'TABS_LABELS/LABEL_INTEGRATION_NAME', 'integrations');
+
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Plugins */ 125),
+ 'AdminSettingsPlugins', 'TABS_LABELS/LABEL_PLUGINS_NAME', 'plugins');
+
+ //kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/Packages */ 124),
+ // 'AdminSettingsPackages', 'TABS_LABELS/LABEL_PACKAGES_NAME', 'packages');
+
+ if (false)
+ {
+ kn.addSettingsViewModel(require('Settings/Admin/Prem/Licensing'),
+ 'AdminSettingsLicensing', 'TABS_LABELS/LABEL_LICENSING_NAME', 'licensing');
+ }
+
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/Admin/About */ 118),
+ 'AdminSettingsAbout', 'TABS_LABELS/LABEL_ABOUT_NAME', 'about');
+
+ Plugins.runSettingsViewModelHooks(true);
+
+ if (fCallback)
+ {
+ fCallback();
+ }
+ };
+
+ SettingsAdminScreen.prototype.onShow = function ()
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.setWindowTitle('');
+ };
+
+ module.exports = SettingsAdminScreen;
+
+ }());
+
+/***/ },
+/* 115 */,
+/* 116 */,
+/* 117 */,
+/* 118 */
+/*!*************************************!*\
+ !*** ./dev/Settings/Admin/About.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ CoreStore = __webpack_require__(/*! Stores/Admin/Core */ 89),
+ AppStore = __webpack_require__(/*! Stores/Admin/App */ 35)
+ ;
+
+ /**
+ * @constructor
+ */
+ function AboutAdminSettings()
+ {
+ this.version = ko.observable(Settings.appSettingsGet('version'));
+ this.access = ko.observable(!!Settings.settingsGet('CoreAccess'));
+ this.errorDesc = ko.observable('');
+
+ this.coreReal = CoreStore.coreReal;
+ this.coreChannel = CoreStore.coreChannel;
+ this.coreType = CoreStore.coreType;
+ this.coreUpdatable = CoreStore.coreUpdatable;
+ this.coreAccess = CoreStore.coreAccess;
+ this.coreChecking = CoreStore.coreChecking;
+ this.coreUpdating = CoreStore.coreUpdating;
+ this.coreWarning = CoreStore.coreWarning;
+ this.coreVersion = CoreStore.coreVersion;
+ this.coreRemoteVersion = CoreStore.coreRemoteVersion;
+ this.coreRemoteRelease = CoreStore.coreRemoteRelease;
+ this.coreVersionCompare = CoreStore.coreVersionCompare;
+
+ this.community = (true) || AppStore.community();
+
+ this.coreRemoteVersionHtmlDesc = ko.computed(function () {
+ Translator.trigger();
+ return Translator.i18n('TAB_ABOUT/HTML_NEW_VERSION', {'VERSION': this.coreRemoteVersion()});
+ }, this);
+
+ this.statusType = ko.computed(function () {
+
+ var
+ sType = '',
+ iVersionCompare = this.coreVersionCompare(),
+ bChecking = this.coreChecking(),
+ bUpdating = this.coreUpdating(),
+ bReal = this.coreReal()
+ ;
+
+ if (bChecking)
+ {
+ sType = 'checking';
+ }
+ else if (bUpdating)
+ {
+ sType = 'updating';
+ }
+ else if (bReal && 0 === iVersionCompare)
+ {
+ sType = 'up-to-date';
+ }
+ else if (bReal && -1 === iVersionCompare)
+ {
+ sType = 'available';
+ }
+ else if (!bReal)
+ {
+ sType = 'error';
+ this.errorDesc('Cannot access the repository at the moment.');
+ }
+
+ return sType;
+
+ }, this);
+ }
+
+ AboutAdminSettings.prototype.onBuild = function ()
+ {
+ if (this.access() && !this.community)
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.reloadCoreData();
+ }
+ };
+
+ AboutAdminSettings.prototype.updateCoreData = function ()
+ {
+ if (!this.coreUpdating() && !this.community)
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.updateCoreData();
+ }
+ };
+
+ module.exports = AboutAdminSettings;
+
+ }());
+
+/***/ },
+/* 119 */
+/*!****************************************!*\
+ !*** ./dev/Settings/Admin/Branding.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6)
+ ;
+
+ /**
+ * @constructor
+ */
+ function BrandingAdminSettings()
+ {
+ var
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ AppStore = __webpack_require__(/*! Stores/Admin/App */ 35)
+ ;
+
+ this.capa = AppStore.prem;
+
+ this.title = ko.observable(Settings.settingsGet('Title'));
+ this.title.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.loadingDesc = ko.observable(Settings.settingsGet('LoadingDescription'));
+ this.loadingDesc.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.faviconUrl = ko.observable(Settings.settingsGet('FaviconUrl'));
+ this.faviconUrl.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.loginLogo = ko.observable(Settings.settingsGet('LoginLogo') || '');
+ this.loginLogo.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.loginBackground = ko.observable(Settings.settingsGet('LoginBackground') || '');
+ this.loginBackground.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.userLogo = ko.observable(Settings.settingsGet('UserLogo') || '');
+ this.userLogo.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.userLogoMessage = ko.observable(Settings.settingsGet('UserLogoMessage') || '');
+ this.userLogoMessage.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.userIframeMessage = ko.observable(Settings.settingsGet('UserIframeMessage') || '');
+ this.userIframeMessage.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.userLogoTitle = ko.observable(Settings.settingsGet('UserLogoTitle') || '');
+ this.userLogoTitle.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.loginDescription = ko.observable(Settings.settingsGet('LoginDescription'));
+ this.loginDescription.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.loginCss = ko.observable(Settings.settingsGet('LoginCss'));
+ this.loginCss.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.userCss = ko.observable(Settings.settingsGet('UserCss'));
+ this.userCss.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.welcomePageUrl = ko.observable(Settings.settingsGet('WelcomePageUrl'));
+ this.welcomePageUrl.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.welcomePageDisplay = ko.observable(Settings.settingsGet('WelcomePageDisplay'));
+ this.welcomePageDisplay.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.welcomePageDisplay.options = ko.computed(function () {
+ Translator.trigger();
+ return [
+ {'optValue': 'none', 'optText': Translator.i18n('TAB_BRANDING/OPTION_WELCOME_PAGE_DISPLAY_NONE')},
+ {'optValue': 'once', 'optText': Translator.i18n('TAB_BRANDING/OPTION_WELCOME_PAGE_DISPLAY_ONCE')},
+ {'optValue': 'always', 'optText': Translator.i18n('TAB_BRANDING/OPTION_WELCOME_PAGE_DISPLAY_ALWAYS')}
+ ];
+ });
+
+ this.loginPowered = ko.observable(!!Settings.settingsGet('LoginPowered'));
+
+ this.community = (true) || AppStore.community();
+ }
+
+ BrandingAdminSettings.prototype.onBuild = function ()
+ {
+ var
+ self = this,
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ _.delay(function () {
+
+ var
+ f1 = Utils.settingsSaveHelperSimpleFunction(self.title.trigger, self),
+ f2 = Utils.settingsSaveHelperSimpleFunction(self.loadingDesc.trigger, self),
+ f3 = Utils.settingsSaveHelperSimpleFunction(self.faviconUrl.trigger, self)
+ ;
+
+ self.title.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f1, {
+ 'Title': Utils.trim(sValue)
+ });
+ });
+
+ self.loadingDesc.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f2, {
+ 'LoadingDescription': Utils.trim(sValue)
+ });
+ });
+
+ self.faviconUrl.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f3, {
+ 'FaviconUrl': Utils.trim(sValue)
+ });
+ });
+
+ }, 50);
+ };
+
+ module.exports = BrandingAdminSettings;
+
+ }());
+
+/***/ },
+/* 120 */
+/*!****************************************!*\
+ !*** ./dev/Settings/Admin/Contacts.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function ContactsAdminSettings()
+ {
+ var
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ this.defautOptionsAfterRender = Utils.defautOptionsAfterRender;
+ this.enableContacts = ko.observable(!!Settings.settingsGet('ContactsEnable'));
+ this.contactsSharing = ko.observable(!!Settings.settingsGet('ContactsSharing'));
+ this.contactsSync = ko.observable(!!Settings.settingsGet('ContactsSync'));
+
+ var
+ aTypes = ['sqlite', 'mysql', 'pgsql'],
+ aSupportedTypes = [],
+ getTypeName = function(sName) {
+ switch (sName)
+ {
+ case 'sqlite':
+ sName = 'SQLite';
+ break;
+ case 'mysql':
+ sName = 'MySQL';
+ break;
+ case 'pgsql':
+ sName = 'PostgreSQL';
+ break;
+ }
+
+ return sName;
+ }
+ ;
+
+ if (!!Settings.settingsGet('SQLiteIsSupported'))
+ {
+ aSupportedTypes.push('sqlite');
+ }
+ if (!!Settings.settingsGet('MySqlIsSupported'))
+ {
+ aSupportedTypes.push('mysql');
+ }
+ if (!!Settings.settingsGet('PostgreSqlIsSupported'))
+ {
+ aSupportedTypes.push('pgsql');
+ }
+
+ this.contactsSupported = 0 < aSupportedTypes.length;
+
+ this.contactsTypes = ko.observableArray([]);
+ this.contactsTypesOptions = this.contactsTypes.map(function (sValue) {
+ var bDisabled = -1 === Utils.inArray(sValue, aSupportedTypes);
+ return {
+ 'id': sValue,
+ 'name': getTypeName(sValue) + (bDisabled ? ' (' + Translator.i18n('HINTS/NOT_SUPPORTED') + ')' : ''),
+ 'disabled': bDisabled
+ };
+ });
+
+ this.contactsTypes(aTypes);
+ this.contactsType = ko.observable('');
+
+ this.mainContactsType = ko.computed({
+ 'owner': this,
+ 'read': this.contactsType,
+ 'write': function (sValue) {
+ if (sValue !== this.contactsType())
+ {
+ if (-1 < Utils.inArray(sValue, aSupportedTypes))
+ {
+ this.contactsType(sValue);
+ }
+ else if (0 < aSupportedTypes.length)
+ {
+ this.contactsType('');
+ }
+ }
+ else
+ {
+ this.contactsType.valueHasMutated();
+ }
+ }
+ }).extend({'notify': 'always'});
+
+ this.contactsType.subscribe(function () {
+ this.testContactsSuccess(false);
+ this.testContactsError(false);
+ this.testContactsErrorMessage('');
+ }, this);
+
+ this.pdoDsn = ko.observable(Settings.settingsGet('ContactsPdoDsn'));
+ this.pdoUser = ko.observable(Settings.settingsGet('ContactsPdoUser'));
+ this.pdoPassword = ko.observable(Settings.settingsGet('ContactsPdoPassword'));
+
+ this.pdoDsnTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.pdoUserTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.pdoPasswordTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.contactsTypeTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.testing = ko.observable(false);
+ this.testContactsSuccess = ko.observable(false);
+ this.testContactsError = ko.observable(false);
+ this.testContactsErrorMessage = ko.observable('');
+
+ this.testContactsCommand = Utils.createCommand(this, function () {
+
+ this.testContactsSuccess(false);
+ this.testContactsError(false);
+ this.testContactsErrorMessage('');
+ this.testing(true);
+
+ Remote.testContacts(this.onTestContactsResponse, {
+ 'ContactsPdoType': this.contactsType(),
+ 'ContactsPdoDsn': this.pdoDsn(),
+ 'ContactsPdoUser': this.pdoUser(),
+ 'ContactsPdoPassword': this.pdoPassword()
+ });
+
+ }, function () {
+ return '' !== this.pdoDsn() && '' !== this.pdoUser();
+ });
+
+ this.contactsType(Settings.settingsGet('ContactsPdoType'));
+
+ this.onTestContactsResponse = _.bind(this.onTestContactsResponse, this);
+ }
+
+ ContactsAdminSettings.prototype.onTestContactsResponse = function (sResult, oData)
+ {
+ this.testContactsSuccess(false);
+ this.testContactsError(false);
+ this.testContactsErrorMessage('');
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result.Result)
+ {
+ this.testContactsSuccess(true);
+ }
+ else
+ {
+ this.testContactsError(true);
+ if (oData && oData.Result)
+ {
+ this.testContactsErrorMessage(oData.Result.Message || '');
+ }
+ else
+ {
+ this.testContactsErrorMessage('');
+ }
+ }
+
+ this.testing(false);
+ };
+
+ ContactsAdminSettings.prototype.onShow = function ()
+ {
+ this.testContactsSuccess(false);
+ this.testContactsError(false);
+ this.testContactsErrorMessage('');
+ };
+
+ ContactsAdminSettings.prototype.onBuild = function ()
+ {
+ var
+ self = this,
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ _.delay(function () {
+
+ var
+ f1 = Utils.settingsSaveHelperSimpleFunction(self.pdoDsnTrigger, self),
+ f3 = Utils.settingsSaveHelperSimpleFunction(self.pdoUserTrigger, self),
+ f4 = Utils.settingsSaveHelperSimpleFunction(self.pdoPasswordTrigger, self),
+ f5 = Utils.settingsSaveHelperSimpleFunction(self.contactsTypeTrigger, self)
+ ;
+
+ self.enableContacts.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'ContactsEnable': bValue ? '1' : '0'
+ });
+ });
+
+ self.contactsSharing.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'ContactsSharing': bValue ? '1' : '0'
+ });
+ });
+
+ self.contactsSync.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'ContactsSync': bValue ? '1' : '0'
+ });
+ });
+
+ self.contactsType.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f5, {
+ 'ContactsPdoType': sValue
+ });
+ });
+
+ self.pdoDsn.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f1, {
+ 'ContactsPdoDsn': Utils.trim(sValue)
+ });
+ });
+
+ self.pdoUser.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f3, {
+ 'ContactsPdoUser': Utils.trim(sValue)
+ });
+ });
+
+ self.pdoPassword.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f4, {
+ 'ContactsPdoPassword': Utils.trim(sValue)
+ });
+ });
+
+ self.contactsType(Settings.settingsGet('ContactsPdoType'));
+
+ }, 50);
+ };
+
+ module.exports = ContactsAdminSettings;
+
+ }());
+
+/***/ },
+/* 121 */
+/*!***************************************!*\
+ !*** ./dev/Settings/Admin/Domains.js ***!
+ \***************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+
+ DomainStore = __webpack_require__(/*! Stores/Admin/Domain */ 57),
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ /**
+ * @constructor
+ */
+ function DomainsAdminSettings()
+ {
+ this.domains = DomainStore.domains;
+
+ this.visibility = ko.computed(function () {
+ return this.domains.loading() ? 'visible' : 'hidden';
+ }, this);
+
+ this.domainForDeletion = ko.observable(null).deleteAccessHelper();
+ }
+
+ DomainsAdminSettings.prototype.createDomain = function ()
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Domain */ 93));
+ };
+
+ DomainsAdminSettings.prototype.deleteDomain = function (oDomain)
+ {
+ this.domains.remove(oDomain);
+ Remote.domainDelete(_.bind(this.onDomainListChangeRequest, this), oDomain.name);
+ };
+
+ DomainsAdminSettings.prototype.disableDomain = function (oDomain)
+ {
+ oDomain.disabled(!oDomain.disabled());
+ Remote.domainDisable(_.bind(this.onDomainListChangeRequest, this), oDomain.name, oDomain.disabled());
+ };
+
+ DomainsAdminSettings.prototype.onBuild = function (oDom)
+ {
+ var self = this;
+ oDom
+ .on('click', '.b-admin-domains-list-table .e-item .e-action', function () {
+ var oDomainItem = ko.dataFor(this);
+ if (oDomainItem)
+ {
+ Remote.domain(_.bind(self.onDomainLoadRequest, self), oDomainItem.name);
+ }
+ })
+ ;
+
+ __webpack_require__(/*! App/Admin */ 22).default.reloadDomainList();
+ };
+
+ DomainsAdminSettings.prototype.onDomainLoadRequest = function (sResult, oData)
+ {
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Domain */ 93), [oData.Result]);
+ }
+ };
+
+ DomainsAdminSettings.prototype.onDomainListChangeRequest = function ()
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.reloadDomainList();
+ };
+
+ module.exports = DomainsAdminSettings;
+
+ }());
+
+/***/ },
+/* 122 */
+/*!***************************************!*\
+ !*** ./dev/Settings/Admin/General.js ***!
+ \***************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ ThemeStore = __webpack_require__(/*! Stores/Theme */ 42),
+ LanguageStore = __webpack_require__(/*! Stores/Language */ 40),
+ AppAdminStore = __webpack_require__(/*! Stores/Admin/App */ 35),
+ CapaAdminStore = __webpack_require__(/*! Stores/Admin/Capa */ 50),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function GeneralAdminSettings()
+ {
+ this.language = LanguageStore.language;
+ this.languages = LanguageStore.languages;
+ this.languageAdmin = LanguageStore.languageAdmin;
+ this.languagesAdmin = LanguageStore.languagesAdmin;
+
+ this.theme = ThemeStore.theme;
+ this.themes = ThemeStore.themes;
+
+ this.capaThemes = CapaAdminStore.themes;
+ this.capaUserBackground = CapaAdminStore.userBackground;
+ this.capaGravatar = CapaAdminStore.gravatar;
+ this.capaAdditionalAccounts = CapaAdminStore.additionalAccounts;
+ this.capaIdentities = CapaAdminStore.identities;
+ this.capaAttachmentThumbnails = CapaAdminStore.attachmentThumbnails;
+ this.capaTemplates = CapaAdminStore.templates;
+
+ this.allowLanguagesOnSettings = AppAdminStore.allowLanguagesOnSettings;
+ this.weakPassword = AppAdminStore.weakPassword;
+
+ this.mainAttachmentLimit = ko.observable(Utils.pInt(Settings.settingsGet('AttachmentLimit')) / (1024 * 1024)).extend({'posInterer': 25});
+ this.uploadData = Settings.settingsGet('PhpUploadSizes');
+ this.uploadDataDesc = this.uploadData && (this.uploadData['upload_max_filesize'] || this.uploadData['post_max_size']) ? [
+ this.uploadData['upload_max_filesize'] ? 'upload_max_filesize = ' + this.uploadData['upload_max_filesize'] + '; ' : '',
+ this.uploadData['post_max_size'] ? 'post_max_size = ' + this.uploadData['post_max_size'] : ''
+ ].join('') : '';
+
+ this.themesOptions = ko.computed(function () {
+ return _.map(this.themes(), function (sTheme) {
+ return {
+ 'optValue': sTheme,
+ 'optText': Utils.convertThemeName(sTheme)
+ };
+ });
+ }, this);
+
+ this.languageFullName = ko.computed(function () {
+ return Utils.convertLangName(this.language());
+ }, this);
+
+ this.languageAdminFullName = ko.computed(function () {
+ return Utils.convertLangName(this.languageAdmin());
+ }, this);
+
+ this.attachmentLimitTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.languageTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.languageAdminTrigger = ko.observable(Enums.SaveSettingsStep.Idle).extend({'throttle': 100});
+ this.themeTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+ }
+
+ GeneralAdminSettings.prototype.onBuild = function ()
+ {
+ var
+ self = this,
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ _.delay(function () {
+
+ var
+ f1 = Utils.settingsSaveHelperSimpleFunction(self.attachmentLimitTrigger, self),
+ f2 = Utils.settingsSaveHelperSimpleFunction(self.languageTrigger, self),
+ f3 = Utils.settingsSaveHelperSimpleFunction(self.themeTrigger, self),
+ fReloadLanguageHelper = function (iSaveSettingsStep) {
+ return function() {
+ self.languageAdminTrigger(iSaveSettingsStep);
+ _.delay(function () {
+ self.languageAdminTrigger(Enums.SaveSettingsStep.Idle);
+ }, 1000);
+ };
+ }
+ ;
+
+ self.mainAttachmentLimit.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f1, {
+ 'AttachmentLimit': Utils.pInt(sValue)
+ });
+ });
+
+ self.language.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f2, {
+ 'Language': Utils.trim(sValue)
+ });
+ });
+
+ self.languageAdmin.subscribe(function (sValue) {
+
+ self.languageAdminTrigger(Enums.SaveSettingsStep.Animate);
+
+ Translator.reload(true, sValue,
+ fReloadLanguageHelper(Enums.SaveSettingsStep.TrueResult),
+ fReloadLanguageHelper(Enums.SaveSettingsStep.FalseResult));
+
+ Remote.saveAdminConfig(null, {
+ 'LanguageAdmin': Utils.trim(sValue)
+ });
+ });
+
+ self.theme.subscribe(function (sValue) {
+
+ Utils.changeTheme(sValue, self.themeTrigger);
+
+ Remote.saveAdminConfig(f3, {
+ 'Theme': Utils.trim(sValue)
+ });
+ });
+
+ self.capaAdditionalAccounts.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'CapaAdditionalAccounts': bValue ? '1' : '0'
+ });
+ });
+
+ self.capaIdentities.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'CapaIdentities': bValue ? '1' : '0'
+ });
+ });
+
+ self.capaTemplates.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'CapaTemplates': bValue ? '1' : '0'
+ });
+ });
+
+ self.capaGravatar.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'CapaGravatar': bValue ? '1' : '0'
+ });
+ });
+
+ self.capaAttachmentThumbnails.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'CapaAttachmentThumbnails': bValue ? '1' : '0'
+ });
+ });
+
+ self.capaThemes.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'CapaThemes': bValue ? '1' : '0'
+ });
+ });
+
+ self.capaUserBackground.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'CapaUserBackground': bValue ? '1' : '0'
+ });
+ });
+
+ self.allowLanguagesOnSettings.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'AllowLanguagesOnSettings': bValue ? '1' : '0'
+ });
+ });
+
+ }, 50);
+ };
+
+ GeneralAdminSettings.prototype.selectLanguage = function ()
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Languages */ 44), [
+ this.language, this.languages(), LanguageStore.userLanguage()
+ ]);
+ };
+
+ GeneralAdminSettings.prototype.selectLanguageAdmin = function ()
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Languages */ 44), [
+ this.languageAdmin, this.languagesAdmin(), LanguageStore.userLanguageAdmin()
+ ]);
+ };
+
+ /**
+ * @return {string}
+ */
+ GeneralAdminSettings.prototype.phpInfoLink = function ()
+ {
+ return Links.phpInfo();
+ };
+
+ module.exports = GeneralAdminSettings;
+
+ }());
+
+/***/ },
+/* 123 */
+/*!*************************************!*\
+ !*** ./dev/Settings/Admin/Login.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ AppAdminStore = __webpack_require__(/*! Stores/Admin/App */ 35),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function LoginAdminSettings()
+ {
+ this.determineUserLanguage = AppAdminStore.determineUserLanguage;
+ this.determineUserDomain = AppAdminStore.determineUserDomain;
+
+ this.defaultDomain = ko.observable(Settings.settingsGet('LoginDefaultDomain'));
+
+ this.allowLanguagesOnLogin = AppAdminStore.allowLanguagesOnLogin;
+ this.defaultDomainTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.dummy = ko.observable(false);
+ }
+
+ LoginAdminSettings.prototype.onBuild = function ()
+ {
+ var
+ self = this,
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ _.delay(function () {
+
+ var f1 = Utils.settingsSaveHelperSimpleFunction(self.defaultDomainTrigger, self);
+
+ self.determineUserLanguage.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'DetermineUserLanguage': bValue ? '1' : '0'
+ });
+ });
+
+ self.determineUserDomain.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'DetermineUserDomain': bValue ? '1' : '0'
+ });
+ });
+
+ self.allowLanguagesOnLogin.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'AllowLanguagesOnLogin': bValue ? '1' : '0'
+ });
+ });
+
+ self.defaultDomain.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f1, {
+ 'LoginDefaultDomain': Utils.trim(sValue)
+ });
+ });
+
+ }, 50);
+ };
+
+ module.exports = LoginAdminSettings;
+
+ }());
+
+/***/ },
+/* 124 */
+/*!****************************************!*\
+ !*** ./dev/Settings/Admin/Packages.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ PackageStore = __webpack_require__(/*! Stores/Admin/Package */ 58),
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ /**
+ * @constructor
+ */
+ function PackagesAdminSettings()
+ {
+ this.packagesError = ko.observable('');
+
+ this.packages = PackageStore.packages;
+ this.packagesReal = PackageStore.packagesReal;
+ this.packagesMainUpdatable = PackageStore.packagesMainUpdatable;
+
+ this.packagesCurrent = this.packages.filter(function (oItem) {
+ return oItem && '' !== oItem['installed'] && !oItem['compare'];
+ });
+
+ this.packagesAvailableForUpdate = this.packages.filter(function (oItem) {
+ return oItem && '' !== oItem['installed'] && !!oItem['compare'];
+ });
+
+ this.packagesAvailableForInstallation = this.packages.filter(function (oItem) {
+ return oItem && '' === oItem['installed'];
+ });
+
+ this.visibility = ko.computed(function () {
+ return PackageStore.packages.loading() ? 'visible' : 'hidden';
+ }, this);
+ }
+
+ PackagesAdminSettings.prototype.onShow = function ()
+ {
+ this.packagesError('');
+ };
+
+ PackagesAdminSettings.prototype.onBuild = function ()
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.reloadPackagesList();
+ };
+
+ PackagesAdminSettings.prototype.requestHelper = function (oPackage, bInstall)
+ {
+ var self = this;
+ return function (sResult, oData) {
+
+ if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result)
+ {
+ if (oData && oData.ErrorCode)
+ {
+ self.packagesError(Translator.getNotification(oData.ErrorCode));
+ }
+ else
+ {
+ self.packagesError(Translator.getNotification(
+ bInstall ? Enums.Notification.CantInstallPackage : Enums.Notification.CantDeletePackage));
+ }
+ }
+
+ _.each(self.packages(), function (oItem) {
+ if (oItem && oPackage && oItem['loading']() && oPackage['file'] === oItem['file'])
+ {
+ oPackage['loading'](false);
+ oItem['loading'](false);
+ }
+ });
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result['Reload'])
+ {
+ window.location.reload();
+ }
+ else
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.reloadPackagesList();
+ }
+ };
+ };
+
+ PackagesAdminSettings.prototype.deletePackage = function (oPackage)
+ {
+ if (oPackage)
+ {
+ oPackage['loading'](true);
+ Remote.packageDelete(this.requestHelper(oPackage, false), oPackage);
+ }
+ };
+
+ PackagesAdminSettings.prototype.installPackage = function (oPackage)
+ {
+ if (oPackage)
+ {
+ oPackage['loading'](true);
+ Remote.packageInstall(this.requestHelper(oPackage, true), oPackage);
+ }
+ };
+
+ module.exports = PackagesAdminSettings;
+
+ }());
+
+/***/ },
+/* 125 */
+/*!***************************************!*\
+ !*** ./dev/Settings/Admin/Plugins.js ***!
+ \***************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+
+ AppStore = __webpack_require__(/*! Stores/Admin/App */ 35),
+ PluginStore = __webpack_require__(/*! Stores/Admin/Plugin */ 59),
+
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ /**
+ * @constructor
+ */
+ function PluginsAdminSettings()
+ {
+ this.enabledPlugins = ko.observable(!!Settings.settingsGet('EnabledPlugins'));
+
+ this.plugins = PluginStore.plugins;
+ this.pluginsError = PluginStore.plugins.error;
+
+ this.community = (true) || AppStore.community();
+
+ this.visibility = ko.computed(function () {
+ return PluginStore.plugins.loading() ? 'visible' : 'hidden';
+ }, this);
+
+ this.onPluginLoadRequest = _.bind(this.onPluginLoadRequest, this);
+ this.onPluginDisableRequest = _.bind(this.onPluginDisableRequest, this);
+ }
+
+ PluginsAdminSettings.prototype.disablePlugin = function (oPlugin)
+ {
+ oPlugin.disabled(!oPlugin.disabled());
+ Remote.pluginDisable(this.onPluginDisableRequest, oPlugin.name, oPlugin.disabled());
+ };
+
+ PluginsAdminSettings.prototype.configurePlugin = function (oPlugin)
+ {
+ Remote.plugin(this.onPluginLoadRequest, oPlugin.name);
+ };
+
+ PluginsAdminSettings.prototype.onBuild = function (oDom)
+ {
+ var self = this;
+
+ oDom
+ .on('click', '.e-item .configure-plugin-action', function () {
+ var oPlugin = ko.dataFor(this);
+ if (oPlugin)
+ {
+ self.configurePlugin(oPlugin);
+ }
+ })
+ .on('click', '.e-item .disabled-plugin', function () {
+ var oPlugin = ko.dataFor(this);
+ if (oPlugin)
+ {
+ self.disablePlugin(oPlugin);
+ }
+ })
+ ;
+
+ this.enabledPlugins.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'EnabledPlugins': bValue ? '1' : '0'
+ });
+ });
+ };
+
+ PluginsAdminSettings.prototype.onShow = function ()
+ {
+ PluginStore.plugins.error('');
+ __webpack_require__(/*! App/Admin */ 22).default.reloadPluginList();
+ };
+
+ PluginsAdminSettings.prototype.onPluginLoadRequest = function (sResult, oData)
+ {
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Plugin */ 149), [oData.Result]);
+ }
+ };
+
+ PluginsAdminSettings.prototype.onPluginDisableRequest = function (sResult, oData)
+ {
+ if (Enums.StorageResultType.Success === sResult && oData)
+ {
+ if (!oData.Result && oData.ErrorCode)
+ {
+ if (Enums.Notification.UnsupportedPluginPackage === oData.ErrorCode && oData.ErrorMessage && '' !== oData.ErrorMessage)
+ {
+ PluginStore.plugins.error(oData.ErrorMessage);
+ }
+ else
+ {
+ PluginStore.plugins.error(Translator.getNotification(oData.ErrorCode));
+ }
+ }
+ }
+
+ __webpack_require__(/*! App/Admin */ 22).default.reloadPluginList();
+ };
+
+ module.exports = PluginsAdminSettings;
+
+ }());
+
+/***/ },
+/* 126 */
+/*!****************************************!*\
+ !*** ./dev/Settings/Admin/Security.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+
+ AppAdminStore = __webpack_require__(/*! Stores/Admin/App */ 35),
+ CapaAdminStore = __webpack_require__(/*! Stores/Admin/Capa */ 50),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ /**
+ * @constructor
+ */
+ function SecurityAdminSettings()
+ {
+ this.useLocalProxyForExternalImages = AppAdminStore.useLocalProxyForExternalImages;
+
+ this.weakPassword = AppAdminStore.weakPassword;
+
+ this.capaOpenPGP = CapaAdminStore.openPGP;
+
+ this.capaTwoFactorAuth = CapaAdminStore.twoFactorAuth;
+ this.capaTwoFactorAuthForce = CapaAdminStore.twoFactorAuthForce;
+
+ this.capaTwoFactorAuth.subscribe(function (bValue) {
+ if (!bValue)
+ {
+ this.capaTwoFactorAuthForce(false);
+ }
+ }, this);
+
+ this.verifySslCertificate = ko.observable(!!Settings.settingsGet('VerifySslCertificate'));
+ this.allowSelfSigned = ko.observable(!!Settings.settingsGet('AllowSelfSigned'));
+
+ this.verifySslCertificate.subscribe(function (bValue) {
+ if (!bValue)
+ {
+ this.allowSelfSigned(true);
+ }
+ }, this);
+
+ this.adminLogin = ko.observable(Settings.settingsGet('AdminLogin'));
+ this.adminLoginError = ko.observable(false);
+ this.adminPassword = ko.observable('');
+ this.adminPasswordNew = ko.observable('');
+ this.adminPasswordNew2 = ko.observable('');
+ this.adminPasswordNewError = ko.observable(false);
+
+ this.adminPasswordUpdateError = ko.observable(false);
+ this.adminPasswordUpdateSuccess = ko.observable(false);
+
+ this.adminPassword.subscribe(function () {
+ this.adminPasswordUpdateError(false);
+ this.adminPasswordUpdateSuccess(false);
+ }, this);
+
+ this.adminLogin.subscribe(function () {
+ this.adminLoginError(false);
+ }, this);
+
+ this.adminPasswordNew.subscribe(function () {
+ this.adminPasswordUpdateError(false);
+ this.adminPasswordUpdateSuccess(false);
+ this.adminPasswordNewError(false);
+ }, this);
+
+ this.adminPasswordNew2.subscribe(function () {
+ this.adminPasswordUpdateError(false);
+ this.adminPasswordUpdateSuccess(false);
+ this.adminPasswordNewError(false);
+ }, this);
+
+ this.saveNewAdminPasswordCommand = Utils.createCommand(this, function () {
+
+ if ('' === Utils.trim(this.adminLogin()))
+ {
+ this.adminLoginError(true);
+ return false;
+ }
+
+ if (this.adminPasswordNew() !== this.adminPasswordNew2())
+ {
+ this.adminPasswordNewError(true);
+ return false;
+ }
+
+ this.adminPasswordUpdateError(false);
+ this.adminPasswordUpdateSuccess(false);
+
+ Remote.saveNewAdminPassword(this.onNewAdminPasswordResponse, {
+ 'Login': this.adminLogin(),
+ 'Password': this.adminPassword(),
+ 'NewPassword': this.adminPasswordNew()
+ });
+
+ }, function () {
+ return '' !== Utils.trim(this.adminLogin()) && '' !== this.adminPassword();
+ });
+
+ this.onNewAdminPasswordResponse = _.bind(this.onNewAdminPasswordResponse, this);
+ }
+
+ SecurityAdminSettings.prototype.onNewAdminPasswordResponse = function (sResult, oData)
+ {
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ this.adminPassword('');
+ this.adminPasswordNew('');
+ this.adminPasswordNew2('');
+
+ this.adminPasswordUpdateSuccess(true);
+
+ this.weakPassword(!!oData.Result.Weak);
+ }
+ else
+ {
+ this.adminPasswordUpdateError(true);
+ }
+ };
+
+ SecurityAdminSettings.prototype.onBuild = function ()
+ {
+ this.capaOpenPGP.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'CapaOpenPGP': bValue ? '1' : '0'
+ });
+ });
+
+ this.capaTwoFactorAuth.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'CapaTwoFactorAuth': bValue ? '1' : '0'
+ });
+ });
+
+ this.capaTwoFactorAuthForce.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'CapaTwoFactorAuthForce': bValue ? '1' : '0'
+ });
+ });
+
+ this.useLocalProxyForExternalImages.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'UseLocalProxyForExternalImages': bValue ? '1' : '0'
+ });
+ });
+
+ this.verifySslCertificate.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'VerifySslCertificate': bValue ? '1' : '0'
+ });
+ });
+
+ this.allowSelfSigned.subscribe(function (bValue) {
+ Remote.saveAdminConfig(null, {
+ 'AllowSelfSigned': bValue ? '1' : '0'
+ });
+ });
+ };
+
+ SecurityAdminSettings.prototype.onHide = function ()
+ {
+ this.adminPassword('');
+ this.adminPasswordNew('');
+ this.adminPasswordNew2('');
+ };
+
+ /**
+ * @return {string}
+ */
+ SecurityAdminSettings.prototype.phpInfoLink = function ()
+ {
+ return Links.phpInfo();
+ };
+
+ module.exports = SecurityAdminSettings;
+
+ }());
+
+
+/***/ },
+/* 127 */
+/*!**************************************!*\
+ !*** ./dev/Settings/Admin/Social.js ***!
+ \**************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1)
+ ;
+
+ /**
+ * @constructor
+ */
+ function SocialAdminSettings()
+ {
+ var SocialStore = __webpack_require__(/*! Stores/Social */ 34);
+
+ this.googleEnable = SocialStore.google.enabled;
+ this.googleEnableAuth = SocialStore.google.capa.auth;
+ this.googleEnableAuthFast = SocialStore.google.capa.authFast;
+ this.googleEnableDrive = SocialStore.google.capa.drive;
+ this.googleEnablePreview = SocialStore.google.capa.preview;
+
+ this.googleEnableRequireClientSettings = SocialStore.google.require.clientSettings;
+ this.googleEnableRequireApiKey = SocialStore.google.require.apiKeySettings;
+
+ this.googleClientID = SocialStore.google.clientID;
+ this.googleClientSecret = SocialStore.google.clientSecret;
+ this.googleApiKey = SocialStore.google.apiKey;
+
+ this.googleTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.googleTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.googleTrigger3 = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.facebookSupported = SocialStore.facebook.supported;
+ this.facebookEnable = SocialStore.facebook.enabled;
+ this.facebookAppID = SocialStore.facebook.appID;
+ this.facebookAppSecret = SocialStore.facebook.appSecret;
+
+ this.facebookTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.facebookTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.twitterEnable = SocialStore.twitter.enabled;
+ this.twitterConsumerKey = SocialStore.twitter.consumerKey;
+ this.twitterConsumerSecret = SocialStore.twitter.consumerSecret;
+
+ this.twitterTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.twitterTrigger2 = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.dropboxEnable = SocialStore.dropbox.enabled;
+ this.dropboxApiKey = SocialStore.dropbox.apiKey;
+
+ this.dropboxTrigger1 = ko.observable(Enums.SaveSettingsStep.Idle);
+ }
+
+ SocialAdminSettings.prototype.onBuild = function ()
+ {
+ var
+ self = this,
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20)
+ ;
+
+ _.delay(function () {
+
+ var
+ f1 = Utils.settingsSaveHelperSimpleFunction(self.facebookTrigger1, self),
+ f2 = Utils.settingsSaveHelperSimpleFunction(self.facebookTrigger2, self),
+ f3 = Utils.settingsSaveHelperSimpleFunction(self.twitterTrigger1, self),
+ f4 = Utils.settingsSaveHelperSimpleFunction(self.twitterTrigger2, self),
+ f5 = Utils.settingsSaveHelperSimpleFunction(self.googleTrigger1, self),
+ f6 = Utils.settingsSaveHelperSimpleFunction(self.googleTrigger2, self),
+ f7 = Utils.settingsSaveHelperSimpleFunction(self.googleTrigger3, self),
+ f8 = Utils.settingsSaveHelperSimpleFunction(self.dropboxTrigger1, self)
+ ;
+
+ self.facebookEnable.subscribe(function (bValue) {
+ if (self.facebookSupported())
+ {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'FacebookEnable': bValue ? '1' : '0'
+ });
+ }
+ });
+
+ self.facebookAppID.subscribe(function (sValue) {
+ if (self.facebookSupported())
+ {
+ Remote.saveAdminConfig(f1, {
+ 'FacebookAppID': Utils.trim(sValue)
+ });
+ }
+ });
+
+ self.facebookAppSecret.subscribe(function (sValue) {
+ if (self.facebookSupported())
+ {
+ Remote.saveAdminConfig(f2, {
+ 'FacebookAppSecret': Utils.trim(sValue)
+ });
+ }
+ });
+
+ self.twitterEnable.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'TwitterEnable': bValue ? '1' : '0'
+ });
+ });
+
+ self.twitterConsumerKey.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f3, {
+ 'TwitterConsumerKey': Utils.trim(sValue)
+ });
+ });
+
+ self.twitterConsumerSecret.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f4, {
+ 'TwitterConsumerSecret': Utils.trim(sValue)
+ });
+ });
+
+ self.googleEnable.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'GoogleEnable': bValue ? '1' : '0'
+ });
+ });
+
+ self.googleEnableAuth.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'GoogleEnableAuth': bValue ? '1' : '0'
+ });
+ });
+
+ self.googleEnableDrive.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'GoogleEnableDrive': bValue ? '1' : '0'
+ });
+ });
+
+ self.googleEnablePreview.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'GoogleEnablePreview': bValue ? '1' : '0'
+ });
+ });
+
+ self.googleClientID.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f5, {
+ 'GoogleClientID': Utils.trim(sValue)
+ });
+ });
+
+ self.googleClientSecret.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f6, {
+ 'GoogleClientSecret': Utils.trim(sValue)
+ });
+ });
+
+ self.googleApiKey.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f7, {
+ 'GoogleApiKey': Utils.trim(sValue)
+ });
+ });
+
+ self.dropboxEnable.subscribe(function (bValue) {
+ Remote.saveAdminConfig(Utils.emptyFunction, {
+ 'DropboxEnable': bValue ? '1' : '0'
+ });
+ });
+
+ self.dropboxApiKey.subscribe(function (sValue) {
+ Remote.saveAdminConfig(f8, {
+ 'DropboxApiKey': Utils.trim(sValue)
+ });
+ });
+
+ }, 50);
+ };
+
+ module.exports = SocialAdminSettings;
+
+ }());
+
+/***/ },
+/* 128 */,
+/* 129 */,
+/* 130 */,
+/* 131 */,
+/* 132 */,
+/* 133 */,
+/* 134 */,
+/* 135 */,
+/* 136 */,
+/* 137 */,
+/* 138 */,
+/* 139 */
+/*!*************************************!*\
+ !*** ./dev/Stores/Admin/License.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2)
+ ;
+
+ /**
+ * @constructor
+ */
+ function LicenseAdminStore()
+ {
+ this.licensing = ko.observable(false);
+ this.licensingProcess = ko.observable(false);
+ this.licenseValid = ko.observable(false);
+ this.licenseExpired = ko.observable(0);
+ this.licenseError = ko.observable('');
+
+ this.licenseTrigger = ko.observable(false);
+ }
+
+ module.exports = new LicenseAdminStore();
+
+ }());
+
+
+/***/ },
+/* 140 */
+/*!*********************************!*\
+ !*** ./dev/View/Admin/Login.js ***!
+ \*********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function LoginAdminView()
+ {
+ AbstractView.call(this, 'Center', 'AdminLogin');
+
+ this.logoPowered = !!Settings.settingsGet('LoginPowered');
+
+ this.mobile = !!Settings.appSettingsGet('mobile');
+ this.mobileDevice = !!Settings.appSettingsGet('mobileDevice');
+
+ this.login = ko.observable('');
+ this.password = ko.observable('');
+
+ this.loginError = ko.observable(false);
+ this.passwordError = ko.observable(false);
+
+ this.loginErrorAnimation = ko.observable(false).extend({'falseTimeout': 500});
+ this.passwordErrorAnimation = ko.observable(false).extend({'falseTimeout': 500});
+
+ this.loginFocus = ko.observable(false);
+
+ this.formHidden = ko.observable(false);
+
+ this.formError = ko.computed(function () {
+ return this.loginErrorAnimation() || this.passwordErrorAnimation();
+ }, this);
+
+ this.login.subscribe(function () {
+ this.loginError(false);
+ }, this);
+
+ this.password.subscribe(function () {
+ this.passwordError(false);
+ }, this);
+
+ this.loginError.subscribe(function (bV) {
+ this.loginErrorAnimation(!!bV);
+ }, this);
+
+ this.passwordError.subscribe(function (bV) {
+ this.passwordErrorAnimation(!!bV);
+ }, this);
+
+ this.submitRequest = ko.observable(false);
+ this.submitError = ko.observable('');
+
+ this.submitCommand = Utils.createCommand(this, function () {
+
+ Utils.triggerAutocompleteInputChange();
+
+ this.loginError(false);
+ this.passwordError(false);
+
+ this.loginError('' === Utils.trim(this.login()));
+ this.passwordError('' === Utils.trim(this.password()));
+
+ if (this.loginError() || this.passwordError())
+ {
+ return false;
+ }
+
+ this.submitRequest(true);
+
+ Remote.adminLogin(_.bind(function (sResult, oData) {
+
+ if (Enums.StorageResultType.Success === sResult && oData && 'AdminLogin' === oData.Action)
+ {
+ if (oData.Result)
+ {
+ __webpack_require__(/*! App/Admin */ 22).default.loginAndLogoutReload(true);
+ }
+ else if (oData.ErrorCode)
+ {
+ this.submitRequest(false);
+ this.submitError(Translator.getNotification(oData.ErrorCode));
+ }
+ }
+ else
+ {
+ this.submitRequest(false);
+ this.submitError(Translator.getNotification(Enums.Notification.UnknownError));
+ }
+
+ }, this), this.login(), this.password());
+
+ return true;
+
+ }, function () {
+ return !this.submitRequest();
+ });
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Admin/Login', 'AdminLoginViewModel'], LoginAdminView);
+ _.extend(LoginAdminView.prototype, AbstractView.prototype);
+
+ LoginAdminView.prototype.onShow = function ()
+ {
+ kn.routeOff();
+
+ _.delay(_.bind(function () {
+ this.loginFocus(true);
+ }, this), 100);
+
+ };
+
+ LoginAdminView.prototype.onHide = function ()
+ {
+ this.loginFocus(false);
+ };
+
+ LoginAdminView.prototype.onBuild = function ()
+ {
+ Utils.triggerAutocompleteInputChange(true);
+ };
+
+ LoginAdminView.prototype.submitForm = function ()
+ {
+ this.submitCommand();
+ };
+
+ module.exports = LoginAdminView;
+
+ }());
+
+/***/ },
+/* 141 */
+/*!*****************************************!*\
+ !*** ./dev/View/Admin/Settings/Menu.js ***!
+ \*****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @param {?} oScreen
+ *
+ * @constructor
+ * @extends AbstractView
+ */
+ function MenuSettingsAdminView(oScreen)
+ {
+ AbstractView.call(this, 'Left', 'AdminMenu');
+
+ this.leftPanelDisabled = Globals.leftPanelDisabled;
+
+ this.menu = oScreen.menu;
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Admin/Settings/Menu', 'AdminSettingsMenuViewModel'], MenuSettingsAdminView);
+ _.extend(MenuSettingsAdminView.prototype, AbstractView.prototype);
+
+ MenuSettingsAdminView.prototype.link = function (sRoute)
+ {
+ return '#/' + sRoute;
+ };
+
+ MenuSettingsAdminView.prototype.onBuild = function (oDom)
+ {
+ key('up, down', _.throttle(function (event, handler) {
+
+ var
+ sH = '',
+ iIndex = -1,
+ bUp = handler && 'up' === handler.shortcut,
+ $items = $('.b-admin-menu .e-item', oDom)
+ ;
+
+ if (event && $items.length)
+ {
+ iIndex = $items.index($items.filter('.selected'));
+ if (bUp && iIndex > 0)
+ {
+ iIndex--;
+ }
+ else if (!bUp && iIndex < $items.length - 1)
+ {
+ iIndex++;
+ }
+
+ sH = $items.eq(iIndex).attr('href');
+ if (sH)
+ {
+ kn.setHash(sH, false, true);
+ }
+ }
+
+ }, 200));
+ };
+
+ module.exports = MenuSettingsAdminView;
+
+ }());
+
+
+/***/ },
+/* 142 */
+/*!*****************************************!*\
+ !*** ./dev/View/Admin/Settings/Pane.js ***!
+ \*****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function PaneSettingsAdminView()
+ {
+ AbstractView.call(this, 'Right', 'AdminPane');
+
+ this.adminDomain = ko.observable(Settings.settingsGet('AdminDomain'));
+ this.version = ko.observable(Settings.appSettingsGet('version'));
+
+ this.capa = !!Settings.settingsGet('PremType');
+ this.community = (true);
+
+ this.adminManLoading = ko.computed(function () {
+ return '000' !== [
+ __webpack_require__(/*! Stores/Admin/Domain */ 57).domains.loading() ? '1' : '0',
+ __webpack_require__(/*! Stores/Admin/Plugin */ 59).plugins.loading() ? '1' : '0',
+ __webpack_require__(/*! Stores/Admin/Package */ 58).packages.loading() ? '1' : '0'
+ ].join('');
+ }, this);
+
+ this.adminManLoadingVisibility = ko.computed(function () {
+ return this.adminManLoading() ? 'visible' : 'hidden';
+ }, this).extend({'rateLimit': 300});
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Admin/Settings/Pane', 'AdminSettingsPaneViewModel'], PaneSettingsAdminView);
+ _.extend(PaneSettingsAdminView.prototype, AbstractView.prototype);
+
+ PaneSettingsAdminView.prototype.logoutClick = function ()
+ {
+ Remote.adminLogout(function () {
+ __webpack_require__(/*! App/Admin */ 22).default.loginAndLogoutReload(true, true);
+ });
+ };
+
+ module.exports = PaneSettingsAdminView;
+
+ }());
+
+/***/ },
+/* 143 */,
+/* 144 */,
+/* 145 */,
+/* 146 */,
+/* 147 */,
+/* 148 */,
+/* 149 */
+/*!**********************************!*\
+ !*** ./dev/View/Popup/Plugin.js ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+ key = __webpack_require__(/*! key */ 18),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Remote = __webpack_require__(/*! Remote/Admin/Ajax */ 20),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function PluginPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsPlugin');
+
+ var self = this;
+
+ this.onPluginSettingsUpdateResponse = _.bind(this.onPluginSettingsUpdateResponse, this);
+
+ this.saveError = ko.observable('');
+
+ this.name = ko.observable('');
+ this.readme = ko.observable('');
+
+ this.configures = ko.observableArray([]);
+
+ this.hasReadme = ko.computed(function () {
+ return '' !== this.readme();
+ }, this);
+
+ this.hasConfiguration = ko.computed(function () {
+ return 0 < this.configures().length;
+ }, this);
+
+ this.readmePopoverConf = {
+ 'placement': 'right',
+ 'trigger': 'hover',
+ // 'trigger': 'click',
+ 'title': Translator.i18n('POPUPS_PLUGIN/TOOLTIP_ABOUT_TITLE'),
+ 'container': 'body',
+ 'html': true,
+ 'content': function () {
+ return '' + self.readme() + ' ';
+ // .replace(/[\r]/g, '').replace(/[\n]/g, ' ').replace(/[\t]/g, ' ');
+ }
+ };
+
+ this.saveCommand = Utils.createCommand(this, function () {
+
+ var oList = {};
+
+ oList['Name'] = this.name();
+
+ _.each(this.configures(), function (oItem) {
+
+ var mValue = oItem.value();
+ if (false === mValue || true === mValue)
+ {
+ mValue = mValue ? '1' : '0';
+ }
+
+ oList['_' + oItem['Name']] = mValue;
+
+ }, this);
+
+ this.saveError('');
+ Remote.pluginSettingsUpdate(this.onPluginSettingsUpdateResponse, oList);
+
+ }, this.hasConfiguration);
+
+ this.bDisabeCloseOnEsc = true;
+ this.sDefaultKeyScope = Enums.KeyState.All;
+
+ this.tryToClosePopup = _.debounce(_.bind(this.tryToClosePopup, this), 200);
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/Plugin', 'PopupsPluginViewModel'], PluginPopupView);
+ _.extend(PluginPopupView.prototype, AbstractView.prototype);
+
+ PluginPopupView.prototype.onPluginSettingsUpdateResponse = function (sResult, oData)
+ {
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ this.cancelCommand();
+ }
+ else
+ {
+ this.saveError('');
+ if (oData && oData.ErrorCode)
+ {
+ this.saveError(Translator.getNotification(oData.ErrorCode));
+ }
+ else
+ {
+ this.saveError(Translator.getNotification(Enums.Notification.CantSavePluginSettings));
+ }
+ }
+ };
+
+ PluginPopupView.prototype.onShow = function (oPlugin)
+ {
+ this.name();
+ this.readme();
+ this.configures([]);
+
+ if (oPlugin)
+ {
+ this.name(oPlugin['Name']);
+ this.readme(oPlugin['Readme']);
+
+ var aConfig = oPlugin['Config'];
+ if (Utils.isNonEmptyArray(aConfig))
+ {
+ this.configures(_.map(aConfig, function (aItem) {
+ return {
+ 'value': ko.observable(aItem[0]),
+ 'placeholder': ko.observable(aItem[6]),
+ 'Name': aItem[1],
+ 'Type': aItem[2],
+ 'Label': aItem[3],
+ 'Default': aItem[4],
+ 'Desc': aItem[5]
+ };
+ }));
+ }
+ }
+ };
+
+ PluginPopupView.prototype.tryToClosePopup = function ()
+ {
+ var
+ self = this,
+ PopupsAskViewModel = __webpack_require__(/*! View/Popup/Ask */ 43)
+ ;
+
+ if (!kn.isPopupVisible(PopupsAskViewModel))
+ {
+ kn.showScreenPopup(PopupsAskViewModel, [Translator.i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'), function () {
+ if (self.modalVisibility())
+ {
+ Utils.delegateRun(self, 'cancelCommand');
+ }
+ }]);
+ }
+ };
+
+ PluginPopupView.prototype.onBuild = function ()
+ {
+ key('esc', Enums.KeyState.All, _.bind(function () {
+ if (this.modalVisibility())
+ {
+ this.tryToClosePopup();
+ }
+ return false;
+ }, this));
+ };
+
+ module.exports = PluginPopupView;
+
+ }());
+
+/***/ }
+/******/ ]);
diff --git a/rainloop/rainloop/v/1.10.0.103/static/js/app.js b/rainloop/rainloop/v/1.10.0.103/static/js/app.js
new file mode 100644
index 0000000..5279a78
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/static/js/app.js
@@ -0,0 +1,31513 @@
+/* RainLoop Webmail (c) RainLoop Team | Licensed under AGPL v3 */
+/******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId])
+/******/ return installedModules[moduleId].exports;
+
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ exports: {},
+/******/ id: moduleId,
+/******/ loaded: false
+/******/ };
+
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ // Flag the module as loaded
+/******/ module.loaded = true;
+
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+
+
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "rainloop/v/0.0.0/static/js/";
+
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/*!*********************!*\
+ !*** ./dev/app.jsx ***!
+ \*********************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _bootstrap = __webpack_require__(/*! bootstrap */ 77);
+
+ var _bootstrap2 = _interopRequireDefault(_bootstrap);
+
+ var _User = __webpack_require__(/*! App/User */ 7);
+
+ var _User2 = _interopRequireDefault(_User);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ (0, _bootstrap2.default)(_User2.default);
+
+/***/ },
+/* 1 */
+/*!*****************************!*\
+ !*** ./dev/Common/Utils.js ***!
+ \*****************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ oEncryptObject = null,
+
+ Utils = {},
+
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+ Autolinker = __webpack_require__(/*! Autolinker */ 78),
+ JSON = __webpack_require__(/*! JSON */ 36),
+ JSEncrypt = __webpack_require__(/*! JSEncrypt */ 79),
+
+ Mime = __webpack_require__(/*! Common/Mime */ 66),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Globals = __webpack_require__(/*! Common/Globals */ 8)
+ ;
+
+ Utils.trim = $.trim;
+ Utils.inArray = $.inArray;
+ Utils.isArray = _.isArray;
+ Utils.isObject = _.isObject;
+ Utils.isFunc = _.isFunction;
+ Utils.isUnd = _.isUndefined;
+ Utils.isNull = _.isNull;
+ Utils.emptyFunction = Utils.noop = function () {};
+
+ /**
+ * @param {Function} callback
+ */
+ Utils.silentTryCatch = function (callback)
+ {
+ try
+ {
+ callback();
+ }
+ catch (e)
+ {
+ // eslint-disable-line no-empty
+ }
+ };
+
+ /**
+ * @param {*} oValue
+ * @return {boolean}
+ */
+ Utils.isNormal = function (oValue)
+ {
+ return !Utils.isUnd(oValue) && !Utils.isNull(oValue);
+ };
+
+ Utils.windowResize = _.debounce(function (iTimeout) {
+ if (Utils.isUnd(iTimeout))
+ {
+ Globals.$win.resize();
+ }
+ else
+ {
+ window.setTimeout(function () {
+ Globals.$win.resize();
+ }, iTimeout);
+ }
+ }, 50);
+
+ Utils.windowResizeCallback = function () {
+ Utils.windowResize();
+ };
+
+ /**
+ * @param {(string|number)} mValue
+ * @param {boolean=} bIncludeZero
+ * @return {boolean}
+ */
+ Utils.isPosNumeric = function (mValue, bIncludeZero)
+ {
+ return Utils.isNormal(mValue) ?
+ ((Utils.isUnd(bIncludeZero) ? true : !!bIncludeZero) ?
+ (/^[0-9]*$/).test(mValue.toString()) :
+ (/^[1-9]+[0-9]*$/).test(mValue.toString())) :
+ false;
+ };
+
+ /**
+ * @param {*} iValue
+ * @param {number=} iDefault = 0
+ * @return {number}
+ */
+ Utils.pInt = function (iValue, iDefault)
+ {
+ var iResult = Utils.isNormal(iValue) && '' !== iValue ? window.parseInt(iValue, 10) : (iDefault || 0);
+ return window.isNaN(iResult) ? (iDefault || 0) : iResult;
+ };
+
+ /**
+ * @param {*} mValue
+ * @return {string}
+ */
+ Utils.pString = function (mValue)
+ {
+ return Utils.isNormal(mValue) ? '' + mValue : '';
+ };
+
+ /**
+ * @param {*} mValue
+ * @return {boolean}
+ */
+ Utils.pBool = function (mValue)
+ {
+ return !!mValue;
+ };
+
+ /**
+ * @param {string} sComponent
+ * @return {string}
+ */
+ Utils.encodeURIComponent = function (sComponent)
+ {
+ return window.encodeURIComponent(sComponent);
+ };
+
+ /**
+ * @param {*} aValue
+ * @return {boolean}
+ */
+ Utils.isNonEmptyArray = function (aValue)
+ {
+ return Utils.isArray(aValue) && 0 < aValue.length;
+ };
+
+ /**
+ * @param {string} sQueryString
+ * @return {Object}
+ */
+ Utils.simpleQueryParser = function (sQueryString)
+ {
+ var
+ oParams = {},
+ aQueries = [],
+ aTemp = [],
+ iIndex = 0,
+ iLen = 0
+ ;
+
+ aQueries = sQueryString.split('&');
+ for (iIndex = 0, iLen = aQueries.length; iIndex < iLen; iIndex++)
+ {
+ aTemp = aQueries[iIndex].split('=');
+ oParams[window.decodeURIComponent(aTemp[0])] = window.decodeURIComponent(aTemp[1]);
+ }
+
+ return oParams;
+ };
+
+ /**
+ * @param {string} sMailToUrl
+ * @param {Function} PopupComposeVoreModel
+ * @return {boolean}
+ */
+ Utils.mailToHelper = function (sMailToUrl, PopupComposeVoreModel)
+ {
+ if (sMailToUrl && 'mailto:' === sMailToUrl.toString().substr(0, 7).toLowerCase())
+ {
+ if (!PopupComposeVoreModel)
+ {
+ return true;
+ }
+
+ sMailToUrl = sMailToUrl.toString().substr(7);
+
+ var
+ aTo = [],
+ aCc = null,
+ aBcc = null,
+ oParams = {},
+ EmailModel = __webpack_require__(/*! Model/Email */ 30),
+ sEmail = sMailToUrl.replace(/\?.+$/, ''),
+ sQueryString = sMailToUrl.replace(/^[^\?]*\?/, ''),
+ fParseEmailLine = function (sLine) {
+ return sLine ? _.compact(_.map(window.decodeURIComponent(sLine).split(/[,]/), function (sItem) {
+ var oEmailModel = new EmailModel();
+ oEmailModel.mailsoParse(sItem);
+ return '' !== oEmailModel.email ? oEmailModel : null;
+ })) : null;
+ }
+ ;
+
+ aTo = fParseEmailLine(sEmail);
+
+ oParams = Utils.simpleQueryParser(sQueryString);
+
+ if (!Utils.isUnd(oParams.cc))
+ {
+ aCc = fParseEmailLine(window.decodeURIComponent(oParams.cc));
+ }
+
+ if (!Utils.isUnd(oParams.bcc))
+ {
+ aBcc = fParseEmailLine(window.decodeURIComponent(oParams.bcc));
+ }
+
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(PopupComposeVoreModel, [Enums.ComposeType.Empty, null,
+ aTo, aCc, aBcc,
+ Utils.isUnd(oParams.subject) ? null :
+ Utils.pString(window.decodeURIComponent(oParams.subject)),
+ Utils.isUnd(oParams.body) ? null :
+ Utils.plainToHtml(Utils.pString(window.decodeURIComponent(oParams.body)))
+ ]);
+
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {string} sPublicKey
+ * @return {JSEncrypt}
+ */
+ Utils.rsaObject = function (sPublicKey)
+ {
+ if (JSEncrypt && sPublicKey && (null === oEncryptObject || (oEncryptObject && oEncryptObject.__sPublicKey !== sPublicKey)) &&
+ window.crypto && window.crypto.getRandomValues)
+ {
+ oEncryptObject = new JSEncrypt();
+ oEncryptObject.setPublicKey(sPublicKey);
+ oEncryptObject.__sPublicKey = sPublicKey;
+ }
+ else
+ {
+ oEncryptObject = false;
+ }
+
+ return oEncryptObject;
+ };
+
+ /**
+ * @param {string} sValue
+ * @param {string} sPublicKey
+ * @return {string}
+ */
+ Utils.rsaEncode = function (sValue, sPublicKey)
+ {
+ if (window.crypto && window.crypto.getRandomValues && sPublicKey)
+ {
+ var
+ sResultValue = false,
+ oEncrypt = Utils.rsaObject(sPublicKey)
+ ;
+
+ if (oEncrypt)
+ {
+ sResultValue = oEncrypt.encrypt(Utils.fakeMd5() + ':' + sValue + ':' + Utils.fakeMd5());
+ if (false !== sResultValue && Utils.isNormal(sResultValue))
+ {
+ return 'rsa:xxx:' + sResultValue;
+ }
+ }
+ }
+
+ return sValue;
+ };
+
+ Utils.rsaEncode.supported = !!(window.crypto && window.crypto.getRandomValues && false && JSEncrypt);
+
+ /**
+ * @param {string} sText
+ * @return {string}
+ */
+ Utils.encodeHtml = function (sText)
+ {
+ return Utils.isNormal(sText) ? _.escape(sText.toString()) : '';
+ };
+
+ /**
+ * @param {string} sText
+ * @param {number=} iLen
+ * @return {string}
+ */
+ Utils.splitPlainText = function (sText, iLen)
+ {
+ var
+ sPrefix = '',
+ sSubText = '',
+ sResult = sText,
+ iSpacePos = 0,
+ iNewLinePos = 0
+ ;
+
+ iLen = Utils.isUnd(iLen) ? 100 : iLen;
+
+ while (sResult.length > iLen)
+ {
+ sSubText = sResult.substring(0, iLen);
+ iSpacePos = sSubText.lastIndexOf(' ');
+ iNewLinePos = sSubText.lastIndexOf('\n');
+
+ if (-1 !== iNewLinePos)
+ {
+ iSpacePos = iNewLinePos;
+ }
+
+ if (-1 === iSpacePos)
+ {
+ iSpacePos = iLen;
+ }
+
+ sPrefix += sSubText.substring(0, iSpacePos) + '\n';
+ sResult = sResult.substring(iSpacePos + 1);
+ }
+
+ return sPrefix + sResult;
+ };
+
+ Utils.timeOutAction = (function () {
+
+ var
+ oTimeOuts = {}
+ ;
+
+ return function (sAction, fFunction, iTimeOut)
+ {
+ if (Utils.isUnd(oTimeOuts[sAction]))
+ {
+ oTimeOuts[sAction] = 0;
+ }
+
+ window.clearTimeout(oTimeOuts[sAction]);
+ oTimeOuts[sAction] = window.setTimeout(fFunction, iTimeOut);
+ };
+ }());
+
+ Utils.timeOutActionSecond = (function () {
+
+ var
+ oTimeOuts = {}
+ ;
+
+ return function (sAction, fFunction, iTimeOut)
+ {
+ if (!oTimeOuts[sAction])
+ {
+ oTimeOuts[sAction] = window.setTimeout(function () {
+ fFunction();
+ oTimeOuts[sAction] = 0;
+ }, iTimeOut);
+ }
+ };
+ }());
+
+ /**
+ * @param {(Object|null|undefined)} oObject
+ * @param {string} sProp
+ * @return {boolean}
+ */
+ Utils.hos = function (oObject, sProp)
+ {
+ return oObject && window.Object && window.Object.hasOwnProperty ? window.Object.hasOwnProperty.call(oObject, sProp) : false;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ Utils.inFocus = function ()
+ {
+ if (window.document.activeElement)
+ {
+ if (Utils.isUnd(window.document.activeElement.__inFocusCache))
+ {
+ window.document.activeElement.__inFocusCache = $(window.document.activeElement).is('input,textarea,iframe,.cke_editable');
+ }
+
+ return !!window.document.activeElement.__inFocusCache;
+ }
+
+ return false;
+ };
+
+ Utils.removeInFocus = function (force)
+ {
+ if (window.document && window.document.activeElement && window.document.activeElement.blur)
+ {
+ var oA = $(window.document.activeElement);
+ if (oA.is('input,textarea'))
+ {
+ window.document.activeElement.blur();
+ }
+ else if (force)
+ {
+ try {
+ window.document.activeElement.blur();
+ } catch (e) {}
+ }
+ }
+ };
+
+ Utils.removeSelection = function ()
+ {
+ if (window && window.getSelection)
+ {
+ var oSel = window.getSelection();
+ if (oSel && oSel.removeAllRanges)
+ {
+ oSel.removeAllRanges();
+ }
+ }
+ else if (window.document && window.document.selection && window.document.selection.empty)
+ {
+ window.document.selection.empty();
+ }
+ };
+
+ /**
+ * @param {string} sPrefix
+ * @param {string} sSubject
+ * @return {string}
+ */
+ Utils.replySubjectAdd = function (sPrefix, sSubject)
+ {
+ sPrefix = Utils.trim(sPrefix.toUpperCase());
+ sSubject = Utils.trim(sSubject.replace(/[\s]+/g, ' '));
+
+ var
+ bDrop = false,
+ aSubject = [],
+ bRe = 'RE' === sPrefix,
+ bFwd = 'FWD' === sPrefix,
+ bPrefixIsRe = !bFwd
+ ;
+
+ if ('' !== sSubject)
+ {
+ _.each(sSubject.split(':'), function (sPart) {
+ var sTrimmedPart = Utils.trim(sPart);
+ if (!bDrop && (/^(RE|FWD)$/i.test(sTrimmedPart) || /^(RE|FWD)[\[\(][\d]+[\]\)]$/i.test(sTrimmedPart)))
+ {
+ if (!bRe)
+ {
+ bRe = !!(/^RE/i.test(sTrimmedPart));
+ }
+
+ if (!bFwd)
+ {
+ bFwd = !!(/^FWD/i.test(sTrimmedPart));
+ }
+ }
+ else
+ {
+ aSubject.push(sPart);
+ bDrop = true;
+ }
+ });
+ }
+
+ if (bPrefixIsRe)
+ {
+ bRe = false;
+ }
+ else
+ {
+ bFwd = false;
+ }
+
+ return Utils.trim(
+ (bPrefixIsRe ? 'Re: ' : 'Fwd: ') +
+ (bRe ? 'Re: ' : '') +
+ (bFwd ? 'Fwd: ' : '') +
+ Utils.trim(aSubject.join(':'))
+ );
+ };
+
+ /**
+ * @param {number} iNum
+ * @param {number} iDec
+ * @return {number}
+ */
+ Utils.roundNumber = function (iNum, iDec)
+ {
+ return window.Math.round(iNum * window.Math.pow(10, iDec)) / window.Math.pow(10, iDec);
+ };
+
+ /**
+ * @param {(number|string)} iSizeInBytes
+ * @return {string}
+ */
+ Utils.friendlySize = function (iSizeInBytes)
+ {
+ iSizeInBytes = Utils.pInt(iSizeInBytes);
+
+ if (iSizeInBytes >= 1073741824)
+ {
+ return Utils.roundNumber(iSizeInBytes / 1073741824, 1) + 'GB';
+ }
+ else if (iSizeInBytes >= 1048576)
+ {
+ return Utils.roundNumber(iSizeInBytes / 1048576, 1) + 'MB';
+ }
+ else if (iSizeInBytes >= 1024)
+ {
+ return Utils.roundNumber(iSizeInBytes / 1024, 0) + 'KB';
+ }
+
+ return iSizeInBytes + 'B';
+ };
+
+ /**
+ * @param {string} sDesc
+ */
+ Utils.log = function (sDesc)
+ {
+ if (window.console && window.console.log)
+ {
+ window.console.log(sDesc);
+ }
+ };
+
+ /**
+ * @param {?} oObject
+ * @param {string} sMethodName
+ * @param {Array=} aParameters
+ * @param {number=} nDelay
+ */
+ Utils.delegateRun = function (oObject, sMethodName, aParameters, nDelay)
+ {
+ if (oObject && oObject[sMethodName])
+ {
+ nDelay = Utils.pInt(nDelay);
+ if (0 >= nDelay)
+ {
+ oObject[sMethodName].apply(oObject, Utils.isArray(aParameters) ? aParameters : []);
+ }
+ else
+ {
+ _.delay(function () {
+ oObject[sMethodName].apply(oObject, Utils.isArray(aParameters) ? aParameters : []);
+ }, nDelay);
+ }
+ }
+ };
+
+ /**
+ * @param {?} oEvent
+ */
+ Utils.kill_CtrlA_CtrlS = function (oEvent)
+ {
+ oEvent = oEvent || window.event;
+ if (oEvent && oEvent.ctrlKey && !oEvent.shiftKey && !oEvent.altKey)
+ {
+ var
+ oSender = oEvent.target || oEvent.srcElement,
+ iKey = oEvent.keyCode || oEvent.which
+ ;
+
+ if (iKey === Enums.EventKeyCode.S)
+ {
+ oEvent.preventDefault();
+ return;
+ }
+ else if (iKey === Enums.EventKeyCode.A)
+ {
+ if (oSender && ('true' === '' + oSender.contentEditable ||
+ (oSender.tagName && oSender.tagName.match(/INPUT|TEXTAREA/i))))
+ {
+ return;
+ }
+
+ if (window.getSelection)
+ {
+ window.getSelection().removeAllRanges();
+ }
+ else if (window.document.selection && window.document.selection.clear)
+ {
+ window.document.selection.clear();
+ }
+
+ oEvent.preventDefault();
+ }
+ }
+ };
+
+ /**
+ * @param {(Object|null|undefined)} oContext
+ * @param {Function} fExecute
+ * @param {(Function|boolean|null)=} fCanExecute
+ * @return {Function}
+ */
+ Utils.createCommand = function (oContext, fExecute, fCanExecute)
+ {
+ var
+ fResult = Utils.emptyFunction,
+ fNonEmpty = function () {
+ if (fResult && fResult.canExecute && fResult.canExecute())
+ {
+ fExecute.apply(oContext, Array.prototype.slice.call(arguments));
+ }
+ return false;
+ }
+ ;
+
+ fResult = fExecute ? fNonEmpty : Utils.emptyFunction;
+ fResult.enabled = ko.observable(true);
+
+ fCanExecute = Utils.isUnd(fCanExecute) ? true : fCanExecute;
+ if (Utils.isFunc(fCanExecute))
+ {
+ fResult.canExecute = ko.computed(function () {
+ return fResult.enabled() && fCanExecute.call(oContext);
+ });
+ }
+ else
+ {
+ fResult.canExecute = ko.computed(function () {
+ return fResult.enabled() && !!fCanExecute;
+ });
+ }
+
+ return fResult;
+ };
+
+ /**
+ * @param {string} sTheme
+ * @return {string}
+ */
+ Utils.convertThemeName = _.memoize(function (sTheme)
+ {
+ if ('@custom' === sTheme.substr(-7))
+ {
+ sTheme = Utils.trim(sTheme.substring(0, sTheme.length - 7));
+ }
+
+ return Utils.trim(sTheme.replace(/[^a-zA-Z0-9]+/g, ' ').replace(/([A-Z])/g, ' $1').replace(/[\s]+/g, ' '));
+ });
+
+ /**
+ * @param {string} sName
+ * @return {string}
+ */
+ Utils.quoteName = function (sName)
+ {
+ return sName.replace(/["]/g, '\\"');
+ };
+
+ /**
+ * @return {number}
+ */
+ Utils.microtime = function ()
+ {
+ return (new window.Date()).getTime();
+ };
+
+ /**
+ * @return {number}
+ */
+ Utils.timestamp = function ()
+ {
+ return window.Math.round(Utils.microtime() / 1000);
+ };
+
+ /**
+ *
+ * @param {string} sLanguage
+ * @param {boolean=} bEng = false
+ * @return {string}
+ */
+ Utils.convertLangName = function (sLanguage, bEng)
+ {
+ return __webpack_require__(/*! Common/Translator */ 6).i18n('LANGS_NAMES' + (true === bEng ? '_EN' : '') + '/LANG_' +
+ sLanguage.toUpperCase().replace(/[^a-zA-Z0-9]+/g, '_'), null, sLanguage);
+ };
+
+ /**
+ * @param {number=} iLen
+ * @return {string}
+ */
+ Utils.fakeMd5 = function(iLen)
+ {
+ var
+ sResult = '',
+ sLine = '0123456789abcdefghijklmnopqrstuvwxyz'
+ ;
+
+ iLen = Utils.isUnd(iLen) ? 32 : Utils.pInt(iLen);
+
+ while (sResult.length < iLen)
+ {
+ sResult += sLine.substr(window.Math.round(window.Math.random() * sLine.length), 1);
+ }
+
+ return sResult;
+ };
+
+ Utils.draggablePlace = function ()
+ {
+ return $('' +
+ ' ' +
+ '
').appendTo('#rl-hidden');
+ };
+
+ Utils.defautOptionsAfterRender = function (oDomOption, oItem)
+ {
+ if (oItem && !Utils.isUnd(oItem.disabled) && oDomOption)
+ {
+ $(oDomOption)
+ .toggleClass('disabled', oItem.disabled)
+ .prop('disabled', oItem.disabled)
+ ;
+ }
+ };
+
+ /**
+ * @param {Object} oViewModel
+ * @param {string} sTemplateID
+ * @param {string} sTitle
+ * @param {Function=} fCallback
+ */
+ Utils.windowPopupKnockout = function (oViewModel, sTemplateID, sTitle, fCallback)
+ {
+ var
+ oScript = null,
+ oWin = window.open(''),
+ sFunc = '__OpenerApplyBindingsUid' + Utils.fakeMd5() + '__',
+ oTemplate = $('#' + sTemplateID)
+ ;
+
+ window[sFunc] = function () {
+
+ if (oWin && oWin.document.body && oTemplate && oTemplate[0])
+ {
+ var oBody = $(oWin.document.body);
+
+ $('#rl-content', oBody).html(oTemplate.html());
+ $('html', oWin.document).addClass('external ' + $('html').attr('class'));
+
+ __webpack_require__(/*! Common/Translator */ 6).i18nToNodes(oBody);
+
+ if (oViewModel && $('#rl-content', oBody)[0])
+ {
+ ko.applyBindings(oViewModel, $('#rl-content', oBody)[0]);
+ }
+
+ window[sFunc] = null;
+
+ fCallback(oWin);
+ }
+ };
+
+ oWin.document.open();
+ oWin.document.write('' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ '' + Utils.encodeHtml(sTitle) + ' ' +
+ '
');
+ oWin.document.close();
+
+ oScript = oWin.document.createElement('script');
+ oScript.type = 'text/javascript';
+ oScript.innerHTML = 'if(window&&window.opener&&window.opener[\'' + sFunc + '\']){window.opener[\'' + sFunc + '\']();window.opener[\'' + sFunc + '\']=null}';
+ oWin.document.getElementsByTagName('head')[0].appendChild(oScript);
+ };
+
+ /**
+ * @param {Function} fCallback
+ * @param {?} koTrigger
+ * @param {?} oContext = null
+ * @param {number=} iTimer = 1000
+ * @return {Function}
+ */
+ Utils.settingsSaveHelperFunction = function (fCallback, koTrigger, oContext, iTimer)
+ {
+ oContext = oContext || null;
+ iTimer = Utils.isUnd(iTimer) ? 1000 : Utils.pInt(iTimer);
+
+ return function (sType, mData, bCached, sRequestAction, oRequestParameters) {
+ koTrigger.call(oContext, mData && mData['Result'] ? Enums.SaveSettingsStep.TrueResult : Enums.SaveSettingsStep.FalseResult);
+ if (fCallback)
+ {
+ fCallback.call(oContext, sType, mData, bCached, sRequestAction, oRequestParameters);
+ }
+ _.delay(function () {
+ koTrigger.call(oContext, Enums.SaveSettingsStep.Idle);
+ }, iTimer);
+ };
+ };
+
+ Utils.settingsSaveHelperSimpleFunction = function (koTrigger, oContext)
+ {
+ return Utils.settingsSaveHelperFunction(null, koTrigger, oContext, 1000);
+ };
+
+ Utils.settingsSaveHelperSubscribeFunction = function (oRemote, sSettingName, sType, fTriggerFunction)
+ {
+ return function (mValue) {
+
+ if (oRemote)
+ {
+ switch (sType)
+ {
+ default:
+ mValue = Utils.pString(mValue);
+ break;
+ case 'bool':
+ case 'boolean':
+ mValue = mValue ? '1' : '0';
+ break;
+ case 'int':
+ case 'integer':
+ case 'number':
+ mValue = Utils.pInt(mValue);
+ break;
+ case 'trim':
+ mValue = Utils.trim(mValue);
+ break;
+ }
+
+ var oData = {};
+ oData[sSettingName] = mValue;
+
+ if (oRemote.saveAdminConfig)
+ {
+ oRemote.saveAdminConfig(fTriggerFunction || null, oData);
+ }
+ else if (oRemote.saveSettings)
+ {
+ oRemote.saveSettings(fTriggerFunction || null, oData);
+ }
+ }
+ };
+ };
+
+ /**
+ * @param {string} sHtml
+ * @return {string}
+ */
+ Utils.htmlToPlain = function (sHtml)
+ {
+ var
+ iPos = 0,
+ iP1 = 0,
+ iP2 = 0,
+ iP3 = 0,
+ iLimit = 0,
+
+ sText = '',
+
+ convertBlockquote = function (sText) {
+ sText = Utils.trim(sText);
+ sText = '> ' + sText.replace(/\n/gm, '\n> ');
+ return sText.replace(/(^|\n)([> ]+)/gm, function () {
+ return (arguments && 2 < arguments.length) ? arguments[1] + $.trim(arguments[2].replace(/[\s]/g, '')) + ' ' : '';
+ });
+ },
+
+ convertDivs = function () {
+ if (arguments && 1 < arguments.length)
+ {
+ var sText = $.trim(arguments[1]);
+ if (0 < sText.length)
+ {
+ sText = sText.replace(/]*>([\s\S\r\n]*)<\/div>/gmi, convertDivs);
+ sText = '\n' + $.trim(sText) + '\n';
+ }
+
+ return sText;
+ }
+
+ return '';
+ },
+
+ convertPre = function () {
+ return (arguments && 1 < arguments.length) ?
+ arguments[1].toString()
+ .replace(/[\n]/gm, '
')
+ .replace(/[\r]/gm, '')
+ : '';
+ },
+
+ fixAttibuteValue = function () {
+ return (arguments && 1 < arguments.length) ?
+ '' + arguments[1] + _.escape(arguments[2]) : '';
+ },
+
+ convertLinks = function () {
+ return (arguments && 1 < arguments.length) ? $.trim(arguments[1]) : '';
+ }
+ ;
+
+ sText = sHtml
+ .replace(/\u0002([\s\S]*)\u0002/gm, '\u200C$1\u200C')
+ .replace(/
]*><\/p>/gi, '')
+ .replace(/
]*>([\s\S\r\n\t]*)<\/pre>/gmi, convertPre)
+ .replace(/[\s]+/gm, ' ')
+ .replace(/((?:href|data)\s?=\s?)("[^"]+?"|'[^']+?')/gmi, fixAttibuteValue)
+ .replace(/ ]*>/gmi, '\n')
+ .replace(/<\/h[\d]>/gi, '\n')
+ .replace(/<\/p>/gi, '\n\n')
+ .replace(/ ]*>/gmi, '\n')
+ .replace(/<\/ul>/gi, '\n')
+ .replace(/]*>/gmi, ' * ')
+ .replace(/<\/li>/gi, '\n')
+ .replace(/<\/td>/gi, '\n')
+ .replace(/<\/tr>/gi, '\n')
+ .replace(/ ]*>/gmi, '\n_______________________________\n\n')
+ .replace(/]*>([\s\S\r\n]*)<\/div>/gmi, convertDivs)
+ .replace(/
]*>/gmi, '\n__bq__start__\n')
+ .replace(/<\/blockquote>/gmi, '\n__bq__end__\n')
+ .replace(/]*>([\s\S\r\n]*?)<\/a>/gmi, convertLinks)
+ .replace(/<\/div>/gi, '\n')
+ .replace(/ /gi, ' ')
+ .replace(/"/gi, '"')
+ .replace(/<[^>]*>/gm, '')
+ ;
+
+ sText = Globals.$div.html(sText).text();
+
+ sText = sText
+ .replace(/\n[ \t]+/gm, '\n')
+ .replace(/[\n]{3,}/gm, '\n\n')
+ .replace(/>/gi, '>')
+ .replace(/</gi, '<')
+ .replace(/&/gi, '&')
+ ;
+
+ sText = Utils.splitPlainText(Utils.trim(sText));
+
+ iPos = 0;
+ iLimit = 800;
+
+ while (0 < iLimit)
+ {
+ iLimit--;
+ iP1 = sText.indexOf('__bq__start__', iPos);
+ if (-1 < iP1)
+ {
+ iP2 = sText.indexOf('__bq__start__', iP1 + 5);
+ iP3 = sText.indexOf('__bq__end__', iP1 + 5);
+
+ if ((-1 === iP2 || iP3 < iP2) && iP1 < iP3)
+ {
+ sText = sText.substring(0, iP1) +
+ convertBlockquote(sText.substring(iP1 + 13, iP3)) +
+ sText.substring(iP3 + 11);
+
+ iPos = 0;
+ }
+ else if (-1 < iP2 && iP2 < iP3)
+ {
+ iPos = iP2 - 1;
+ }
+ else
+ {
+ iPos = 0;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ sText = sText
+ .replace(/__bq__start__/gm, '')
+ .replace(/__bq__end__/gm, '')
+ ;
+
+ return sText;
+ };
+
+ /**
+ * @param {string} sPlain
+ * @param {boolean} bFindEmailAndLinks = false
+ * @return {string}
+ */
+ Utils.plainToHtml = function (sPlain, bFindEmailAndLinks)
+ {
+ sPlain = sPlain.toString().replace(/\r/g, '');
+
+ bFindEmailAndLinks = Utils.isUnd(bFindEmailAndLinks) ? false : !!bFindEmailAndLinks;
+
+ var
+ bIn = false,
+ bDo = true,
+ bStart = true,
+ aNextText = [],
+ sLine = '',
+ iIndex = 0,
+ aText = sPlain.split("\n")
+ ;
+
+ do
+ {
+ bDo = false;
+ aNextText = [];
+ for (iIndex = 0; iIndex < aText.length; iIndex++)
+ {
+ sLine = aText[iIndex];
+ bStart = '>' === sLine.substr(0, 1);
+ if (bStart && !bIn)
+ {
+ bDo = true;
+ bIn = true;
+ aNextText.push('~~~blockquote~~~');
+ aNextText.push(sLine.substr(1));
+ }
+ else if (!bStart && bIn)
+ {
+ if ('' !== sLine)
+ {
+ bIn = false;
+ aNextText.push('~~~/blockquote~~~');
+ aNextText.push(sLine);
+ }
+ else
+ {
+ aNextText.push(sLine);
+ }
+ }
+ else if (bStart && bIn)
+ {
+ aNextText.push(sLine.substr(1));
+ }
+ else
+ {
+ aNextText.push(sLine);
+ }
+ }
+
+ if (bIn)
+ {
+ bIn = false;
+ aNextText.push('~~~/blockquote~~~');
+ }
+
+ aText = aNextText;
+ }
+ while (bDo);
+
+ sPlain = aText.join("\n");
+
+ sPlain = sPlain
+ // .replace(/~~~\/blockquote~~~\n~~~blockquote~~~/g, '\n')
+ .replace(/&/g, '&')
+ .replace(/>/g, '>').replace(/')
+ .replace(/[\s]*~~~\/blockquote~~~/g, ' ')
+ .replace(/\u200C([\s\S]*)\u200C/g, '\u0002$1\u0002')
+ .replace(/\n/g, '
')
+ ;
+
+ return bFindEmailAndLinks ? Utils.findEmailAndLinks(sPlain) : sPlain;
+ };
+
+ window.rainloop_Utils_htmlToPlain = Utils.htmlToPlain;
+ window.rainloop_Utils_plainToHtml = Utils.plainToHtml;
+
+ /**
+ * @param {string} sHtml
+ * @return {string}
+ */
+ Utils.findEmailAndLinks = function (sHtml)
+ {
+ // return sHtml;
+ sHtml = Autolinker.link(sHtml, {
+ 'newWindow': true,
+ 'stripPrefix': false,
+ 'urls': true,
+ 'email': true,
+ 'twitter': false,
+ 'replaceFn': function (autolinker, match) {
+ return !(autolinker && match && 'url' === match.getType() && match.matchedText && 0 !== match.matchedText.indexOf('http'));
+ }
+ });
+
+ return sHtml;
+ };
+
+ /**
+ * @param {string} sUrl
+ * @param {number} iValue
+ * @param {Function} fCallback
+ */
+ Utils.resizeAndCrop = function (sUrl, iValue, fCallback)
+ {
+ var oTempImg = new window.Image();
+ oTempImg.onload = function() {
+
+ var
+ aDiff = [0, 0],
+ oCanvas = window.document.createElement('canvas'),
+ oCtx = oCanvas.getContext('2d')
+ ;
+
+ oCanvas.width = iValue;
+ oCanvas.height = iValue;
+
+ if (this.width > this.height)
+ {
+ aDiff = [this.width - this.height, 0];
+ }
+ else
+ {
+ aDiff = [0, this.height - this.width];
+ }
+
+ oCtx.fillStyle = '#fff';
+ oCtx.fillRect(0, 0, iValue, iValue);
+ oCtx.drawImage(this, aDiff[0] / 2, aDiff[1] / 2, this.width - aDiff[0], this.height - aDiff[1], 0, 0, iValue, iValue);
+
+ fCallback(oCanvas.toDataURL('image/jpeg'));
+ };
+
+ oTempImg.src = sUrl;
+ };
+
+ /**
+ * @param {Array} aSystem
+ * @param {Array} aList
+ * @param {Array=} aDisabled
+ * @param {Array=} aHeaderLines
+ * @param {?number=} iUnDeep
+ * @param {Function=} fDisableCallback
+ * @param {Function=} fVisibleCallback
+ * @param {Function=} fRenameCallback
+ * @param {boolean=} bSystem
+ * @param {boolean=} bBuildUnvisible
+ * @return {Array}
+ */
+ Utils.folderListOptionsBuilder = function (aSystem, aList, aDisabled, aHeaderLines,
+ iUnDeep, fDisableCallback, fVisibleCallback, fRenameCallback, bSystem, bBuildUnvisible)
+ {
+ var
+ /**
+ * @type {?FolderModel}
+ */
+ oItem = null,
+ bSep = false,
+ iIndex = 0,
+ iLen = 0,
+ sDeepPrefix = '\u00A0\u00A0\u00A0',
+ aResult = []
+ ;
+
+ bBuildUnvisible = Utils.isUnd(bBuildUnvisible) ? false : !!bBuildUnvisible;
+ bSystem = !Utils.isNormal(bSystem) ? 0 < aSystem.length : bSystem;
+ iUnDeep = !Utils.isNormal(iUnDeep) ? 0 : iUnDeep;
+ fDisableCallback = Utils.isNormal(fDisableCallback) ? fDisableCallback : null;
+ fVisibleCallback = Utils.isNormal(fVisibleCallback) ? fVisibleCallback : null;
+ fRenameCallback = Utils.isNormal(fRenameCallback) ? fRenameCallback : null;
+
+ if (!Utils.isArray(aDisabled))
+ {
+ aDisabled = [];
+ }
+
+ if (!Utils.isArray(aHeaderLines))
+ {
+ aHeaderLines = [];
+ }
+
+ for (iIndex = 0, iLen = aHeaderLines.length; iIndex < iLen; iIndex++)
+ {
+ aResult.push({
+ 'id': aHeaderLines[iIndex][0],
+ 'name': aHeaderLines[iIndex][1],
+ 'system': false,
+ 'seporator': false,
+ 'disabled': false
+ });
+ }
+
+ bSep = true;
+ for (iIndex = 0, iLen = aSystem.length; iIndex < iLen; iIndex++)
+ {
+ oItem = aSystem[iIndex];
+ if (fVisibleCallback ? fVisibleCallback.call(null, oItem) : true)
+ {
+ if (bSep && 0 < aResult.length)
+ {
+ aResult.push({
+ 'id': '---',
+ 'name': '---',
+ 'system': false,
+ 'seporator': true,
+ 'disabled': true
+ });
+ }
+
+ bSep = false;
+ aResult.push({
+ 'id': oItem.fullNameRaw,
+ 'name': fRenameCallback ? fRenameCallback.call(null, oItem) : oItem.name(),
+ 'system': true,
+ 'seporator': false,
+ 'disabled': !oItem.selectable || -1 < Utils.inArray(oItem.fullNameRaw, aDisabled) ||
+ (fDisableCallback ? fDisableCallback.call(null, oItem) : false)
+ });
+ }
+ }
+
+ bSep = true;
+ for (iIndex = 0, iLen = aList.length; iIndex < iLen; iIndex++)
+ {
+ oItem = aList[iIndex];
+ // if (oItem.subScribed() || !oItem.existen || bBuildUnvisible)
+ if ((oItem.subScribed() || !oItem.existen || bBuildUnvisible) && (oItem.selectable || oItem.hasSubScribedSubfolders()))
+ {
+ if (fVisibleCallback ? fVisibleCallback.call(null, oItem) : true)
+ {
+ if (Enums.FolderType.User === oItem.type() || !bSystem || oItem.hasSubScribedSubfolders())
+ {
+ if (bSep && 0 < aResult.length)
+ {
+ aResult.push({
+ 'id': '---',
+ 'name': '---',
+ 'system': false,
+ 'seporator': true,
+ 'disabled': true
+ });
+ }
+
+ bSep = false;
+ aResult.push({
+ 'id': oItem.fullNameRaw,
+ 'name': (new window.Array(oItem.deep + 1 - iUnDeep)).join(sDeepPrefix) +
+ (fRenameCallback ? fRenameCallback.call(null, oItem) : oItem.name()),
+ 'system': false,
+ 'seporator': false,
+ 'disabled': !oItem.selectable || -1 < Utils.inArray(oItem.fullNameRaw, aDisabled) ||
+ (fDisableCallback ? fDisableCallback.call(null, oItem) : false)
+ });
+ }
+ }
+ }
+
+ if (oItem.subScribed() && 0 < oItem.subFolders().length)
+ {
+ aResult = aResult.concat(Utils.folderListOptionsBuilder([], oItem.subFolders(), aDisabled, [],
+ iUnDeep, fDisableCallback, fVisibleCallback, fRenameCallback, bSystem, bBuildUnvisible));
+ }
+ }
+
+ return aResult;
+ };
+
+ Utils.computedPagenatorHelper = function (koCurrentPage, koPageCount)
+ {
+ return function() {
+
+ var
+ iPrev = 0,
+ iNext = 0,
+ iLimit = 2,
+ aResult = [],
+ iCurrentPage = koCurrentPage(),
+ iPageCount = koPageCount(),
+
+ /**
+ * @param {number} iIndex
+ * @param {boolean=} bPush = true
+ * @param {string=} sCustomName = ''
+ */
+ fAdd = function (iIndex, bPush, sCustomName) {
+
+ var oData = {
+ 'current': iIndex === iCurrentPage,
+ 'name': Utils.isUnd(sCustomName) ? iIndex.toString() : sCustomName.toString(),
+ 'custom': Utils.isUnd(sCustomName) ? false : true,
+ 'title': Utils.isUnd(sCustomName) ? '' : iIndex.toString(),
+ 'value': iIndex.toString()
+ };
+
+ if (Utils.isUnd(bPush) ? true : !!bPush)
+ {
+ aResult.push(oData);
+ }
+ else
+ {
+ aResult.unshift(oData);
+ }
+ }
+ ;
+
+ if (1 < iPageCount || (0 < iPageCount && iPageCount < iCurrentPage))
+ // if (0 < iPageCount && 0 < iCurrentPage)
+ {
+ if (iPageCount < iCurrentPage)
+ {
+ fAdd(iPageCount);
+ iPrev = iPageCount;
+ iNext = iPageCount;
+ }
+ else
+ {
+ if (3 >= iCurrentPage || iPageCount - 2 <= iCurrentPage)
+ {
+ iLimit += 2;
+ }
+
+ fAdd(iCurrentPage);
+ iPrev = iCurrentPage;
+ iNext = iCurrentPage;
+ }
+
+ while (0 < iLimit) {
+
+ iPrev -= 1;
+ iNext += 1;
+
+ if (0 < iPrev)
+ {
+ fAdd(iPrev, false);
+ iLimit--;
+ }
+
+ if (iPageCount >= iNext)
+ {
+ fAdd(iNext, true);
+ iLimit--;
+ }
+ else if (0 >= iPrev)
+ {
+ break;
+ }
+ }
+
+ if (3 === iPrev)
+ {
+ fAdd(2, false);
+ }
+ else if (3 < iPrev)
+ {
+ fAdd(window.Math.round((iPrev - 1) / 2), false, '...');
+ }
+
+ if (iPageCount - 2 === iNext)
+ {
+ fAdd(iPageCount - 1, true);
+ }
+ else if (iPageCount - 2 > iNext)
+ {
+ fAdd(window.Math.round((iPageCount + iNext) / 2), true, '...');
+ }
+
+ // first and last
+ if (1 < iPrev)
+ {
+ fAdd(1, false);
+ }
+
+ if (iPageCount > iNext)
+ {
+ fAdd(iPageCount, true);
+ }
+ }
+
+ return aResult;
+ };
+ };
+
+ Utils.selectElement = function (element)
+ {
+ var sel, range;
+ if (window.getSelection)
+ {
+ sel = window.getSelection();
+ sel.removeAllRanges();
+ range = window.document.createRange();
+ range.selectNodeContents(element);
+ sel.addRange(range);
+ }
+ else if (window.document.selection)
+ {
+ range = window.document.body.createTextRange();
+ range.moveToElementText(element);
+ range.select();
+ }
+ };
+
+ Utils.detectDropdownVisibility = _.debounce(function () {
+ Globals.dropdownVisibility(!!_.find(Globals.aBootstrapDropdowns, function (oItem) {
+ return oItem.hasClass('open');
+ }));
+ }, 50);
+
+ /**
+ * @param {boolean=} bDelay = false
+ */
+ Utils.triggerAutocompleteInputChange = function (bDelay) {
+
+ var fFunc = function () {
+ $('.checkAutocomplete').trigger('change');
+ };
+
+ if (Utils.isUnd(bDelay) ? false : !!bDelay)
+ {
+ _.delay(fFunc, 100);
+ }
+ else
+ {
+ fFunc();
+ }
+ };
+
+ /**
+ * @param {Object} oParams
+ */
+ Utils.setHeadViewport = function (oParams)
+ {
+ var aContent = [];
+ _.each(oParams, function (sKey, sValue) {
+ aContent.push('' + sKey + '=' + sValue);
+ });
+
+ $('#rl-head-viewport').attr('content', aContent.join(', '));
+ };
+
+ /**
+ * @param {string} sFileName
+ * @return {string}
+ */
+ Utils.getFileExtension = function (sFileName)
+ {
+ sFileName = Utils.trim(sFileName).toLowerCase();
+
+ var sResult = sFileName.split('.').pop();
+ return (sResult === sFileName) ? '' : sResult;
+ };
+
+ Utils.configurationScriptTagCache = {};
+
+ /**
+ * @param {string} sConfiguration
+ * @return {object}
+ */
+ Utils.getConfigurationFromScriptTag = function (sConfiguration)
+ {
+ var oResult = {};
+
+ if (!Utils.configurationScriptTagCache[sConfiguration])
+ {
+ Utils.configurationScriptTagCache[sConfiguration] = $('script[type="application/json"][data-configuration="' + sConfiguration + '"]');
+ }
+
+ try {
+ oResult = JSON.parse(Utils.configurationScriptTagCache[sConfiguration].text());
+ } catch (e) {/* eslint-disable-line no-empty */}
+
+ return oResult;
+ };
+
+ /**
+ * @param {string} sFileName
+ * @return {string}
+ */
+ Utils.mimeContentType = function (sFileName)
+ {
+ var
+ sExt = '',
+ sResult = 'application/octet-stream'
+ ;
+
+ sFileName = Utils.trim(sFileName).toLowerCase();
+
+ if ('winmail.dat' === sFileName)
+ {
+ return 'application/ms-tnef';
+ }
+
+ sExt = Utils.getFileExtension(sFileName);
+ if (sExt && 0 < sExt.length && !Utils.isUnd(Mime[sExt]))
+ {
+ sResult = Mime[sExt];
+ }
+
+ return sResult;
+ };
+
+ /**
+ * @param {mixed} mPropOrValue
+ * @param {mixed} mValue
+ */
+ Utils.disposeOne = function (mPropOrValue, mValue)
+ {
+ var mDisposable = mValue || mPropOrValue;
+ if (mDisposable && typeof mDisposable.dispose === 'function')
+ {
+ mDisposable.dispose();
+ }
+ };
+
+ /**
+ * @param {Object} oObject
+ */
+ Utils.disposeObject = function (oObject)
+ {
+ if (oObject)
+ {
+ if (Utils.isArray(oObject.disposables))
+ {
+ _.each(oObject.disposables, Utils.disposeOne);
+ }
+
+ ko.utils.objectForEach(oObject, Utils.disposeOne);
+ }
+ };
+
+ /**
+ * @param {Object|Array} mObjectOrObjects
+ */
+ Utils.delegateRunOnDestroy = function (mObjectOrObjects)
+ {
+ if (mObjectOrObjects)
+ {
+ if (Utils.isArray(mObjectOrObjects))
+ {
+ _.each(mObjectOrObjects, function (oItem) {
+ Utils.delegateRunOnDestroy(oItem);
+ });
+ }
+ else if (mObjectOrObjects && mObjectOrObjects.onDestroy)
+ {
+ mObjectOrObjects.onDestroy();
+ }
+ }
+ };
+
+ Utils.__themeTimer = 0;
+ Utils.__themeAjax = null;
+
+ Utils.changeTheme = function (sValue, themeTrigger)
+ {
+ var
+ oThemeLink = $('#rlThemeLink'),
+ oThemeStyle = $('#rlThemeStyle'),
+ sUrl = oThemeLink.attr('href')
+ ;
+
+ if (!sUrl)
+ {
+ sUrl = oThemeStyle.attr('data-href');
+ }
+
+ if (sUrl)
+ {
+ sUrl = sUrl.toString().replace(/\/-\/[^\/]+\/\-\//, '/-/' + sValue + '/-/');
+ sUrl = sUrl.toString().replace(/\/Css\/[^\/]+\/User\//, '/Css/0/User/');
+ sUrl = sUrl.toString().replace(/\/Hash\/[^\/]+\//, '/Hash/-/');
+
+ if ('Json/' !== sUrl.substring(sUrl.length - 5, sUrl.length))
+ {
+ sUrl += 'Json/';
+ }
+
+ window.clearTimeout(Utils.__themeTimer);
+ themeTrigger(Enums.SaveSettingsStep.Animate);
+
+ if (Utils.__themeAjax && Utils.__themeAjax.abort)
+ {
+ Utils.__themeAjax.abort();
+ }
+
+ Utils.__themeAjax = $.ajax({
+ 'url': sUrl,
+ 'dataType': 'json'
+ }).done(function(aData) {
+
+ if (aData && Utils.isArray(aData) && 2 === aData.length)
+ {
+ if (oThemeLink && oThemeLink[0] && (!oThemeStyle || !oThemeStyle[0]))
+ {
+ oThemeStyle = $('');
+ oThemeLink.after(oThemeStyle);
+ oThemeLink.remove();
+ }
+
+ if (oThemeStyle && oThemeStyle[0])
+ {
+ oThemeStyle.attr('data-href', sUrl).attr('data-theme', aData[0]);
+ if (oThemeStyle[0].styleSheet && !Utils.isUnd(oThemeStyle[0].styleSheet.cssText))
+ {
+ oThemeStyle[0].styleSheet.cssText = aData[1];
+ }
+ else
+ {
+ oThemeStyle.text(aData[1]);
+ }
+ }
+
+ themeTrigger(Enums.SaveSettingsStep.TrueResult);
+ }
+
+ }).always(function() {
+
+ Utils.__themeTimer = window.setTimeout(function () {
+ themeTrigger(Enums.SaveSettingsStep.Idle);
+ }, 1000);
+
+ Utils.__themeAjax = null;
+ });
+ }
+ };
+
+ Utils.substr = window.String.substr;
+ if ('ab'.substr(-1) !== 'b')
+ {
+ Utils.substr = function(sStr, iStart, iLength)
+ {
+ if (iStart < 0)
+ {
+ iStart = sStr.length + iStart;
+ }
+
+ return sStr.substr(iStart, iLength);
+ };
+ }
+
+ module.exports = Utils;
+
+ }());
+
+/***/ },
+/* 2 */
+/*!****************************!*\
+ !*** ./dev/External/ko.js ***!
+ \****************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function (ko) {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ JSON = __webpack_require__(/*! JSON */ 36),
+ Opentip = __webpack_require__(/*! Opentip */ 54),
+
+ fDisposalTooltipHelper = function (oElement) {
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ if (oElement && oElement.__opentip)
+ {
+ oElement.__opentip.deactivate();
+ }
+ });
+ }
+ ;
+
+ ko.bindingHandlers.updateWidth = {
+ 'init': function (oElement, fValueAccessor) {
+ var
+ $w = $(window),
+ $oEl = $(oElement),
+ fValue = fValueAccessor(),
+ fInit = function(){
+ fValue($oEl.width());
+ window.setTimeout(function(){
+ fValue($oEl.width());
+ }, 500);
+ }
+ ;
+
+ $w.on('resize', fInit);
+ fInit();
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $w.off('resize', fInit);
+ });
+ }
+ };
+
+ ko.bindingHandlers.editor = {
+ 'init': function (oElement, fValueAccessor) {
+
+ var
+ oEditor = null,
+ fValue = fValueAccessor(),
+
+ fUpdateEditorValue = function () {
+ if (fValue && fValue.__editor)
+ {
+ fValue.__editor.setHtmlOrPlain(fValue());
+ }
+ },
+
+ fUpdateKoValue = function () {
+ if (fValue && fValue.__editor)
+ {
+ fValue(fValue.__editor.getDataWithHtmlMark());
+ }
+ },
+
+ fOnReady = function () {
+ fValue.__editor = oEditor;
+ fUpdateEditorValue();
+ },
+
+ HtmlEditor = __webpack_require__(/*! Common/HtmlEditor */ 45)
+ ;
+
+ if (ko.isObservable(fValue) && HtmlEditor)
+ {
+ oEditor = new HtmlEditor(oElement, fUpdateKoValue, fOnReady, fUpdateKoValue);
+
+ fValue.__fetchEditorValue = fUpdateKoValue;
+
+ fValue.subscribe(fUpdateEditorValue);
+
+ // ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ // });
+ }
+ }
+ };
+
+ ko.bindingHandlers.json = {
+ 'init': function (oElement, fValueAccessor) {
+ $(oElement).text(JSON.stringify(ko.unwrap(fValueAccessor())));
+ },
+ 'update': function (oElement, fValueAccessor) {
+ $(oElement).text(JSON.stringify(ko.unwrap(fValueAccessor())));
+ }
+ };
+
+ ko.bindingHandlers.scrollerShadows = {
+ 'init': function (oElement) {
+
+ var
+ iLimit = 8,
+ $oEl = $(oElement),
+ $win = $(window),
+ oCont = $oEl.find('[data-scroller-shadows-content]')[0] || null,
+ fFunc = _.throttle(function () {
+ $oEl
+ .toggleClass('scroller-shadow-top', iLimit < oCont.scrollTop)
+ .toggleClass('scroller-shadow-bottom', oCont.scrollTop + iLimit < oCont.scrollHeight - oCont.clientHeight)
+ ;
+ }, 100)
+ ;
+
+ if (oCont)
+ {
+ $(oCont).on('scroll resize', fFunc);
+ $win.on('resize', fFunc);
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oCont, function () {
+ $(oCont).off();
+ $win.off('resize', fFunc);
+ });
+ }
+ }
+ };
+
+ ko.bindingHandlers.tooltip = {
+ 'init': function (oElement, fValueAccessor) {
+
+ var
+ bi18n = true,
+ sValue = '',
+ Translator = null,
+ $oEl = $(oElement),
+ fValue = fValueAccessor(),
+ bMobile = 'on' === ($oEl.data('tooltip-mobile') || 'off'),
+ Globals = __webpack_require__(/*! Common/Globals */ 8)
+ ;
+
+ if (!Globals.bMobileDevice || bMobile)
+ {
+ bi18n = 'on' === ($oEl.data('tooltip-i18n') || 'on');
+ sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue);
+
+ oElement.__opentip = new Opentip(oElement, {
+ 'style': 'rainloopTip',
+ 'element': oElement,
+ 'tipJoint': $oEl.data('tooltip-join') || 'bottom'
+ });
+
+ Globals.dropdownVisibility.subscribe(function (bV) {
+ if (bV) {
+ oElement.__opentip.hide();
+ }
+ });
+
+ if ('' === sValue)
+ {
+ oElement.__opentip.hide();
+ oElement.__opentip.deactivate();
+ oElement.__opentip.setContent('');
+ }
+ else
+ {
+ oElement.__opentip.activate();
+ }
+
+ if (bi18n)
+ {
+ Translator = __webpack_require__(/*! Common/Translator */ 6);
+
+ oElement.__opentip.setContent(Translator.i18n(sValue));
+
+ Translator.trigger.subscribe(function () {
+ oElement.__opentip.setContent(Translator.i18n(sValue));
+ });
+
+ Globals.dropdownVisibility.subscribe(function () {
+ if (oElement && oElement.__opentip)
+ {
+ oElement.__opentip.setContent(__webpack_require__(/*! Common/Translator */ 6).i18n(sValue));
+ }
+ });
+ }
+ else
+ {
+ oElement.__opentip.setContent(sValue);
+ }
+ }
+ },
+ 'update': function (oElement, fValueAccessor) {
+
+ var
+ bi18n = true,
+ sValue = '',
+ $oEl = $(oElement),
+ fValue = fValueAccessor(),
+ bMobile = 'on' === ($oEl.data('tooltip-mobile') || 'off'),
+ Globals = __webpack_require__(/*! Common/Globals */ 8)
+ ;
+
+ if ((!Globals.bMobileDevice || bMobile) && oElement.__opentip)
+ {
+ bi18n = 'on' === ($oEl.data('tooltip-i18n') || 'on');
+ sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue);
+
+ if (sValue)
+ {
+ oElement.__opentip.setContent(
+ bi18n ? __webpack_require__(/*! Common/Translator */ 6).i18n(sValue) : sValue);
+ oElement.__opentip.activate();
+ }
+ else
+ {
+ oElement.__opentip.hide();
+ oElement.__opentip.deactivate();
+ oElement.__opentip.setContent('');
+ }
+ }
+ }
+ };
+
+ ko.bindingHandlers.tooltipErrorTip = {
+ 'init': function (oElement) {
+
+ var $oEl = $(oElement);
+
+ oElement.__opentip = new Opentip(oElement, {
+ 'style': 'rainloopErrorTip',
+ 'hideOn': 'mouseout click',
+ 'element': oElement,
+ 'tipJoint': $oEl.data('tooltip-join') || 'top'
+ });
+
+ oElement.__opentip.deactivate();
+
+ $(window.document).on('click', function () {
+ if (oElement && oElement.__opentip)
+ {
+ oElement.__opentip.hide();
+ }
+ });
+
+ fDisposalTooltipHelper(oElement);
+ },
+ 'update': function (oElement, fValueAccessor) {
+
+ var
+ $oEl = $(oElement),
+ fValue = fValueAccessor(),
+ sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue),
+ oOpenTips = oElement.__opentip
+ ;
+
+ if (oOpenTips)
+ {
+ if ('' === sValue)
+ {
+ oOpenTips.hide();
+ oOpenTips.deactivate();
+ oOpenTips.setContent('');
+ }
+ else
+ {
+ _.delay(function () {
+ if ($oEl.is(':visible'))
+ {
+ oOpenTips.setContent(sValue);
+ oOpenTips.activate();
+ oOpenTips.show();
+ }
+ else
+ {
+ oOpenTips.hide();
+ oOpenTips.deactivate();
+ oOpenTips.setContent('');
+ }
+ }, 100);
+ }
+ }
+ }
+ };
+
+ ko.bindingHandlers.registrateBootstrapDropdown = {
+ 'init': function (oElement) {
+ var Globals = __webpack_require__(/*! Common/Globals */ 8);
+ if (Globals && Globals.aBootstrapDropdowns)
+ {
+ Globals.aBootstrapDropdowns.push($(oElement));
+
+ $(oElement).click(function () {
+ __webpack_require__(/*! Common/Utils */ 1).detectDropdownVisibility();
+ });
+
+ // ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ // });
+ }
+ }
+ };
+
+ ko.bindingHandlers.openDropdownTrigger = {
+ 'update': function (oElement, fValueAccessor) {
+ if (ko.unwrap(fValueAccessor()))
+ {
+ var $oEl = $(oElement);
+ if (!$oEl.hasClass('open'))
+ {
+ $oEl.find('.dropdown-toggle').dropdown('toggle');
+ }
+
+ $oEl.find('.dropdown-toggle').focus();
+
+ __webpack_require__(/*! Common/Utils */ 1).detectDropdownVisibility();
+ fValueAccessor()(false);
+ }
+ }
+ };
+
+ ko.bindingHandlers.dropdownCloser = {
+ 'init': function (oElement) {
+ $(oElement).closest('.dropdown').on('click', '.e-item', function () {
+ $(oElement).dropdown('toggle');
+ });
+ }
+ };
+
+ ko.bindingHandlers.popover = {
+ 'init': function (oElement, fValueAccessor) {
+ $(oElement).popover(ko.unwrap(fValueAccessor()));
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement).popover('destroy');
+ });
+ }
+ };
+
+ ko.bindingHandlers.csstext = {
+ 'init': function (oElement, fValueAccessor) {
+ if (oElement && oElement.styleSheet && undefined !== oElement.styleSheet.cssText)
+ {
+ oElement.styleSheet.cssText = ko.unwrap(fValueAccessor());
+ }
+ else
+ {
+ $(oElement).text(ko.unwrap(fValueAccessor()));
+ }
+ },
+ 'update': function (oElement, fValueAccessor) {
+ if (oElement && oElement.styleSheet && undefined !== oElement.styleSheet.cssText)
+ {
+ oElement.styleSheet.cssText = ko.unwrap(fValueAccessor());
+ }
+ else
+ {
+ $(oElement).text(ko.unwrap(fValueAccessor()));
+ }
+ }
+ };
+
+ ko.bindingHandlers.resizecrop = {
+ 'init': function (oElement) {
+ $(oElement).addClass('resizecrop').resizecrop({
+ 'width': '100',
+ 'height': '100',
+ 'wrapperCSS': {
+ 'border-radius': '10px'
+ }
+ });
+ },
+ 'update': function (oElement, fValueAccessor) {
+ fValueAccessor()();
+ $(oElement).resizecrop({
+ 'width': '100',
+ 'height': '100'
+ });
+ }
+ };
+
+ ko.bindingHandlers.onEnter = {
+ 'init': function (oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) {
+ $(oElement).on('keypress.koOnEnter', function (oEvent) {
+ if (oEvent && 13 === window.parseInt(oEvent.keyCode, 10))
+ {
+ $(oElement).trigger('change');
+ fValueAccessor().call(oViewModel);
+ }
+ });
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement).off('keypress.koOnEnter');
+ });
+ }
+ };
+
+ ko.bindingHandlers.onSpace = {
+ 'init': function (oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) {
+ $(oElement).on('keyup.koOnSpace', function (oEvent) {
+ if (oEvent && 32 === window.parseInt(oEvent.keyCode, 10))
+ {
+ fValueAccessor().call(oViewModel, oEvent);
+ }
+ });
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement).off('keyup.koOnSpace');
+ });
+ }
+ };
+
+ ko.bindingHandlers.onTab = {
+ 'init': function (oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) {
+ $(oElement).on('keydown.koOnTab', function (oEvent) {
+ if (oEvent && 9 === window.parseInt(oEvent.keyCode, 10))
+ {
+ return fValueAccessor().call(oViewModel, !!oEvent.shiftKey);
+ }
+ });
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement).off('keydown.koOnTab');
+ });
+ }
+ };
+
+ ko.bindingHandlers.onEsc = {
+ 'init': function (oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) {
+ $(oElement).on('keypress.koOnEsc', function (oEvent) {
+ if (oEvent && 27 === window.parseInt(oEvent.keyCode, 10))
+ {
+ $(oElement).trigger('change');
+ fValueAccessor().call(oViewModel);
+ }
+ });
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement).off('keypress.koOnEsc');
+ });
+ }
+ };
+
+ ko.bindingHandlers.clickOnTrue = {
+ 'update': function (oElement, fValueAccessor) {
+ if (ko.unwrap(fValueAccessor()))
+ {
+ $(oElement).click();
+ }
+ }
+ };
+
+ ko.bindingHandlers.modal = {
+ 'init': function (oElement, fValueAccessor) {
+
+ var
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1)
+ ;
+
+ $(oElement).toggleClass('fade', !Globals.bMobileDevice).modal({
+ 'keyboard': false,
+ 'show': ko.unwrap(fValueAccessor())
+ })
+ .on('shown.koModal', Utils.windowResizeCallback)
+ .find('.close').on('click.koModal', function () {
+ fValueAccessor()(false);
+ });
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement)
+ .off('shown.koModal')
+ .find('.close')
+ .off('click.koModal')
+ ;
+ });
+ },
+ 'update': function (oElement, fValueAccessor) {
+
+ var Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ $(oElement).modal(!!ko.unwrap(fValueAccessor()) ? 'show' : 'hide');
+
+ if (Globals.$html.hasClass('rl-anim'))
+ {
+ Globals.$html.addClass('rl-modal-animation');
+ _.delay(function () {
+ Globals.$html.removeClass('rl-modal-animation');
+ }, 400);
+ }
+
+ }
+ };
+
+ ko.bindingHandlers.moment = {
+ 'init': function (oElement, fValueAccessor) {
+ __webpack_require__(/*! Common/Momentor */ 26).momentToNode(
+ $(oElement).addClass('moment').data('moment-time', ko.unwrap(fValueAccessor()))
+ );
+ },
+ 'update': function (oElement, fValueAccessor) {
+ __webpack_require__(/*! Common/Momentor */ 26).momentToNode(
+ $(oElement).data('moment-time', ko.unwrap(fValueAccessor()))
+ );
+ }
+ };
+
+ ko.bindingHandlers.i18nInit = {
+ 'init': function (oElement) {
+ __webpack_require__(/*! Common/Translator */ 6).i18nToNodes(oElement);
+ }
+ };
+
+ ko.bindingHandlers.translatorInit = {
+ 'init': function (oElement) {
+ __webpack_require__(/*! Common/Translator */ 6).i18nToNodes(oElement);
+ }
+ };
+
+ ko.bindingHandlers.i18nUpdate = {
+ 'update': function (oElement, fValueAccessor) {
+ ko.unwrap(fValueAccessor());
+ __webpack_require__(/*! Common/Translator */ 6).i18nToNodes(oElement);
+ }
+ };
+
+ ko.bindingHandlers.link = {
+ 'update': function (oElement, fValueAccessor) {
+ $(oElement).attr('href', ko.unwrap(fValueAccessor()));
+ }
+ };
+
+ ko.bindingHandlers.title = {
+ 'update': function (oElement, fValueAccessor) {
+ $(oElement).attr('title', ko.unwrap(fValueAccessor()));
+ }
+ };
+
+ ko.bindingHandlers.textF = {
+ 'init': function (oElement, fValueAccessor) {
+ $(oElement).text(ko.unwrap(fValueAccessor()));
+ }
+ };
+
+ ko.bindingHandlers.initDom = {
+ 'init': function (oElement, fValueAccessor) {
+ fValueAccessor()(oElement);
+ }
+ };
+
+ ko.bindingHandlers.initFixedTrigger = {
+ 'init': function (oElement, fValueAccessor) {
+ var
+ aValues = ko.unwrap(fValueAccessor()),
+ $oContainer = null,
+ $oElement = $(oElement),
+ oOffset = null,
+
+ iTop = aValues[1] || 0
+ ;
+
+ $oContainer = $(aValues[0] || null);
+ $oContainer = $oContainer[0] ? $oContainer : null;
+
+ if ($oContainer)
+ {
+ $(window).resize(function () {
+ oOffset = $oContainer.offset();
+ if (oOffset && oOffset.top)
+ {
+ $oElement.css('top', oOffset.top + iTop);
+ }
+ });
+ }
+ }
+ };
+
+ ko.bindingHandlers.initResizeTrigger = {
+ 'init': function (oElement, fValueAccessor) {
+ var aValues = ko.unwrap(fValueAccessor());
+ $(oElement).css({
+ 'height': aValues[1],
+ 'min-height': aValues[1]
+ });
+ },
+ 'update': function (oElement, fValueAccessor) {
+
+ var
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ aValues = ko.unwrap(fValueAccessor()),
+ iValue = Utils.pInt(aValues[1]),
+ iSize = 0,
+ iOffset = $(oElement).offset().top
+ ;
+
+ if (0 < iOffset)
+ {
+ iOffset += Utils.pInt(aValues[2]);
+ iSize = Globals.$win.height() - iOffset;
+
+ if (iValue < iSize)
+ {
+ iValue = iSize;
+ }
+
+ $(oElement).css({
+ 'height': iValue,
+ 'min-height': iValue
+ });
+ }
+ }
+ };
+
+ ko.bindingHandlers.appendDom = {
+ 'update': function (oElement, fValueAccessor) {
+ $(oElement).hide().empty().append(ko.unwrap(fValueAccessor())).show();
+ }
+ };
+
+ ko.bindingHandlers.draggable = {
+ 'init': function (oElement, fValueAccessor, fAllBindingsAccessor) {
+
+ var
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1)
+ ;
+
+ if (!Globals.bMobileDevice)
+ {
+ var
+ iTriggerZone = 100,
+ iScrollSpeed = 3,
+ fAllValueFunc = fAllBindingsAccessor(),
+ sDroppableSelector = fAllValueFunc && fAllValueFunc['droppableSelector'] ? fAllValueFunc['droppableSelector'] : '',
+ oConf = {
+ 'distance': 20,
+ 'handle': '.dragHandle',
+ 'cursorAt': {'top': 22, 'left': 3},
+ 'refreshPositions': true,
+ 'scroll': true
+ }
+ ;
+
+ if (sDroppableSelector)
+ {
+ oConf['drag'] = function (oEvent) {
+
+ $(sDroppableSelector).each(function () {
+ var
+ moveUp = null,
+ moveDown = null,
+ $this = $(this),
+ oOffset = $this.offset(),
+ bottomPos = oOffset.top + $this.height()
+ ;
+
+ window.clearInterval($this.data('timerScroll'));
+ $this.data('timerScroll', false);
+
+ if (oEvent.pageX >= oOffset.left && oEvent.pageX <= oOffset.left + $this.width())
+ {
+ if (oEvent.pageY >= bottomPos - iTriggerZone && oEvent.pageY <= bottomPos)
+ {
+ moveUp = function() {
+ $this.scrollTop($this.scrollTop() + iScrollSpeed);
+ Utils.windowResize();
+ };
+
+ $this.data('timerScroll', window.setInterval(moveUp, 10));
+ moveUp();
+ }
+
+ if (oEvent.pageY >= oOffset.top && oEvent.pageY <= oOffset.top + iTriggerZone)
+ {
+ moveDown = function() {
+ $this.scrollTop($this.scrollTop() - iScrollSpeed);
+ Utils.windowResize();
+ };
+
+ $this.data('timerScroll', window.setInterval(moveDown, 10));
+ moveDown();
+ }
+ }
+ });
+ };
+
+ oConf['stop'] = function() {
+ $(sDroppableSelector).each(function () {
+ window.clearInterval($(this).data('timerScroll'));
+ $(this).data('timerScroll', false);
+ });
+ };
+ }
+
+ oConf['helper'] = function (oEvent) {
+ return fValueAccessor()(oEvent && oEvent.target ? ko.dataFor(oEvent.target) : null);
+ };
+
+ $(oElement).draggable(oConf).on('mousedown.koDraggable', function () {
+ Utils.removeInFocus();
+ });
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement)
+ .off('mousedown.koDraggable')
+ .draggable('destroy')
+ ;
+ });
+ }
+ }
+ };
+
+ ko.bindingHandlers.droppable = {
+ 'init': function (oElement, fValueAccessor, fAllBindingsAccessor) {
+ var Globals = __webpack_require__(/*! Common/Globals */ 8);
+ if (!Globals.bMobileDevice)
+ {
+ var
+ fValueFunc = fValueAccessor(),
+ fAllValueFunc = fAllBindingsAccessor(),
+ fOverCallback = fAllValueFunc && fAllValueFunc['droppableOver'] ? fAllValueFunc['droppableOver'] : null,
+ fOutCallback = fAllValueFunc && fAllValueFunc['droppableOut'] ? fAllValueFunc['droppableOut'] : null,
+ oConf = {
+ 'tolerance': 'pointer',
+ 'hoverClass': 'droppableHover'
+ }
+ ;
+
+ if (fValueFunc)
+ {
+ oConf['drop'] = function (oEvent, oUi) {
+ fValueFunc(oEvent, oUi);
+ };
+
+ if (fOverCallback)
+ {
+ oConf['over'] = function (oEvent, oUi) {
+ fOverCallback(oEvent, oUi);
+ };
+ }
+
+ if (fOutCallback)
+ {
+ oConf['out'] = function (oEvent, oUi) {
+ fOutCallback(oEvent, oUi);
+ };
+ }
+
+ $(oElement).droppable(oConf);
+
+ ko.utils.domNodeDisposal.addDisposeCallback(oElement, function () {
+ $(oElement).droppable('destroy');
+ });
+ }
+ }
+ }
+ };
+
+ ko.bindingHandlers.nano = {
+ 'init': function (oElement) {
+ var Globals = __webpack_require__(/*! Common/Globals */ 8);
+ if (!Globals.bDisableNanoScroll)
+ {
+ $(oElement)
+ .addClass('nano')
+ .nanoScroller({
+ 'iOSNativeScrolling': false,
+ 'preventPageScrolling': true
+ })
+ ;
+ }
+ }
+ };
+
+ ko.bindingHandlers.saveTrigger = {
+ 'init': function (oElement) {
+
+ var $oEl = $(oElement);
+
+ $oEl.data('save-trigger-type', $oEl.is('input[type=text],input[type=email],input[type=password],select,textarea') ? 'input' : 'custom');
+
+ if ('custom' === $oEl.data('save-trigger-type'))
+ {
+ $oEl.append(
+ '
'
+ ).addClass('settings-saved-trigger');
+ }
+ else
+ {
+ $oEl.addClass('settings-saved-trigger-input');
+ }
+ },
+ 'update': function (oElement, fValueAccessor) {
+ var
+ mValue = ko.unwrap(fValueAccessor()),
+ $oEl = $(oElement)
+ ;
+
+ if ('custom' === $oEl.data('save-trigger-type'))
+ {
+ switch (mValue.toString())
+ {
+ case '1':
+ $oEl
+ .find('.animated,.error').hide().removeClass('visible')
+ .end()
+ .find('.success').show().addClass('visible')
+ ;
+ break;
+ case '0':
+ $oEl
+ .find('.animated,.success').hide().removeClass('visible')
+ .end()
+ .find('.error').show().addClass('visible')
+ ;
+ break;
+ case '-2':
+ $oEl
+ .find('.error,.success').hide().removeClass('visible')
+ .end()
+ .find('.animated').show().addClass('visible')
+ ;
+ break;
+ default:
+ $oEl
+ .find('.animated').hide()
+ .end()
+ .find('.error,.success').removeClass('visible')
+ ;
+ break;
+ }
+ }
+ else
+ {
+ switch (mValue.toString())
+ {
+ case '1':
+ $oEl.addClass('success').removeClass('error');
+ break;
+ case '0':
+ $oEl.addClass('error').removeClass('success');
+ break;
+ case '-2':
+ // $oEl;
+ break;
+ default:
+ $oEl.removeClass('error success');
+ break;
+ }
+ }
+ }
+ };
+
+ ko.bindingHandlers.emailsTags = {
+ 'init': function(oElement, fValueAccessor, fAllBindingsAccessor) {
+
+ var
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ EmailModel = __webpack_require__(/*! Model/Email */ 30),
+
+ $oEl = $(oElement),
+ fValue = fValueAccessor(),
+ fAllBindings = fAllBindingsAccessor(),
+ fAutoCompleteSource = fAllBindings['autoCompleteSource'] || null,
+ fFocusCallback = function (bValue) {
+ if (fValue && fValue.focused)
+ {
+ fValue.focused(!!bValue);
+ }
+ }
+ ;
+
+ $oEl.inputosaurus({
+ 'parseOnBlur': true,
+ 'allowDragAndDrop': true,
+ 'focusCallback': fFocusCallback,
+ 'inputDelimiters': [',', ';', "\n"],
+ 'autoCompleteSource': fAutoCompleteSource,
+ // 'elementHook': function (oEl, oItem) {
+ // if (oEl && oItem)
+ // {
+ // oEl.addClass('pgp');
+ // window.console.log(arguments);
+ // }
+ // },
+ 'parseHook': function (aInput) {
+
+ return _.map(aInput, function (sInputValue) {
+
+ var
+ sValue = Utils.trim(sInputValue),
+ oEmail = null
+ ;
+
+ if ('' !== sValue)
+ {
+ oEmail = new EmailModel();
+ oEmail.mailsoParse(sValue);
+ return [oEmail.toLine(false), oEmail];
+ }
+
+ return [sValue, null];
+
+ });
+
+ // var aResult = [];
+ //
+ // _.each(aInput, function (sInputValue) {
+ //
+ // var
+ // aM = null,
+ // aValues = [],
+ // sValue = Utils.trim(sInputValue),
+ // oEmail = null
+ // ;
+ //
+ // if ('' !== sValue)
+ // {
+ // aM = sValue.match(/[@]/g);
+ // if (aM && 0 < aM.length)
+ // {
+ // sValue = sValue.replace(/[\r\n]+/g, '; ').replace(/[\s]+/g, ' ');
+ // aValues = EmailModel.splitHelper(sValue, ';');
+ //
+ // _.each(aValues, function (sV) {
+ //
+ // oEmail = new EmailModel();
+ // oEmail.mailsoParse(sV);
+ //
+ // if (oEmail.email)
+ // {
+ // aResult.push([oEmail.toLine(false), oEmail]);
+ // }
+ // else
+ // {
+ // aResult.push(['', null]);
+ // }
+ // });
+ // }
+ // else
+ // {
+ // aResult.push([sInputValue, null]);
+ // }
+ // }
+ // else
+ // {
+ // aResult.push([sInputValue, null]);
+ // }
+ // });
+ //
+ // return aResult;
+ },
+ 'change': _.bind(function (oEvent) {
+ $oEl.data('EmailsTagsValue', oEvent.target.value);
+ fValue(oEvent.target.value);
+ }, this)
+ });
+
+ if (fValue && fValue.focused && fValue.focused.subscribe)
+ {
+ fValue.focused.subscribe(function (bValue) {
+ $oEl.inputosaurus(!!bValue ? 'focus' : 'blur');
+ });
+ }
+ },
+ 'update': function (oElement, fValueAccessor) {
+
+ var
+ $oEl = $(oElement),
+ fValue = fValueAccessor(),
+ sValue = ko.unwrap(fValue)
+ ;
+
+ if ($oEl.data('EmailsTagsValue') !== sValue)
+ {
+ $oEl.val(sValue);
+ $oEl.data('EmailsTagsValue', sValue);
+ $oEl.inputosaurus('refresh');
+ }
+ }
+ };
+
+ ko.bindingHandlers.command = {
+ 'init': function (oElement, fValueAccessor, fAllBindingsAccessor, oViewModel) {
+ var
+ jqElement = $(oElement),
+ oCommand = fValueAccessor()
+ ;
+
+ if (!oCommand || !oCommand.enabled || !oCommand.canExecute)
+ {
+ throw new Error('You are not using command function');
+ }
+
+ jqElement.addClass('command');
+ ko.bindingHandlers[jqElement.is('form') ? 'submit' : 'click'].init.apply(oViewModel, arguments);
+ },
+
+ 'update': function (oElement, fValueAccessor) {
+
+ var
+ bResult = true,
+ jqElement = $(oElement),
+ oCommand = fValueAccessor()
+ ;
+
+ bResult = oCommand.enabled();
+ jqElement.toggleClass('command-not-enabled', !bResult);
+
+ if (bResult)
+ {
+ bResult = oCommand.canExecute();
+ jqElement.toggleClass('command-can-not-be-execute', !bResult);
+ }
+
+ jqElement.toggleClass('command-disabled disable disabled', !bResult).toggleClass('no-disabled', !!bResult);
+
+ if (jqElement.is('input') || jqElement.is('button'))
+ {
+ jqElement.prop('disabled', !bResult);
+ }
+ }
+ };
+
+ // extenders
+
+ ko.extenders.trimmer = function (oTarget)
+ {
+ var
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ oResult = ko.computed({
+ 'read': oTarget,
+ 'write': function (sNewValue) {
+ oTarget(Utils.trim(sNewValue.toString()));
+ },
+ 'owner': this
+ })
+ ;
+
+ oResult(oTarget());
+ return oResult;
+ };
+
+ ko.extenders.posInterer = function (oTarget, iDefault)
+ {
+ var
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ oResult = ko.computed({
+ 'read': oTarget,
+ 'write': function (sNewValue) {
+ var iNew = Utils.pInt(sNewValue.toString(), iDefault);
+ if (0 >= iNew)
+ {
+ iNew = iDefault;
+ }
+
+ if (iNew === oTarget() && '' + iNew !== '' + sNewValue)
+ {
+ oTarget(iNew + 1);
+ }
+
+ oTarget(iNew);
+ }
+ })
+ ;
+
+ oResult(oTarget());
+ return oResult;
+ };
+
+ ko.extenders.limitedList = function (oTarget, mList)
+ {
+ var
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ oResult = ko.computed({
+ 'read': oTarget,
+ 'write': function (sNewValue) {
+
+ var
+ sCurrentValue = ko.unwrap(oTarget),
+ aList = ko.unwrap(mList)
+ ;
+
+ if (Utils.isNonEmptyArray(aList))
+ {
+ if (-1 < Utils.inArray(sNewValue, aList))
+ {
+ oTarget(sNewValue);
+ }
+ else if (-1 < Utils.inArray(sCurrentValue, aList))
+ {
+ oTarget(sCurrentValue + ' ');
+ oTarget(sCurrentValue);
+ }
+ else
+ {
+ oTarget(aList[0] + ' ');
+ oTarget(aList[0]);
+ }
+ }
+ else
+ {
+ oTarget('');
+ }
+ }
+ }).extend({'notify': 'always'})
+ ;
+
+ oResult(oTarget());
+
+ if (!oResult.valueHasMutated)
+ {
+ oResult.valueHasMutated = function () {
+ oTarget.valueHasMutated();
+ };
+ }
+
+ return oResult;
+ };
+
+ ko.extenders.reversible = function (oTarget)
+ {
+ var mValue = oTarget();
+
+ oTarget.commit = function ()
+ {
+ mValue = oTarget();
+ };
+
+ oTarget.reverse = function ()
+ {
+ oTarget(mValue);
+ };
+
+ oTarget.commitedValue = function ()
+ {
+ return mValue;
+ };
+
+ return oTarget;
+ };
+
+ ko.extenders.toggleSubscribe = function (oTarget, oOptions)
+ {
+ oTarget.subscribe(oOptions[1], oOptions[0], 'beforeChange');
+ oTarget.subscribe(oOptions[2], oOptions[0]);
+
+ return oTarget;
+ };
+
+ ko.extenders.toggleSubscribeProperty = function (oTarget, oOptions)
+ {
+ var sProp = oOptions[1];
+
+ if (sProp)
+ {
+ oTarget.subscribe(function (oPrev) {
+ if (oPrev && oPrev[sProp])
+ {
+ oPrev[sProp](false);
+ }
+ }, oOptions[0], 'beforeChange');
+
+ oTarget.subscribe(function (oNext) {
+ if (oNext && oNext[sProp])
+ {
+ oNext[sProp](true);
+ }
+ }, oOptions[0]);
+ }
+
+ return oTarget;
+ };
+
+ ko.extenders.falseTimeout = function (oTarget, iOption)
+ {
+ oTarget.iFalseTimeoutTimeout = 0;
+ oTarget.subscribe(function (bValue) {
+ if (bValue)
+ {
+ window.clearTimeout(oTarget.iFalseTimeoutTimeout);
+ oTarget.iFalseTimeoutTimeout = window.setTimeout(function () {
+ oTarget(false);
+ oTarget.iFalseTimeoutTimeout = 0;
+ }, __webpack_require__(/*! Common/Utils */ 1).pInt(iOption));
+ }
+ });
+
+ return oTarget;
+ };
+
+ ko.extenders.specialThrottle = function (oTarget, iOption)
+ {
+ oTarget.iSpecialThrottleTimeoutValue = __webpack_require__(/*! Common/Utils */ 1).pInt(iOption);
+ if (0 < oTarget.iSpecialThrottleTimeoutValue)
+ {
+ oTarget.iSpecialThrottleTimeout = 0;
+ oTarget.valueForRead = ko.observable(!!oTarget()).extend({'throttle': 10});
+
+ return ko.computed({
+ 'read': oTarget.valueForRead,
+ 'write': function (bValue) {
+
+ if (bValue)
+ {
+ oTarget.valueForRead(bValue);
+ }
+ else
+ {
+ if (oTarget.valueForRead())
+ {
+ window.clearTimeout(oTarget.iSpecialThrottleTimeout);
+ oTarget.iSpecialThrottleTimeout = window.setTimeout(function () {
+ oTarget.valueForRead(false);
+ oTarget.iSpecialThrottleTimeout = 0;
+ }, oTarget.iSpecialThrottleTimeoutValue);
+ }
+ else
+ {
+ oTarget.valueForRead(bValue);
+ }
+ }
+ }
+ });
+ }
+
+ return oTarget;
+ };
+
+ // functions
+
+ ko.observable.fn.validateNone = function ()
+ {
+ this.hasError = ko.observable(false);
+ return this;
+ };
+
+ ko.observable.fn.validateEmail = function ()
+ {
+ var Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ this.hasError = ko.observable(false);
+
+ this.subscribe(function (sValue) {
+ sValue = Utils.trim(sValue);
+ this.hasError('' !== sValue && !(/^[^@\s]+@[^@\s]+$/.test(sValue)));
+ }, this);
+
+ this.valueHasMutated();
+ return this;
+ };
+
+ ko.observable.fn.validateSimpleEmail = function ()
+ {
+ var Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ this.hasError = ko.observable(false);
+
+ this.subscribe(function (sValue) {
+ sValue = Utils.trim(sValue);
+ this.hasError('' !== sValue && !(/^.+@.+$/.test(sValue)));
+ }, this);
+
+ this.valueHasMutated();
+ return this;
+ };
+
+ ko.observable.fn.deleteAccessHelper = function ()
+ {
+ this.extend({'falseTimeout': 3000}).extend({'toggleSubscribe': [null,
+ function (oPrev) {
+ if (oPrev && oPrev.deleteAccess)
+ {
+ oPrev.deleteAccess(false);
+ }
+ }, function (oNext) {
+ if (oNext && oNext.deleteAccess)
+ {
+ oNext.deleteAccess(true);
+ }
+ }
+ ]});
+
+ return this;
+ };
+
+ ko.observable.fn.validateFunc = function (fFunc)
+ {
+ var Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ this.hasFuncError = ko.observable(false);
+
+ if (Utils.isFunc(fFunc))
+ {
+ this.subscribe(function (sValue) {
+ this.hasFuncError(!fFunc(sValue));
+ }, this);
+
+ this.valueHasMutated();
+ }
+
+ return this;
+ };
+
+ module.exports = ko;
+
+ }(ko));
+
+
+/***/ },
+/* 3 */
+/*!***************************!*\
+ !*** external "window._" ***!
+ \***************************/
+/***/ function(module, exports) {
+
+ module.exports = window._;
+
+/***/ },
+/* 4 */
+/*!******************************!*\
+ !*** ./dev/Common/Enums.jsx ***!
+ \******************************/
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ /* eslint quote-props: 0 */
+
+ /**
+ * @enum {string}
+ */
+ var FileType = exports.FileType = {
+ 'Unknown': 'unknown',
+ 'Text': 'text',
+ 'Html': 'html',
+ 'Code': 'code',
+ 'Eml': 'eml',
+ 'WordText': 'word-text',
+ 'Pdf': 'pdf',
+ 'Image': 'image',
+ 'Audio': 'audio',
+ 'Video': 'video',
+ 'Sheet': 'sheet',
+ 'Presentation': 'presentation',
+ 'Certificate': 'certificate',
+ 'CertificateBin': 'certificate-bin',
+ 'Archive': 'archive'
+ };
+
+ /**
+ * @enum {string}
+ */
+ var StorageResultType = exports.StorageResultType = {
+ 'Success': 'success',
+ 'Abort': 'abort',
+ 'Error': 'error',
+ 'Unload': 'unload'
+ };
+
+ /**
+ * @enum {string}
+ */
+ var Focused = exports.Focused = {
+ 'None': 'none',
+ 'MessageList': 'message-list',
+ 'MessageView': 'message-view',
+ 'FolderList': 'folder-list'
+ };
+
+ /**
+ * @enum {number}
+ */
+ var State = exports.State = {
+ 'Empty': 10,
+ 'Login': 20,
+ 'Auth': 30
+ };
+
+ /**
+ * @enum {number}
+ */
+ var StateType = exports.StateType = {
+ 'Webmail': 0,
+ 'Admin': 1
+ };
+
+ /**
+ * @enum {string}
+ */
+ var Capa = exports.Capa = {
+ 'TwoFactor': 'TWO_FACTOR',
+ 'TwoFactorForce': 'TWO_FACTOR_FORCE',
+ 'OpenPGP': 'OPEN_PGP',
+ 'Prefetch': 'PREFETCH',
+ 'Gravatar': 'GRAVATAR',
+ 'Folders': 'FOLDERS',
+ 'Composer': 'COMPOSER',
+ 'Contacts': 'CONTACTS',
+ 'Reload': 'RELOAD',
+ 'Search': 'SEARCH',
+ 'SearchAdv': 'SEARCH_ADV',
+ 'MessageActions': 'MESSAGE_ACTIONS',
+ 'MessageListActions': 'MESSAGELIST_ACTIONS',
+ 'AttachmentsActions': 'ATTACHMENTS_ACTIONS',
+ 'DangerousActions': 'DANGEROUS_ACTIONS',
+ 'Settings': 'SETTINGS',
+ 'Help': 'HELP',
+ 'Themes': 'THEMES',
+ 'UserBackground': 'USER_BACKGROUND',
+ 'Sieve': 'SIEVE',
+ 'Filters': 'FILTERS',
+ 'AttachmentThumbnails': 'ATTACHMENT_THUMBNAILS',
+ 'Templates': 'TEMPLATES',
+ 'AutoLogout': 'AUTOLOGOUT',
+ 'AdditionalAccounts': 'ADDITIONAL_ACCOUNTS',
+ 'Identities': 'IDENTITIES'
+ };
+
+ /**
+ * @enum {string}
+ */
+ var KeyState = exports.KeyState = {
+ 'All': 'all',
+ 'None': 'none',
+ 'ContactList': 'contact-list',
+ 'MessageList': 'message-list',
+ 'FolderList': 'folder-list',
+ 'MessageView': 'message-view',
+ 'Compose': 'compose',
+ 'Settings': 'settings',
+ 'Menu': 'menu',
+ 'PopupComposeOpenPGP': 'compose-open-pgp',
+ 'PopupMessageOpenPGP': 'message-open-pgp',
+ 'PopupViewOpenPGP': 'view-open-pgp',
+ 'PopupKeyboardShortcutsHelp': 'popup-keyboard-shortcuts-help',
+ 'PopupAsk': 'popup-ask'
+ };
+
+ /**
+ * @enum {number}
+ */
+ var FolderType = exports.FolderType = {
+ 'Inbox': 10,
+ 'SentItems': 11,
+ 'Draft': 12,
+ 'Trash': 13,
+ 'Spam': 14,
+ 'Archive': 15,
+ 'NotSpam': 80,
+ 'User': 99
+ };
+
+ /**
+ * @enum {number}
+ */
+ var ServerFolderType = exports.ServerFolderType = {
+ 'USER': 0,
+ 'INBOX': 1,
+ 'SENT': 2,
+ 'DRAFTS': 3,
+ 'JUNK': 4,
+ 'TRASH': 5,
+ 'IMPORTANT': 10,
+ 'FLAGGED': 11,
+ 'ALL': 12
+ };
+
+ /**
+ * @enum {string}
+ */
+ var LoginSignMeTypeAsString = exports.LoginSignMeTypeAsString = {
+ 'DefaultOff': 'defaultoff',
+ 'DefaultOn': 'defaulton',
+ 'Unused': 'unused'
+ };
+
+ /**
+ * @enum {number}
+ */
+ var LoginSignMeType = exports.LoginSignMeType = {
+ 'DefaultOff': 0,
+ 'DefaultOn': 1,
+ 'Unused': 2
+ };
+
+ /**
+ * @enum {string}
+ */
+ var ComposeType = exports.ComposeType = {
+ 'Empty': 'empty',
+ 'Reply': 'reply',
+ 'ReplyAll': 'replyall',
+ 'Forward': 'forward',
+ 'ForwardAsAttachment': 'forward-as-attachment',
+ 'Draft': 'draft',
+ 'EditAsNew': 'editasnew'
+ };
+
+ /**
+ * @enum {number}
+ */
+ var UploadErrorCode = exports.UploadErrorCode = {
+ 'Normal': 0,
+ 'FileIsTooBig': 1,
+ 'FilePartiallyUploaded': 2,
+ 'FileNoUploaded': 3,
+ 'MissingTempFolder': 4,
+ 'FileOnSaveingError': 5,
+ 'FileType': 98,
+ 'Unknown': 99
+ };
+
+ /**
+ * @enum {number}
+ */
+ var SetSystemFoldersNotification = exports.SetSystemFoldersNotification = {
+ 'None': 0,
+ 'Sent': 1,
+ 'Draft': 2,
+ 'Spam': 3,
+ 'Trash': 4,
+ 'Archive': 5
+ };
+
+ /**
+ * @enum {number}
+ */
+ var ClientSideKeyName = exports.ClientSideKeyName = {
+ 'FoldersLashHash': 0,
+ 'MessagesInboxLastHash': 1,
+ 'MailBoxListSize': 2,
+ 'ExpandedFolders': 3,
+ 'FolderListSize': 4,
+ 'MessageListSize': 5,
+ 'LastReplyAction': 6,
+ 'LastSignMe': 7,
+ 'ComposeLastIdentityID': 8
+ };
+
+ /**
+ * @enum {number}
+ */
+ var EventKeyCode = exports.EventKeyCode = {
+ 'Backspace': 8,
+ 'Tab': 9,
+ 'Enter': 13,
+ 'Esc': 27,
+ 'PageUp': 33,
+ 'PageDown': 34,
+ 'Left': 37,
+ 'Right': 39,
+ 'Up': 38,
+ 'Down': 40,
+ 'End': 35,
+ 'Home': 36,
+ 'Space': 32,
+ 'Insert': 45,
+ 'Delete': 46,
+ 'A': 65,
+ 'S': 83
+ };
+
+ /**
+ * @enum {number}
+ */
+ var MessageSetAction = exports.MessageSetAction = {
+ 'SetSeen': 0,
+ 'UnsetSeen': 1,
+ 'SetFlag': 2,
+ 'UnsetFlag': 3
+ };
+
+ /**
+ * @enum {number}
+ */
+ var MessageSelectAction = exports.MessageSelectAction = {
+ 'All': 0,
+ 'None': 1,
+ 'Invert': 2,
+ 'Unseen': 3,
+ 'Seen': 4,
+ 'Flagged': 5,
+ 'Unflagged': 6
+ };
+
+ /**
+ * @enum {number}
+ */
+ var DesktopNotification = exports.DesktopNotification = {
+ 'Allowed': 0,
+ 'NotAllowed': 1,
+ 'Denied': 2,
+ 'NotSupported': 9
+ };
+
+ /**
+ * @enum {number}
+ */
+ var MessagePriority = exports.MessagePriority = {
+ 'Low': 5,
+ 'Normal': 3,
+ 'High': 1
+ };
+
+ /**
+ * @enum {string}
+ */
+ var EditorDefaultType = exports.EditorDefaultType = {
+ 'Html': 'Html',
+ 'Plain': 'Plain',
+ 'HtmlForced': 'HtmlForced',
+ 'PlainForced': 'PlainForced'
+ };
+
+ /**
+ * @enum {number}
+ */
+ var ServerSecure = exports.ServerSecure = {
+ 'None': 0,
+ 'SSL': 1,
+ 'TLS': 2
+ };
+
+ /**
+ * @enum {number}
+ */
+ var SearchDateType = exports.SearchDateType = {
+ 'All': -1,
+ 'Days3': 3,
+ 'Days7': 7,
+ 'Month': 30
+ };
+
+ /**
+ * @enum {number}
+ */
+ var SaveSettingsStep = exports.SaveSettingsStep = {
+ 'Animate': -2,
+ 'Idle': -1,
+ 'TrueResult': 1,
+ 'FalseResult': 0
+ };
+
+ /**
+ * @enum {number}
+ */
+ var Layout = exports.Layout = {
+ 'NoPreview': 0,
+ 'SidePreview': 1,
+ 'BottomPreview': 2,
+ 'Mobile': 3
+ };
+
+ /**
+ * @enum {string}
+ */
+ var FilterConditionField = exports.FilterConditionField = {
+ 'From': 'From',
+ 'Recipient': 'Recipient',
+ 'Subject': 'Subject',
+ 'Header': 'Header',
+ 'Size': 'Size'
+ };
+
+ /**
+ * @enum {string}
+ */
+ var FilterConditionType = exports.FilterConditionType = {
+ 'Contains': 'Contains',
+ 'NotContains': 'NotContains',
+ 'EqualTo': 'EqualTo',
+ 'NotEqualTo': 'NotEqualTo',
+ 'Over': 'Over',
+ 'Under': 'Under'
+ };
+
+ /**
+ * @enum {string}
+ */
+ var FiltersAction = exports.FiltersAction = {
+ 'None': 'None',
+ 'MoveTo': 'MoveTo',
+ 'Discard': 'Discard',
+ 'Vacation': 'Vacation',
+ 'Reject': 'Reject',
+ 'Forward': 'Forward'
+ };
+
+ /**
+ * @enum {string}
+ */
+ var FilterRulesType = exports.FilterRulesType = {
+ 'All': 'All',
+ 'Any': 'Any'
+ };
+
+ /**
+ * @enum {number}
+ */
+ var SignedVerifyStatus = exports.SignedVerifyStatus = {
+ 'UnknownPublicKeys': -4,
+ 'UnknownPrivateKey': -3,
+ 'Unverified': -2,
+ 'Error': -1,
+ 'None': 0,
+ 'Success': 1
+ };
+
+ /**
+ * @enum {number}
+ */
+ var ContactPropertyType = exports.ContactPropertyType = {
+
+ 'Unknown': 0,
+
+ 'FullName': 10,
+
+ 'FirstName': 15,
+ 'LastName': 16,
+ 'MiddleName': 16,
+ 'Nick': 18,
+
+ 'NamePrefix': 20,
+ 'NameSuffix': 21,
+
+ 'Email': 30,
+ 'Phone': 31,
+ 'Web': 32,
+
+ 'Birthday': 40,
+
+ 'Facebook': 90,
+ 'Skype': 91,
+ 'GitHub': 92,
+
+ 'Note': 110,
+
+ 'Custom': 250
+ };
+
+ /**
+ * @enum {number}
+ */
+ var Notification = exports.Notification = {
+ 'InvalidToken': 101,
+ 'AuthError': 102,
+ 'AccessError': 103,
+ 'ConnectionError': 104,
+ 'CaptchaError': 105,
+ 'SocialFacebookLoginAccessDisable': 106,
+ 'SocialTwitterLoginAccessDisable': 107,
+ 'SocialGoogleLoginAccessDisable': 108,
+ 'DomainNotAllowed': 109,
+ 'AccountNotAllowed': 110,
+
+ 'AccountTwoFactorAuthRequired': 120,
+ 'AccountTwoFactorAuthError': 121,
+
+ 'CouldNotSaveNewPassword': 130,
+ 'CurrentPasswordIncorrect': 131,
+ 'NewPasswordShort': 132,
+ 'NewPasswordWeak': 133,
+ 'NewPasswordForbidden': 134,
+
+ 'ContactsSyncError': 140,
+
+ 'CantGetMessageList': 201,
+ 'CantGetMessage': 202,
+ 'CantDeleteMessage': 203,
+ 'CantMoveMessage': 204,
+ 'CantCopyMessage': 205,
+
+ 'CantSaveMessage': 301,
+ 'CantSendMessage': 302,
+ 'InvalidRecipients': 303,
+
+ 'CantSaveFilters': 351,
+ 'CantGetFilters': 352,
+ 'FiltersAreNotCorrect': 355,
+
+ 'CantCreateFolder': 400,
+ 'CantRenameFolder': 401,
+ 'CantDeleteFolder': 402,
+ 'CantSubscribeFolder': 403,
+ 'CantUnsubscribeFolder': 404,
+ 'CantDeleteNonEmptyFolder': 405,
+
+ 'CantSaveSettings': 501,
+ 'CantSavePluginSettings': 502,
+
+ 'DomainAlreadyExists': 601,
+
+ 'CantInstallPackage': 701,
+ 'CantDeletePackage': 702,
+ 'InvalidPluginPackage': 703,
+ 'UnsupportedPluginPackage': 704,
+
+ 'LicensingServerIsUnavailable': 710,
+ 'LicensingExpired': 711,
+ 'LicensingBanned': 712,
+
+ 'DemoSendMessageError': 750,
+ 'DemoAccountError': 751,
+
+ 'AccountAlreadyExists': 801,
+ 'AccountDoesNotExist': 802,
+
+ 'MailServerError': 901,
+ 'ClientViewError': 902,
+ 'InvalidInputArgument': 903,
+
+ 'AjaxFalse': 950,
+ 'AjaxAbort': 951,
+ 'AjaxParse': 952,
+ 'AjaxTimeout': 953,
+
+ 'UnknownNotification': 999,
+ 'UnknownError': 999
+ };
+
+/***/ },
+/* 5 */
+/*!****************************!*\
+ !*** ./dev/Knoin/Knoin.js ***!
+ \****************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+ hasher = __webpack_require__(/*! hasher */ 81),
+ crossroads = __webpack_require__(/*! crossroads */ 49),
+
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Plugins = __webpack_require__(/*! Common/Plugins */ 23),
+ Utils = __webpack_require__(/*! Common/Utils */ 1)
+ ;
+
+ /**
+ * @constructor
+ */
+ function Knoin()
+ {
+ this.oScreens = {};
+ this.sDefaultScreenName = '';
+ this.oCurrentScreen = null;
+ }
+
+ Knoin.prototype.oScreens = {};
+ Knoin.prototype.sDefaultScreenName = '';
+ Knoin.prototype.oCurrentScreen = null;
+
+ Knoin.prototype.hideLoading = function ()
+ {
+ $('#rl-content').show();
+ $('#rl-loading').hide().remove();
+ };
+
+ /**
+ * @param {Object} thisObject
+ */
+ Knoin.prototype.constructorEnd = function (thisObject)
+ {
+ if (Utils.isFunc(thisObject['__constructor_end']))
+ {
+ thisObject['__constructor_end'].call(thisObject);
+ }
+ };
+
+ /**
+ * @param {string|Array} mName
+ * @param {Function} ViewModelClass
+ */
+ Knoin.prototype.extendAsViewModel = function (mName, ViewModelClass)
+ {
+ if (ViewModelClass)
+ {
+ if (Utils.isArray(mName))
+ {
+ ViewModelClass.__names = mName;
+ }
+ else
+ {
+ ViewModelClass.__names = [mName];
+ }
+
+ ViewModelClass.__name = ViewModelClass.__names[0];
+ }
+ };
+
+ /**
+ * @param {Function} SettingsViewModelClass
+ * @param {string} sLabelName
+ * @param {string} sTemplate
+ * @param {string} sRoute
+ * @param {boolean=} bDefault
+ */
+ Knoin.prototype.addSettingsViewModel = function (SettingsViewModelClass, sTemplate, sLabelName, sRoute, bDefault)
+ {
+ SettingsViewModelClass.__rlSettingsData = {
+ 'Label': sLabelName,
+ 'Template': sTemplate,
+ 'Route': sRoute,
+ 'IsDefault': !!bDefault
+ };
+
+ Globals.aViewModels['settings'].push(SettingsViewModelClass);
+ };
+
+ /**
+ * @param {Function} SettingsViewModelClass
+ */
+ Knoin.prototype.removeSettingsViewModel = function (SettingsViewModelClass)
+ {
+ Globals.aViewModels['settings-removed'].push(SettingsViewModelClass);
+ };
+
+ /**
+ * @param {Function} SettingsViewModelClass
+ */
+ Knoin.prototype.disableSettingsViewModel = function (SettingsViewModelClass)
+ {
+ Globals.aViewModels['settings-disabled'].push(SettingsViewModelClass);
+ };
+
+ Knoin.prototype.routeOff = function ()
+ {
+ hasher.changed.active = false;
+ };
+
+ Knoin.prototype.routeOn = function ()
+ {
+ hasher.changed.active = true;
+ };
+
+ /**
+ * @param {string} sScreenName
+ * @return {?Object}
+ */
+ Knoin.prototype.screen = function (sScreenName)
+ {
+ return ('' !== sScreenName && !Utils.isUnd(this.oScreens[sScreenName])) ? this.oScreens[sScreenName] : null;
+ };
+
+ /**
+ * @param {Function} ViewModelClass
+ * @param {Object=} oScreen
+ */
+ Knoin.prototype.buildViewModel = function (ViewModelClass, oScreen)
+ {
+ if (ViewModelClass && !ViewModelClass.__builded)
+ {
+ var
+ kn = this,
+ oViewModel = new ViewModelClass(oScreen),
+ sPosition = oViewModel.viewModelPosition(),
+ oViewModelPlace = $('#rl-content #rl-' + sPosition.toLowerCase()),
+ oViewModelDom = null
+ ;
+
+ ViewModelClass.__builded = true;
+ ViewModelClass.__vm = oViewModel;
+
+ oViewModel.onShowTrigger = ko.observable(false);
+ oViewModel.onHideTrigger = ko.observable(false);
+
+ oViewModel.viewModelName = ViewModelClass.__name;
+ oViewModel.viewModelNames = ViewModelClass.__names;
+
+ if (oViewModelPlace && 1 === oViewModelPlace.length)
+ {
+ oViewModelDom = $('
').addClass('rl-view-model').addClass('RL-' + oViewModel.viewModelTemplate()).hide();
+ oViewModelDom.appendTo(oViewModelPlace);
+
+ oViewModel.viewModelDom = oViewModelDom;
+ ViewModelClass.__dom = oViewModelDom;
+
+ if ('Popups' === sPosition)
+ {
+ oViewModel.cancelCommand = oViewModel.closeCommand = Utils.createCommand(oViewModel, function () {
+ kn.hideScreenPopup(ViewModelClass);
+ });
+
+ oViewModel.modalVisibility.subscribe(function (bValue) {
+
+ var self = this;
+ if (bValue)
+ {
+ this.viewModelDom.show();
+ this.storeAndSetKeyScope();
+
+ Globals.popupVisibilityNames.push(this.viewModelName);
+ oViewModel.viewModelDom.css('z-index', 3000 + Globals.popupVisibilityNames().length + 10);
+
+ if (this.onShowTrigger)
+ {
+ this.onShowTrigger(!this.onShowTrigger());
+ }
+
+ Utils.delegateRun(this, 'onShowWithDelay', [], 500);
+ }
+ else
+ {
+ Utils.delegateRun(this, 'onHide');
+ Utils.delegateRun(this, 'onHideWithDelay', [], 500);
+
+ if (this.onHideTrigger)
+ {
+ this.onHideTrigger(!this.onHideTrigger());
+ }
+
+ this.restoreKeyScope();
+
+ _.each(this.viewModelNames, function (sName) {
+ Plugins.runHook('view-model-on-hide', [sName, self]);
+ });
+
+ Globals.popupVisibilityNames.remove(this.viewModelName);
+ oViewModel.viewModelDom.css('z-index', 2000);
+
+ _.delay(function () {
+ self.viewModelDom.hide();
+ }, 300);
+ }
+
+ }, oViewModel);
+ }
+
+ _.each(ViewModelClass.__names, function (sName) {
+ Plugins.runHook('view-model-pre-build', [sName, oViewModel, oViewModelDom]);
+ });
+
+ ko.applyBindingAccessorsToNode(oViewModelDom[0], {
+ 'translatorInit': true,
+ 'template': function () { return {'name': oViewModel.viewModelTemplate()};}
+ }, oViewModel);
+
+ Utils.delegateRun(oViewModel, 'onBuild', [oViewModelDom]);
+ if (oViewModel && 'Popups' === sPosition)
+ {
+ oViewModel.registerPopupKeyDown();
+ }
+
+ _.each(ViewModelClass.__names, function (sName) {
+ Plugins.runHook('view-model-post-build', [sName, oViewModel, oViewModelDom]);
+ });
+ }
+ else
+ {
+ Utils.log('Cannot find view model position: ' + sPosition);
+ }
+ }
+
+ return ViewModelClass ? ViewModelClass.__vm : null;
+ };
+
+ /**
+ * @param {Function} ViewModelClassToHide
+ */
+ Knoin.prototype.hideScreenPopup = function (ViewModelClassToHide)
+ {
+ if (ViewModelClassToHide && ViewModelClassToHide.__vm && ViewModelClassToHide.__dom)
+ {
+ ViewModelClassToHide.__vm.modalVisibility(false);
+ }
+ };
+
+ /**
+ * @param {Function} ViewModelClassToShow
+ * @param {Array=} aParameters
+ */
+ Knoin.prototype.showScreenPopup = function (ViewModelClassToShow, aParameters)
+ {
+ if (ViewModelClassToShow)
+ {
+ this.buildViewModel(ViewModelClassToShow);
+
+ if (ViewModelClassToShow.__vm && ViewModelClassToShow.__dom)
+ {
+ Utils.delegateRun(ViewModelClassToShow.__vm, 'onBeforeShow', aParameters || []);
+
+ ViewModelClassToShow.__vm.modalVisibility(true);
+
+ Utils.delegateRun(ViewModelClassToShow.__vm, 'onShow', aParameters || []);
+
+ _.each(ViewModelClassToShow.__names, function (sName) {
+ Plugins.runHook('view-model-on-show', [sName, ViewModelClassToShow.__vm, aParameters || []]);
+ });
+ }
+ }
+ };
+
+ /**
+ * @param {Function} ViewModelClassToShow
+ * @return {boolean}
+ */
+ Knoin.prototype.isPopupVisible = function (ViewModelClassToShow)
+ {
+ return ViewModelClassToShow && ViewModelClassToShow.__vm ? ViewModelClassToShow.__vm.modalVisibility() : false;
+ };
+
+ /**
+ * @param {string} sScreenName
+ * @param {string} sSubPart
+ */
+ Knoin.prototype.screenOnRoute = function (sScreenName, sSubPart)
+ {
+ var
+ self = this,
+ oScreen = null,
+ bSameScreen= false,
+ oCross = null
+ ;
+
+ if ('' === Utils.pString(sScreenName))
+ {
+ sScreenName = this.sDefaultScreenName;
+ }
+
+ if ('' !== sScreenName)
+ {
+ oScreen = this.screen(sScreenName);
+ if (!oScreen)
+ {
+ oScreen = this.screen(this.sDefaultScreenName);
+ if (oScreen)
+ {
+ sSubPart = sScreenName + '/' + sSubPart;
+ sScreenName = this.sDefaultScreenName;
+ }
+ }
+
+ if (oScreen && oScreen.__started)
+ {
+ bSameScreen = this.oCurrentScreen && oScreen === this.oCurrentScreen;
+
+ if (!oScreen.__builded)
+ {
+ oScreen.__builded = true;
+
+ if (Utils.isNonEmptyArray(oScreen.viewModels()))
+ {
+ _.each(oScreen.viewModels(), function (ViewModelClass) {
+ this.buildViewModel(ViewModelClass, oScreen);
+ }, this);
+ }
+
+ Utils.delegateRun(oScreen, 'onBuild');
+ }
+
+ _.defer(function () {
+
+ // hide screen
+ if (self.oCurrentScreen && !bSameScreen)
+ {
+ Utils.delegateRun(self.oCurrentScreen, 'onHide');
+ Utils.delegateRun(self.oCurrentScreen, 'onHideWithDelay', [], 500);
+
+ if (self.oCurrentScreen.onHideTrigger)
+ {
+ self.oCurrentScreen.onHideTrigger(!self.oCurrentScreen.onHideTrigger());
+ }
+
+ if (Utils.isNonEmptyArray(self.oCurrentScreen.viewModels()))
+ {
+ _.each(self.oCurrentScreen.viewModels(), function (ViewModelClass) {
+
+ if (ViewModelClass.__vm && ViewModelClass.__dom &&
+ 'Popups' !== ViewModelClass.__vm.viewModelPosition())
+ {
+ ViewModelClass.__dom.hide();
+ ViewModelClass.__vm.viewModelVisibility(false);
+
+ Utils.delegateRun(ViewModelClass.__vm, 'onHide');
+ Utils.delegateRun(ViewModelClass.__vm, 'onHideWithDelay', [], 500);
+
+ if (ViewModelClass.__vm.onHideTrigger)
+ {
+ ViewModelClass.__vm.onHideTrigger(!ViewModelClass.__vm.onHideTrigger());
+ }
+ }
+
+ });
+ }
+ }
+ // --
+
+ self.oCurrentScreen = oScreen;
+
+ // show screen
+ if (self.oCurrentScreen && !bSameScreen)
+ {
+ Utils.delegateRun(self.oCurrentScreen, 'onShow');
+ if (self.oCurrentScreen.onShowTrigger)
+ {
+ self.oCurrentScreen.onShowTrigger(!self.oCurrentScreen.onShowTrigger());
+ }
+
+ Plugins.runHook('screen-on-show', [self.oCurrentScreen.screenName(), self.oCurrentScreen]);
+
+ if (Utils.isNonEmptyArray(self.oCurrentScreen.viewModels()))
+ {
+ _.each(self.oCurrentScreen.viewModels(), function (ViewModelClass) {
+
+ if (ViewModelClass.__vm && ViewModelClass.__dom &&
+ 'Popups' !== ViewModelClass.__vm.viewModelPosition())
+ {
+ Utils.delegateRun(ViewModelClass.__vm, 'onBeforeShow');
+
+ ViewModelClass.__dom.show();
+ ViewModelClass.__vm.viewModelVisibility(true);
+
+ Utils.delegateRun(ViewModelClass.__vm, 'onShow');
+ if (ViewModelClass.__vm.onShowTrigger)
+ {
+ ViewModelClass.__vm.onShowTrigger(!ViewModelClass.__vm.onShowTrigger());
+ }
+
+ Utils.delegateRun(ViewModelClass.__vm, 'onShowWithDelay', [], 200);
+
+ _.each(ViewModelClass.__names, function (sName) {
+ Plugins.runHook('view-model-on-show', [sName, ViewModelClass.__vm]);
+ });
+ }
+
+ }, self);
+ }
+ }
+ // --
+
+ oCross = oScreen.__cross ? oScreen.__cross() : null;
+ if (oCross)
+ {
+ oCross.parse(sSubPart);
+ }
+ });
+ }
+ }
+ };
+
+ /**
+ * @param {Array} aScreensClasses
+ */
+ Knoin.prototype.startScreens = function (aScreensClasses)
+ {
+ $('#rl-content').css({
+ 'visibility': 'hidden'
+ });
+
+ _.each(aScreensClasses, function (CScreen) {
+
+ if (CScreen)
+ {
+ var
+ oScreen = new CScreen(),
+ sScreenName = oScreen ? oScreen.screenName() : ''
+ ;
+
+ if (oScreen && '' !== sScreenName)
+ {
+ if ('' === this.sDefaultScreenName)
+ {
+ this.sDefaultScreenName = sScreenName;
+ }
+
+ this.oScreens[sScreenName] = oScreen;
+ }
+ }
+
+ }, this);
+
+
+ _.each(this.oScreens, function (oScreen) {
+ if (oScreen && !oScreen.__started && oScreen.__start)
+ {
+ oScreen.__started = true;
+ oScreen.__start();
+
+ Plugins.runHook('screen-pre-start', [oScreen.screenName(), oScreen]);
+ Utils.delegateRun(oScreen, 'onStart');
+ Plugins.runHook('screen-post-start', [oScreen.screenName(), oScreen]);
+ }
+ }, this);
+
+ var oCross = crossroads.create();
+ oCross.addRoute(/^([a-zA-Z0-9\-]*)\/?(.*)$/, _.bind(this.screenOnRoute, this));
+
+ hasher.initialized.add(oCross.parse, oCross);
+ hasher.changed.add(oCross.parse, oCross);
+ hasher.init();
+
+ $('#rl-content').css({
+ 'visibility': 'visible'
+ });
+
+ _.delay(function () {
+ Globals.$html.removeClass('rl-started-trigger').addClass('rl-started');
+ }, 100);
+
+ _.delay(function () {
+ Globals.$html.addClass('rl-started-delay');
+ }, 200);
+ };
+
+ /**
+ * @param {string} sHash
+ * @param {boolean=} bSilence = false
+ * @param {boolean=} bReplace = false
+ */
+ Knoin.prototype.setHash = function (sHash, bSilence, bReplace)
+ {
+ sHash = '#' === sHash.substr(0, 1) ? sHash.substr(1) : sHash;
+ sHash = '/' === sHash.substr(0, 1) ? sHash.substr(1) : sHash;
+
+ bReplace = Utils.isUnd(bReplace) ? false : !!bReplace;
+
+ if (Utils.isUnd(bSilence) ? false : !!bSilence)
+ {
+ hasher.changed.active = false;
+ hasher[bReplace ? 'replaceHash' : 'setHash'](sHash);
+ hasher.changed.active = true;
+ }
+ else
+ {
+ hasher.changed.active = true;
+ hasher[bReplace ? 'replaceHash' : 'setHash'](sHash);
+ hasher.setHash(sHash);
+ }
+ };
+
+ module.exports = new Knoin();
+
+ }());
+
+/***/ },
+/* 6 */
+/*!***********************************!*\
+ !*** ./dev/Common/Translator.jsx ***!
+ \***********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Enums = __webpack_require__(/*! Common/Enums */ 4);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ var _Globals2 = _interopRequireDefault(_Globals);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var Translator = function () {
+ function Translator() {
+ _classCallCheck(this, Translator);
+
+ this.data = {};
+ this.notificationI18N = {};
+
+ this.data = _common.window.rainloopI18N || {};
+ this.trigger = _ko2.default.observable(false);
+ this.i18n = _common._.bind(this.i18n, this);
+ this.init();
+ }
+
+ /**
+ * @param {string} key
+ * @param {Object=} valueList
+ * @param {string=} defaulValue
+ * @return {string}
+ */
+
+
+ Translator.prototype.i18n = function i18n(key, valueList, defaulValue) {
+
+ var valueName = '',
+ result = this.data[key];
+
+ if (_common._.isUndefined(result)) {
+ result = _common._.isUndefined(defaulValue) ? key : defaulValue;
+ }
+
+ if (!_common._.isUndefined(valueList) && !_common._.isNull(valueList)) {
+ for (valueName in valueList) {
+ if (_common._.has(valueList, valueName)) {
+ result = result.replace('%' + valueName + '%', valueList[valueName]);
+ }
+ }
+ }
+
+ return result;
+ };
+
+ /**
+ * @param {Object} element
+ */
+
+
+ Translator.prototype.i18nToNode = function i18nToNode(element) {
+
+ var $el = (0, _common.$)(element),
+ key = $el.data('i18n');
+
+ if (key) {
+ if ('[' === key.substr(0, 1)) {
+ switch (key.substr(0, 6)) {
+ case '[html]':
+ $el.html(this.i18n(key.substr(6)));
+ break;
+ case '[place':
+ $el.attr('placeholder', this.i18n(key.substr(13)));
+ break;
+ case '[title':
+ $el.attr('title', this.i18n(key.substr(7)));
+ break;
+ }
+ } else {
+ $el.text(this.i18n(key));
+ }
+ }
+ };
+
+ /**
+ * @param {Object} elements
+ * @param {boolean=} animate = false
+ */
+
+
+ Translator.prototype.i18nToNodes = function i18nToNodes(elements) {
+ var _this = this;
+
+ var animate = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
+
+ _common._.defer(function () {
+
+ (0, _common.$)('[data-i18n]', elements).each(function (index, item) {
+ _this.i18nToNode(item);
+ });
+
+ if (animate && _Globals2.default.bAnimationSupported) {
+ (0, _common.$)('.i18n-animation[data-i18n]', elements).letterfx({
+ fx: 'fall fade',
+ backwards: false,
+ timing: 50,
+ fx_duration: '50ms',
+ letter_end: 'restore',
+ element_end: 'restore'
+ });
+ }
+ });
+ };
+
+ Translator.prototype.reloadData = function reloadData() {
+ if (_common.window.rainloopI18N) {
+ this.data = _common.window.rainloopI18N || {};
+
+ this.i18nToNodes(_common.window.document, true);
+
+ __webpack_require__(/*! Common/Momentor */ 26).reload();
+ this.trigger(!this.trigger());
+ }
+
+ _common.window.rainloopI18N = null;
+ };
+
+ Translator.prototype.initNotificationLanguage = function initNotificationLanguage() {
+ var _this2 = this;
+
+ var map = [[_Enums.Notification.InvalidToken, 'NOTIFICATIONS/INVALID_TOKEN'], [_Enums.Notification.InvalidToken, 'NOTIFICATIONS/INVALID_TOKEN'], [_Enums.Notification.AuthError, 'NOTIFICATIONS/AUTH_ERROR'], [_Enums.Notification.AccessError, 'NOTIFICATIONS/ACCESS_ERROR'], [_Enums.Notification.ConnectionError, 'NOTIFICATIONS/CONNECTION_ERROR'], [_Enums.Notification.CaptchaError, 'NOTIFICATIONS/CAPTCHA_ERROR'], [_Enums.Notification.SocialFacebookLoginAccessDisable, 'NOTIFICATIONS/SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE'], [_Enums.Notification.SocialTwitterLoginAccessDisable, 'NOTIFICATIONS/SOCIAL_TWITTER_LOGIN_ACCESS_DISABLE'], [_Enums.Notification.SocialGoogleLoginAccessDisable, 'NOTIFICATIONS/SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE'], [_Enums.Notification.DomainNotAllowed, 'NOTIFICATIONS/DOMAIN_NOT_ALLOWED'], [_Enums.Notification.AccountNotAllowed, 'NOTIFICATIONS/ACCOUNT_NOT_ALLOWED'], [_Enums.Notification.AccountTwoFactorAuthRequired, 'NOTIFICATIONS/ACCOUNT_TWO_FACTOR_AUTH_REQUIRED'], [_Enums.Notification.AccountTwoFactorAuthError, 'NOTIFICATIONS/ACCOUNT_TWO_FACTOR_AUTH_ERROR'], [_Enums.Notification.CouldNotSaveNewPassword, 'NOTIFICATIONS/COULD_NOT_SAVE_NEW_PASSWORD'], [_Enums.Notification.CurrentPasswordIncorrect, 'NOTIFICATIONS/CURRENT_PASSWORD_INCORRECT'], [_Enums.Notification.NewPasswordShort, 'NOTIFICATIONS/NEW_PASSWORD_SHORT'], [_Enums.Notification.NewPasswordWeak, 'NOTIFICATIONS/NEW_PASSWORD_WEAK'], [_Enums.Notification.NewPasswordForbidden, 'NOTIFICATIONS/NEW_PASSWORD_FORBIDDENT'], [_Enums.Notification.ContactsSyncError, 'NOTIFICATIONS/CONTACTS_SYNC_ERROR'], [_Enums.Notification.CantGetMessageList, 'NOTIFICATIONS/CANT_GET_MESSAGE_LIST'], [_Enums.Notification.CantGetMessage, 'NOTIFICATIONS/CANT_GET_MESSAGE'], [_Enums.Notification.CantDeleteMessage, 'NOTIFICATIONS/CANT_DELETE_MESSAGE'], [_Enums.Notification.CantMoveMessage, 'NOTIFICATIONS/CANT_MOVE_MESSAGE'], [_Enums.Notification.CantCopyMessage, 'NOTIFICATIONS/CANT_MOVE_MESSAGE'], [_Enums.Notification.CantSaveMessage, 'NOTIFICATIONS/CANT_SAVE_MESSAGE'], [_Enums.Notification.CantSendMessage, 'NOTIFICATIONS/CANT_SEND_MESSAGE'], [_Enums.Notification.InvalidRecipients, 'NOTIFICATIONS/INVALID_RECIPIENTS'], [_Enums.Notification.CantSaveFilters, 'NOTIFICATIONS/CANT_SAVE_FILTERS'], [_Enums.Notification.CantGetFilters, 'NOTIFICATIONS/CANT_GET_FILTERS'], [_Enums.Notification.FiltersAreNotCorrect, 'NOTIFICATIONS/FILTERS_ARE_NOT_CORRECT'], [_Enums.Notification.CantCreateFolder, 'NOTIFICATIONS/CANT_CREATE_FOLDER'], [_Enums.Notification.CantRenameFolder, 'NOTIFICATIONS/CANT_RENAME_FOLDER'], [_Enums.Notification.CantDeleteFolder, 'NOTIFICATIONS/CANT_DELETE_FOLDER'], [_Enums.Notification.CantDeleteNonEmptyFolder, 'NOTIFICATIONS/CANT_DELETE_NON_EMPTY_FOLDER'], [_Enums.Notification.CantSubscribeFolder, 'NOTIFICATIONS/CANT_SUBSCRIBE_FOLDER'], [_Enums.Notification.CantUnsubscribeFolder, 'NOTIFICATIONS/CANT_UNSUBSCRIBE_FOLDER'], [_Enums.Notification.CantSaveSettings, 'NOTIFICATIONS/CANT_SAVE_SETTINGS'], [_Enums.Notification.CantSavePluginSettings, 'NOTIFICATIONS/CANT_SAVE_PLUGIN_SETTINGS'], [_Enums.Notification.DomainAlreadyExists, 'NOTIFICATIONS/DOMAIN_ALREADY_EXISTS'], [_Enums.Notification.CantInstallPackage, 'NOTIFICATIONS/CANT_INSTALL_PACKAGE'], [_Enums.Notification.CantDeletePackage, 'NOTIFICATIONS/CANT_DELETE_PACKAGE'], [_Enums.Notification.InvalidPluginPackage, 'NOTIFICATIONS/INVALID_PLUGIN_PACKAGE'], [_Enums.Notification.UnsupportedPluginPackage, 'NOTIFICATIONS/UNSUPPORTED_PLUGIN_PACKAGE'], [_Enums.Notification.LicensingServerIsUnavailable, 'NOTIFICATIONS/LICENSING_SERVER_IS_UNAVAILABLE'], [_Enums.Notification.LicensingExpired, 'NOTIFICATIONS/LICENSING_EXPIRED'], [_Enums.Notification.LicensingBanned, 'NOTIFICATIONS/LICENSING_BANNED'], [_Enums.Notification.DemoSendMessageError, 'NOTIFICATIONS/DEMO_SEND_MESSAGE_ERROR'], [_Enums.Notification.DemoAccountError, 'NOTIFICATIONS/DEMO_ACCOUNT_ERROR'], [_Enums.Notification.AccountAlreadyExists, 'NOTIFICATIONS/ACCOUNT_ALREADY_EXISTS'], [_Enums.Notification.AccountDoesNotExist, 'NOTIFICATIONS/ACCOUNT_DOES_NOT_EXIST'], [_Enums.Notification.MailServerError, 'NOTIFICATIONS/MAIL_SERVER_ERROR'], [_Enums.Notification.InvalidInputArgument, 'NOTIFICATIONS/INVALID_INPUT_ARGUMENT'], [_Enums.Notification.UnknownNotification, 'NOTIFICATIONS/UNKNOWN_ERROR'], [_Enums.Notification.UnknownError, 'NOTIFICATIONS/UNKNOWN_ERROR']];
+
+ this.notificationI18N = this.notificationI18N || {};
+
+ map.forEach(function (item) {
+ _this2.notificationI18N[item[0]] = _this2.i18n(item[1]);
+ });
+ };
+
+ /**
+ * @param {Function} callback
+ * @param {Object} scope
+ * @param {Function=} langCallback
+ */
+
+
+ Translator.prototype.initOnStartOrLangChange = function initOnStartOrLangChange(callback, scope) {
+ var langCallback = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2];
+
+ if (callback) {
+ callback.call(scope);
+ }
+
+ if (langCallback) {
+ this.trigger.subscribe(function () {
+ if (callback) {
+ callback.call(scope);
+ }
+
+ langCallback.call(scope);
+ });
+ } else if (callback) {
+ this.trigger.subscribe(callback, scope);
+ }
+ };
+
+ /**
+ * @param {number} code
+ * @param {*=} message = ''
+ * @param {*=} defCode = null
+ * @return {string}
+ */
+
+
+ Translator.prototype.getNotification = function getNotification(code) {
+ var message = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1];
+ var defCode = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2];
+
+ code = _common.window.parseInt(code, 10) || 0;
+ if (_Enums.Notification.ClientViewError === code && message) {
+ return message;
+ }
+
+ defCode = defCode ? _common.window.parseInt(defCode, 10) || 0 : 0;
+ return _common._.isUndefined(this.notificationI18N[code]) ? defCode && _common._.isUndefined(this.notificationI18N[defCode]) ? this.notificationI18N[defCode] : '' : this.notificationI18N[code];
+ };
+
+ /**
+ * @param {object} response
+ * @param {number} defCode = Notification.UnknownNotification
+ * @return {string}
+ */
+
+
+ Translator.prototype.getNotificationFromResponse = function getNotificationFromResponse(response) {
+ var defCode = arguments.length <= 1 || arguments[1] === undefined ? _Enums.Notification.UnknownNotification : arguments[1];
+
+ return response && response.ErrorCode ? this.getNotification(_Utils2.default.pInt(response.ErrorCode), response.ErrorMessage || '') : this.getNotification(defCode);
+ };
+
+ /**
+ * @param {*} code
+ * @return {string}
+ */
+
+
+ Translator.prototype.getUploadErrorDescByCode = function getUploadErrorDescByCode(code) {
+ var result = '';
+ switch (_common.window.parseInt(code, 10) || 0) {
+ case _Enums.UploadErrorCode.FileIsTooBig:
+ result = this.i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG');
+ break;
+ case _Enums.UploadErrorCode.FilePartiallyUploaded:
+ result = this.i18n('UPLOAD/ERROR_FILE_PARTIALLY_UPLOADED');
+ break;
+ case _Enums.UploadErrorCode.FileNoUploaded:
+ result = this.i18n('UPLOAD/ERROR_NO_FILE_UPLOADED');
+ break;
+ case _Enums.UploadErrorCode.MissingTempFolder:
+ result = this.i18n('UPLOAD/ERROR_MISSING_TEMP_FOLDER');
+ break;
+ case _Enums.UploadErrorCode.FileOnSaveingError:
+ result = this.i18n('UPLOAD/ERROR_ON_SAVING_FILE');
+ break;
+ case _Enums.UploadErrorCode.FileType:
+ result = this.i18n('UPLOAD/ERROR_FILE_TYPE');
+ break;
+ default:
+ result = this.i18n('UPLOAD/ERROR_UNKNOWN');
+ break;
+ }
+
+ return result;
+ };
+
+ /**
+ * @param {boolean} admin
+ * @param {string} language
+ * @param {Function=} done
+ * @param {Function=} fail
+ */
+
+
+ Translator.prototype.reload = function reload(admin, language, done, fail) {
+
+ var self = this,
+ start = _Utils2.default.microtime();
+
+ _Globals2.default.$html.addClass('rl-changing-language');
+
+ _common.$.ajax({
+ url: __webpack_require__(/*! Common/Links */ 12).langLink(language, admin),
+ dataType: 'script',
+ cache: true
+ }).fail(fail || _Utils2.default.emptyFunction).done(function () {
+ _common._.delay(function () {
+
+ self.reloadData();
+
+ (done || _Utils2.default.emptyFunction)();
+
+ var isRtl = -1 < _Utils2.default.inArray(language, ['ar', 'ar_sa', 'he', 'he_he', 'ur', 'ur_ir']);
+
+ _Globals2.default.$html.removeClass('rl-changing-language').removeClass('rl-rtl rl-ltr').addClass(isRtl ? 'rl-rtl' : 'rl-ltr')
+ // .attr('dir', isRtl ? 'rtl' : 'ltr')
+ ;
+ }, 500 < _Utils2.default.microtime() - start ? 1 : 500);
+ });
+ };
+
+ Translator.prototype.init = function init() {
+ _Globals2.default.$html.addClass('rl-' + (_Globals2.default.$html.attr('dir') || 'ltr'));
+ };
+
+ return Translator;
+ }();
+
+ module.exports = new Translator();
+
+/***/ },
+/* 7 */
+/*!**************************!*\
+ !*** ./dev/App/User.jsx ***!
+ \**************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _progressJs = __webpack_require__(/*! progressJs */ 83);
+
+ var _progressJs2 = _interopRequireDefault(_progressJs);
+
+ var _Tinycon = __webpack_require__(/*! Tinycon */ 171);
+
+ var _Tinycon2 = _interopRequireDefault(_Tinycon);
+
+ var _Enums = __webpack_require__(/*! Common/Enums */ 4);
+
+ var Enums = _interopRequireWildcard(_Enums);
+
+ var _Consts = __webpack_require__(/*! Common/Consts */ 17);
+
+ var Consts = _interopRequireWildcard(_Consts);
+
+ var _Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ var _Globals2 = _interopRequireDefault(_Globals);
+
+ var _Plugins = __webpack_require__(/*! Common/Plugins */ 23);
+
+ var _Plugins2 = _interopRequireDefault(_Plugins);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Links = __webpack_require__(/*! Common/Links */ 12);
+
+ var _Links2 = _interopRequireDefault(_Links);
+
+ var _Events = __webpack_require__(/*! Common/Events */ 25);
+
+ var _Events2 = _interopRequireDefault(_Events);
+
+ var _Translator = __webpack_require__(/*! Common/Translator */ 6);
+
+ var _Translator2 = _interopRequireDefault(_Translator);
+
+ var _Momentor = __webpack_require__(/*! Common/Momentor */ 26);
+
+ var _Momentor2 = _interopRequireDefault(_Momentor);
+
+ var _Cache = __webpack_require__(/*! Common/Cache */ 19);
+
+ var _Cache2 = _interopRequireDefault(_Cache);
+
+ var _Social = __webpack_require__(/*! Stores/Social */ 34);
+
+ var _Social2 = _interopRequireDefault(_Social);
+
+ var _Settings = __webpack_require__(/*! Stores/User/Settings */ 28);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ var _Account = __webpack_require__(/*! Stores/User/Account */ 31);
+
+ var _Account2 = _interopRequireDefault(_Account);
+
+ var _Identity = __webpack_require__(/*! Stores/User/Identity */ 53);
+
+ var _Identity2 = _interopRequireDefault(_Identity);
+
+ var _Template = __webpack_require__(/*! Stores/User/Template */ 92);
+
+ var _Template2 = _interopRequireDefault(_Template);
+
+ var _Folder = __webpack_require__(/*! Stores/User/Folder */ 21);
+
+ var _Folder2 = _interopRequireDefault(_Folder);
+
+ var _Pgp = __webpack_require__(/*! Stores/User/Pgp */ 33);
+
+ var _Pgp2 = _interopRequireDefault(_Pgp);
+
+ var _Message = __webpack_require__(/*! Stores/User/Message */ 32);
+
+ var _Message2 = _interopRequireDefault(_Message);
+
+ var _Contact = __webpack_require__(/*! Stores/User/Contact */ 51);
+
+ var _Contact2 = _interopRequireDefault(_Contact);
+
+ var _Client = __webpack_require__(/*! Storage/Client */ 47);
+
+ var _Client2 = _interopRequireDefault(_Client);
+
+ var _Settings3 = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings4 = _interopRequireDefault(_Settings3);
+
+ var _Ajax = __webpack_require__(/*! Remote/User/Ajax */ 15);
+
+ var _Ajax2 = _interopRequireDefault(_Ajax);
+
+ var _Ajax3 = __webpack_require__(/*! Promises/User/Ajax */ 41);
+
+ var _Ajax4 = _interopRequireDefault(_Ajax3);
+
+ var _Email = __webpack_require__(/*! Model/Email */ 30);
+
+ var _Email2 = _interopRequireDefault(_Email);
+
+ var _Account3 = __webpack_require__(/*! Model/Account */ 101);
+
+ var _Account4 = _interopRequireDefault(_Account3);
+
+ var _Identity3 = __webpack_require__(/*! Model/Identity */ 107);
+
+ var _Identity4 = _interopRequireDefault(_Identity3);
+
+ var _Template3 = __webpack_require__(/*! Model/Template */ 110);
+
+ var _Template4 = _interopRequireDefault(_Template3);
+
+ var _OpenPgpKey = __webpack_require__(/*! Model/OpenPgpKey */ 109);
+
+ var _OpenPgpKey2 = _interopRequireDefault(_OpenPgpKey);
+
+ var _Knoin = __webpack_require__(/*! Knoin/Knoin */ 5);
+
+ var _Knoin2 = _interopRequireDefault(_Knoin);
+
+ var _Abstract = __webpack_require__(/*! App/Abstract */ 64);
+
+ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var AppUser = function (_AbstractApp) {
+ _inherits(AppUser, _AbstractApp);
+
+ function AppUser() {
+ _classCallCheck(this, AppUser);
+
+ var _this = _possibleConstructorReturn(this, _AbstractApp.call(this, _Ajax2.default));
+
+ _this.oMoveCache = {};
+
+
+ _this.quotaDebounce = _common._.debounce(_this.quota, 1000 * 30);
+ _this.moveOrDeleteResponseHelper = _common._.bind(_this.moveOrDeleteResponseHelper, _this);
+
+ _this.messagesMoveTrigger = _common._.debounce(_this.messagesMoveTrigger, 500);
+
+ _common.window.setInterval(function () {
+ return _Events2.default.pub('interval.30s');
+ }, 30000);
+ _common.window.setInterval(function () {
+ return _Events2.default.pub('interval.1m');
+ }, 60000);
+ _common.window.setInterval(function () {
+ return _Events2.default.pub('interval.2m');
+ }, 60000 * 2);
+ _common.window.setInterval(function () {
+ return _Events2.default.pub('interval.3m');
+ }, 60000 * 3);
+ _common.window.setInterval(function () {
+ return _Events2.default.pub('interval.5m');
+ }, 60000 * 5);
+ _common.window.setInterval(function () {
+ return _Events2.default.pub('interval.10m');
+ }, 60000 * 10);
+ _common.window.setInterval(function () {
+ return _Events2.default.pub('interval.15m');
+ }, 60000 * 15);
+ _common.window.setInterval(function () {
+ return _Events2.default.pub('interval.20m');
+ }, 60000 * 15);
+
+ _common.window.setTimeout(function () {
+ return _common.window.setInterval(function () {
+ return _Events2.default.pub('interval.2m-after5m');
+ }, 60000 * 2);
+ }, 60000 * 5);
+ _common.window.setTimeout(function () {
+ return _common.window.setInterval(function () {
+ return _Events2.default.pub('interval.5m-after5m');
+ }, 60000 * 5);
+ }, 60000 * 5);
+ _common.window.setTimeout(function () {
+ return _common.window.setInterval(function () {
+ return _Events2.default.pub('interval.10m-after5m');
+ }, 60000 * 10);
+ }, 60000 * 5);
+
+ _common.$.wakeUp(function () {
+ _Ajax2.default.jsVersion(function (sResult, oData) {
+ if (Enums.StorageResultType.Success === sResult && oData && !oData.Result) {
+ if (_common.window.parent && !!_Settings4.default.appSettingsGet('inIframe')) {
+ _common.window.parent.location.reload();
+ } else {
+ _common.window.location.reload();
+ }
+ }
+ }, _Settings4.default.appSettingsGet('version'));
+ }, {}, 60 * 60 * 1000);
+
+ if (_Settings4.default.settingsGet('UserBackgroundHash')) {
+ _common._.delay(function () {
+ (0, _common.$)('#rl-bg').attr('style', 'background-image: none !important;').backstretch(_Links2.default.userBackground(_Settings4.default.settingsGet('UserBackgroundHash')), {
+ fade: _Globals2.default.bAnimationSupported ? 1000 : 0,
+ centeredX: true,
+ centeredY: true
+ }).removeAttr('style');
+ }, 1000);
+ }
+
+ _this.socialUsers = _common._.bind(_this.socialUsers, _this);
+ return _this;
+ }
+
+ AppUser.prototype.remote = function remote() {
+ return _Ajax2.default;
+ };
+
+ AppUser.prototype.reloadFlagsCurrentMessageListAndMessageFromCache = function reloadFlagsCurrentMessageListAndMessageFromCache() {
+ _common._.each(_Message2.default.messageList(), function (message) {
+ _Cache2.default.initMessageFlagsFromCache(message);
+ });
+ _Cache2.default.initMessageFlagsFromCache(_Message2.default.message());
+ };
+
+ /**
+ * @param {boolean=} bDropPagePosition = false
+ * @param {boolean=} bDropCurrenFolderCache = false
+ */
+
+
+ AppUser.prototype.reloadMessageList = function reloadMessageList() {
+ var bDropPagePosition = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
+ var bDropCurrenFolderCache = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
+
+
+ var iOffset = (_Message2.default.messageListPage() - 1) * _Settings2.default.messagesPerPage();
+
+ if (bDropCurrenFolderCache) {
+ _Cache2.default.setFolderHash(_Folder2.default.currentFolderFullNameRaw(), '');
+ }
+
+ if (bDropPagePosition) {
+ _Message2.default.messageListPage(1);
+ _Message2.default.messageListPageBeforeThread(1);
+ iOffset = 0;
+
+ _Knoin2.default.setHash(_Links2.default.mailBox(_Folder2.default.currentFolderFullNameHash(), _Message2.default.messageListPage(), _Message2.default.messageListSearch(), _Message2.default.messageListThreadUid()), true, true);
+ }
+
+ _Message2.default.messageListLoading(true);
+ _Ajax2.default.messageList(function (sResult, oData, bCached) {
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result) {
+ _Message2.default.messageListError('');
+ _Message2.default.messageListLoading(false);
+
+ _Message2.default.setMessageList(oData, bCached);
+ } else if (Enums.StorageResultType.Unload === sResult) {
+ _Message2.default.messageListError('');
+ _Message2.default.messageListLoading(false);
+ } else if (Enums.StorageResultType.Abort !== sResult) {
+ _Message2.default.messageList([]);
+ _Message2.default.messageListLoading(false);
+ _Message2.default.messageListError(oData && oData.ErrorCode ? _Translator2.default.getNotification(oData.ErrorCode) : _Translator2.default.i18n('NOTIFICATIONS/CANT_GET_MESSAGE_LIST'));
+ }
+ }, _Folder2.default.currentFolderFullNameRaw(), iOffset, _Settings2.default.messagesPerPage(), _Message2.default.messageListSearch(), _Message2.default.messageListThreadUid());
+ };
+
+ AppUser.prototype.recacheInboxMessageList = function recacheInboxMessageList() {
+ _Ajax2.default.messageList(_Utils2.default.emptyFunction, _Cache2.default.getFolderInboxName(), 0, _Settings2.default.messagesPerPage(), '', '', true);
+ };
+
+ /**
+ * @param {Function} fResultFunc
+ * @return {boolean}
+ */
+
+
+ AppUser.prototype.contactsSync = function contactsSync(fResultFunc) {
+
+ var oContacts = _Contact2.default.contacts;
+ if (oContacts.importing() || oContacts.syncing() || !_Contact2.default.enableContactsSync() || !_Contact2.default.allowContactsSync()) {
+ return false;
+ }
+
+ oContacts.syncing(true);
+
+ _Ajax2.default.contactsSync(function (sResult, oData) {
+
+ oContacts.syncing(false);
+
+ if (fResultFunc) {
+ fResultFunc(sResult, oData);
+ }
+ });
+
+ return true;
+ };
+
+ AppUser.prototype.messagesMoveTrigger = function messagesMoveTrigger() {
+ var _this2 = this;
+
+ var sTrashFolder = _Folder2.default.trashFolder(),
+ sSpamFolder = _Folder2.default.spamFolder();
+
+ _common._.each(this.oMoveCache, function (oItem) {
+
+ var bSpam = sSpamFolder === oItem.To,
+ bTrash = sTrashFolder === oItem.To,
+ bHam = !bSpam && sSpamFolder === oItem.From && _Cache2.default.getFolderInboxName() === oItem.To;
+
+ _Ajax2.default.messagesMove(_this2.moveOrDeleteResponseHelper, oItem.From, oItem.To, oItem.Uid, bSpam ? 'SPAM' : bHam ? 'HAM' : '', bSpam || bTrash);
+ });
+
+ this.oMoveCache = {};
+ };
+
+ AppUser.prototype.messagesMoveHelper = function messagesMoveHelper(sFromFolderFullNameRaw, sToFolderFullNameRaw, aUidForMove) {
+
+ var sH = '$$' + sFromFolderFullNameRaw + '$$' + sToFolderFullNameRaw + '$$';
+ if (!this.oMoveCache[sH]) {
+ this.oMoveCache[sH] = {
+ From: sFromFolderFullNameRaw,
+ To: sToFolderFullNameRaw,
+ Uid: []
+ };
+ }
+
+ this.oMoveCache[sH].Uid = _common._.union(this.oMoveCache[sH].Uid, aUidForMove);
+ this.messagesMoveTrigger();
+ };
+
+ AppUser.prototype.messagesCopyHelper = function messagesCopyHelper(sFromFolderFullNameRaw, sToFolderFullNameRaw, aUidForCopy) {
+ _Ajax2.default.messagesCopy(this.moveOrDeleteResponseHelper, sFromFolderFullNameRaw, sToFolderFullNameRaw, aUidForCopy);
+ };
+
+ AppUser.prototype.messagesDeleteHelper = function messagesDeleteHelper(sFromFolderFullNameRaw, aUidForRemove) {
+ _Ajax2.default.messagesDelete(this.moveOrDeleteResponseHelper, sFromFolderFullNameRaw, aUidForRemove);
+ };
+
+ AppUser.prototype.moveOrDeleteResponseHelper = function moveOrDeleteResponseHelper(sResult, oData) {
+
+ if (Enums.StorageResultType.Success === sResult && _Folder2.default.currentFolder()) {
+ if (oData && _Utils2.default.isArray(oData.Result) && 2 === oData.Result.length) {
+ _Cache2.default.setFolderHash(oData.Result[0], oData.Result[1]);
+ } else {
+ _Cache2.default.setFolderHash(_Folder2.default.currentFolderFullNameRaw(), '');
+
+ if (oData && -1 < _Utils2.default.inArray(oData.ErrorCode, [Enums.Notification.CantMoveMessage, Enums.Notification.CantCopyMessage])) {
+ _common.window.alert(_Translator2.default.getNotification(oData.ErrorCode));
+ }
+ }
+
+ this.reloadMessageList(0 === _Message2.default.messageList().length);
+ this.quotaDebounce();
+ }
+ };
+
+ /**
+ * @param {string} sFromFolderFullNameRaw
+ * @param {Array} aUidForRemove
+ */
+
+
+ AppUser.prototype.deleteMessagesFromFolderWithoutCheck = function deleteMessagesFromFolderWithoutCheck(sFromFolderFullNameRaw, aUidForRemove) {
+ this.messagesDeleteHelper(sFromFolderFullNameRaw, aUidForRemove);
+ _Message2.default.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove);
+ };
+
+ /**
+ * @param {number} iDeleteType
+ * @param {string} sFromFolderFullNameRaw
+ * @param {Array} aUidForRemove
+ * @param {boolean=} bUseFolder = true
+ */
+
+
+ AppUser.prototype.deleteMessagesFromFolder = function deleteMessagesFromFolder(iDeleteType, sFromFolderFullNameRaw, aUidForRemove, bUseFolder) {
+ var _this3 = this;
+
+ var oMoveFolder = null,
+ nSetSystemFoldersNotification = null;
+
+ switch (iDeleteType) {
+ case Enums.FolderType.Spam:
+ oMoveFolder = _Cache2.default.getFolderFromCacheList(_Folder2.default.spamFolder());
+ nSetSystemFoldersNotification = Enums.SetSystemFoldersNotification.Spam;
+ break;
+ case Enums.FolderType.NotSpam:
+ oMoveFolder = _Cache2.default.getFolderFromCacheList(_Cache2.default.getFolderInboxName());
+ break;
+ case Enums.FolderType.Trash:
+ oMoveFolder = _Cache2.default.getFolderFromCacheList(_Folder2.default.trashFolder());
+ nSetSystemFoldersNotification = Enums.SetSystemFoldersNotification.Trash;
+ break;
+ case Enums.FolderType.Archive:
+ oMoveFolder = _Cache2.default.getFolderFromCacheList(_Folder2.default.archiveFolder());
+ nSetSystemFoldersNotification = Enums.SetSystemFoldersNotification.Archive;
+ break;
+ }
+
+ bUseFolder = _Utils2.default.isUnd(bUseFolder) ? true : !!bUseFolder;
+ if (bUseFolder) {
+ if (Enums.FolderType.Spam === iDeleteType && Consts.UNUSED_OPTION_VALUE === _Folder2.default.spamFolder() || Enums.FolderType.Trash === iDeleteType && Consts.UNUSED_OPTION_VALUE === _Folder2.default.trashFolder() || Enums.FolderType.Archive === iDeleteType && Consts.UNUSED_OPTION_VALUE === _Folder2.default.archiveFolder()) {
+ bUseFolder = false;
+ }
+ }
+
+ if (!oMoveFolder && bUseFolder) {
+ _Knoin2.default.showScreenPopup(__webpack_require__(/*! View/Popup/FolderSystem */ 52), [nSetSystemFoldersNotification]);
+ } else if (!bUseFolder || Enums.FolderType.Trash === iDeleteType && (sFromFolderFullNameRaw === _Folder2.default.spamFolder() || sFromFolderFullNameRaw === _Folder2.default.trashFolder())) {
+ _Knoin2.default.showScreenPopup(__webpack_require__(/*! View/Popup/Ask */ 43), [_Translator2.default.i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'), function () {
+ _this3.messagesDeleteHelper(sFromFolderFullNameRaw, aUidForRemove);
+ _Message2.default.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove);
+ }]);
+ } else if (oMoveFolder) {
+ this.messagesMoveHelper(sFromFolderFullNameRaw, oMoveFolder.fullNameRaw, aUidForRemove);
+ _Message2.default.removeMessagesFromList(sFromFolderFullNameRaw, aUidForRemove, oMoveFolder.fullNameRaw);
+ }
+ };
+
+ /**
+ * @param {string} sFromFolderFullNameRaw
+ * @param {Array} aUidForMove
+ * @param {string} sToFolderFullNameRaw
+ * @param {boolean=} bCopy = false
+ */
+
+
+ AppUser.prototype.moveMessagesToFolder = function moveMessagesToFolder(sFromFolderFullNameRaw, aUidForMove, sToFolderFullNameRaw, bCopy) {
+
+ if (sFromFolderFullNameRaw !== sToFolderFullNameRaw && _Utils2.default.isArray(aUidForMove) && 0 < aUidForMove.length) {
+ var oFromFolder = _Cache2.default.getFolderFromCacheList(sFromFolderFullNameRaw),
+ oToFolder = _Cache2.default.getFolderFromCacheList(sToFolderFullNameRaw);
+
+ if (oFromFolder && oToFolder) {
+ if (_Utils2.default.isUnd(bCopy) ? false : !!bCopy) {
+ this.messagesCopyHelper(oFromFolder.fullNameRaw, oToFolder.fullNameRaw, aUidForMove);
+ } else {
+ this.messagesMoveHelper(oFromFolder.fullNameRaw, oToFolder.fullNameRaw, aUidForMove);
+ }
+
+ _Message2.default.removeMessagesFromList(oFromFolder.fullNameRaw, aUidForMove, oToFolder.fullNameRaw, bCopy);
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {Function=} callback = null
+ */
+
+
+ AppUser.prototype.foldersReload = function foldersReload() {
+ var callback = arguments.length <= 0 || arguments[0] === undefined ? null : arguments[0];
+
+
+ _Ajax4.default.foldersReload(_Folder2.default.foldersLoading).then(function (value) {
+ if (callback) {
+ callback(!!value);
+ }
+ }).fail(function () {
+ if (callback) {
+ _common._.delay(function () {
+ return callback(false);
+ }, 1);
+ }
+ });
+ };
+
+ AppUser.prototype.foldersPromisesActionHelper = function foldersPromisesActionHelper(promise, errorDefCode) {
+
+ _Ajax4.default.abort('Folders').fastResolve(true).then(function () {
+ return promise;
+ }).fail(function (errorCode) {
+ _Folder2.default.folderList.error(_Translator2.default.getNotification(errorCode, '', errorDefCode));
+ }).fin(function () {
+ _Ajax4.default.foldersReloadWithTimeout(_Folder2.default.foldersLoading);
+ }).done();
+ };
+
+ AppUser.prototype.reloadOpenPgpKeys = function reloadOpenPgpKeys() {
+
+ if (_Pgp2.default.capaOpenPGP()) {
+ var aKeys = [],
+ oEmail = new _Email2.default(),
+ oOpenpgpKeyring = _Pgp2.default.openpgpKeyring,
+ oOpenpgpKeys = oOpenpgpKeyring ? oOpenpgpKeyring.getAllKeys() : [];
+
+ _common._.each(oOpenpgpKeys, function (oItem, iIndex) {
+ if (oItem && oItem.primaryKey) {
+ var aEmails = [],
+ aUsers = [],
+ oPrimaryUser = oItem.getPrimaryUser(),
+ sUser = oPrimaryUser && oPrimaryUser.user ? oPrimaryUser.user.userId.userid : oItem.users && oItem.users[0] ? oItem.users[0].userId.userid : '';
+
+ if (oItem.users) {
+ _common._.each(oItem.users, function (item) {
+ oEmail.clear();
+ oEmail.mailsoParse(item.userId.userid);
+ if (oEmail.validate()) {
+ aEmails.push(oEmail.email);
+ aUsers.push(item.userId.userid);
+ }
+ });
+ }
+
+ if (aEmails.length) {
+ aKeys.push(new _OpenPgpKey2.default(iIndex, oItem.primaryKey.getFingerprint(), oItem.primaryKey.getKeyId().toHex().toLowerCase(), _common._.uniq(_common._.compact(_common._.map(oItem.getKeyIds(), function (item) {
+ return item && item.toHex ? item.toHex() : null;
+ }))), aUsers, aEmails, oItem.isPrivate(), oItem.armor(), sUser));
+ }
+ }
+ });
+
+ _Utils2.default.delegateRunOnDestroy(_Pgp2.default.openpgpkeys());
+ _Pgp2.default.openpgpkeys(aKeys);
+ }
+ };
+
+ AppUser.prototype.accountsCounts = function accountsCounts() {
+ return false;
+ // AccountStore.accounts.loading(true);
+ //
+ // Remote.accountsCounts((sResult, oData) => {
+ //
+ // AccountStore.accounts.loading(false);
+ //
+ // if (Enums.StorageResultType.Success === sResult && oData.Result && oData.Result['Counts'])
+ // {
+ // var
+ // sEmail = AccountStore.email(),
+ // aAcounts = AccountStore.accounts()
+ // ;
+ //
+ // _.each(oData.Result['Counts'], (oItem) => {
+ //
+ // var oAccount = _.find(aAcounts, (oAccount) => {
+ // return oAccount && oItem[0] === oAccount.email && sEmail !== oAccount.email;
+ // });
+ //
+ // if (oAccount)
+ // {
+ // oAccount.count(Utils.pInt(oItem[1]));
+ // }
+ // });
+ // }
+ // });
+ };
+
+ AppUser.prototype.accountsAndIdentities = function accountsAndIdentities(bBoot) {
+ var _this4 = this;
+
+ _Account2.default.accounts.loading(true);
+ _Identity2.default.identities.loading(true);
+
+ _Ajax2.default.accountsAndIdentities(function (sResult, oData) {
+
+ _Account2.default.accounts.loading(false);
+ _Identity2.default.identities.loading(false);
+
+ if (Enums.StorageResultType.Success === sResult && oData.Result) {
+ var aCounts = {},
+ sParentEmail = _Settings4.default.settingsGet('ParentEmail'),
+ sAccountEmail = _Account2.default.email();
+
+ sParentEmail = '' === sParentEmail ? sAccountEmail : sParentEmail;
+
+ if (_Utils2.default.isArray(oData.Result.Accounts)) {
+ _common._.each(_Account2.default.accounts(), function (oAccount) {
+ aCounts[oAccount.email] = oAccount.count();
+ });
+
+ _Utils2.default.delegateRunOnDestroy(_Account2.default.accounts());
+
+ _Account2.default.accounts(_common._.map(oData.Result.Accounts, function (sValue) {
+ return new _Account4.default(sValue, sValue !== sParentEmail, aCounts[sValue] || 0);
+ }));
+ }
+
+ if (_Utils2.default.isUnd(bBoot) ? false : !!bBoot) {
+ _common._.delay(function () {
+ return _this4.accountsCounts();
+ }, 1000 * 5);
+ _Events2.default.sub('interval.10m-after5m', function () {
+ return _this4.accountsCounts();
+ });
+ }
+
+ if (_Utils2.default.isArray(oData.Result.Identities)) {
+ _Utils2.default.delegateRunOnDestroy(_Identity2.default.identities());
+
+ _Identity2.default.identities(_common._.map(oData.Result.Identities, function (oIdentityData) {
+
+ var sId = _Utils2.default.pString(oIdentityData.Id),
+ sEmail = _Utils2.default.pString(oIdentityData.Email),
+ oIdentity = new _Identity4.default(sId, sEmail);
+
+ oIdentity.name(_Utils2.default.pString(oIdentityData.Name));
+ oIdentity.replyTo(_Utils2.default.pString(oIdentityData.ReplyTo));
+ oIdentity.bcc(_Utils2.default.pString(oIdentityData.Bcc));
+ oIdentity.signature(_Utils2.default.pString(oIdentityData.Signature));
+ oIdentity.signatureInsertBefore(!!oIdentityData.SignatureInsertBefore);
+
+ return oIdentity;
+ }));
+ }
+ }
+ });
+ };
+
+ AppUser.prototype.templates = function templates() {
+
+ _Template2.default.templates.loading(true);
+
+ _Ajax2.default.templates(function (result, data) {
+
+ _Template2.default.templates.loading(false);
+
+ if (Enums.StorageResultType.Success === result && data.Result && _Utils2.default.isArray(data.Result.Templates)) {
+ _Utils2.default.delegateRunOnDestroy(_Template2.default.templates());
+
+ _Template2.default.templates(_common._.compact(_common._.map(data.Result.Templates, function (templateData) {
+ var template = new _Template4.default();
+ return template.parse(templateData) ? template : null;
+ })));
+ }
+ });
+ };
+
+ AppUser.prototype.quota = function quota() {
+ _Ajax2.default.quota(function (result, data) {
+ if (Enums.StorageResultType.Success === result && data && data.Result && _Utils2.default.isArray(data.Result) && 1 < data.Result.length && _Utils2.default.isPosNumeric(data.Result[0], true) && _Utils2.default.isPosNumeric(data.Result[1], true)) {
+ __webpack_require__(/*! Stores/User/Quota */ 91).populateData(_Utils2.default.pInt(data.Result[1]), _Utils2.default.pInt(data.Result[0]));
+ }
+ });
+ };
+
+ /**
+ * @param {string} folder
+ * @param {Array=} list = []
+ */
+
+
+ AppUser.prototype.folderInformation = function folderInformation(folder, list) {
+ var _this5 = this;
+
+ if ('' !== _Utils2.default.trim(folder)) {
+ _Ajax2.default.folderInformation(function (result, data) {
+ if (Enums.StorageResultType.Success === result) {
+ if (data && data.Result && data.Result.Hash && data.Result.Folder) {
+ var uid = '',
+ check = false,
+ unreadCountChange = false;
+
+ var folderFromCache = _Cache2.default.getFolderFromCacheList(data.Result.Folder);
+ if (folderFromCache) {
+ folderFromCache.interval = _Momentor2.default.momentNowUnix();
+
+ if (data.Result.Hash) {
+ _Cache2.default.setFolderHash(data.Result.Folder, data.Result.Hash);
+ }
+
+ if (_Utils2.default.isNormal(data.Result.MessageCount)) {
+ folderFromCache.messageCountAll(data.Result.MessageCount);
+ }
+
+ if (_Utils2.default.isNormal(data.Result.MessageUnseenCount)) {
+ if (_Utils2.default.pInt(folderFromCache.messageCountUnread()) !== _Utils2.default.pInt(data.Result.MessageUnseenCount)) {
+ unreadCountChange = true;
+ }
+
+ folderFromCache.messageCountUnread(data.Result.MessageUnseenCount);
+ }
+
+ if (unreadCountChange) {
+ _Cache2.default.clearMessageFlagsFromCacheByFolder(folderFromCache.fullNameRaw);
+ }
+
+ if (data.Result.Flags) {
+ for (uid in data.Result.Flags) {
+ if (data.Result.Flags.hasOwnProperty(uid)) {
+ check = true;
+ var flags = data.Result.Flags[uid];
+ _Cache2.default.storeMessageFlagsToCacheByFolderAndUid(folderFromCache.fullNameRaw, uid.toString(), [!flags.IsSeen, !!flags.IsFlagged, !!flags.IsAnswered, !!flags.IsForwarded, !!flags.IsReadReceipt]);
+ }
+ }
+
+ if (check) {
+ _this5.reloadFlagsCurrentMessageListAndMessageFromCache();
+ }
+ }
+
+ _Message2.default.initUidNextAndNewMessages(folderFromCache.fullNameRaw, data.Result.UidNext, data.Result.NewMessages);
+
+ var hash = _Cache2.default.getFolderHash(data.Result.Folder);
+ if (data.Result.Hash !== hash || '' === hash || unreadCountChange) {
+ if (folderFromCache.fullNameRaw === _Folder2.default.currentFolderFullNameRaw()) {
+ _this5.reloadMessageList();
+ } else if (_Cache2.default.getFolderInboxName() === folderFromCache.fullNameRaw) {
+ _this5.recacheInboxMessageList();
+ }
+ }
+ }
+ }
+ }
+ }, folder, list);
+ }
+ };
+
+ /**
+ * @param {boolean=} boot = false
+ */
+
+
+ AppUser.prototype.folderInformationMultiply = function folderInformationMultiply() {
+ var _this6 = this;
+
+ var boot = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
+
+
+ var folders = _Folder2.default.getNextFolderNames();
+ if (_Utils2.default.isNonEmptyArray(folders)) {
+ _Ajax2.default.folderInformationMultiply(function (sResult, oData) {
+ if (Enums.StorageResultType.Success === sResult) {
+ if (oData && oData.Result && oData.Result.List && _Utils2.default.isNonEmptyArray(oData.Result.List)) {
+ (function () {
+ var utc = _Momentor2.default.momentNowUnix();
+ _common._.each(oData.Result.List, function (oItem) {
+
+ var sHash = _Cache2.default.getFolderHash(oItem.Folder),
+ oFolder = _Cache2.default.getFolderFromCacheList(oItem.Folder),
+ bUnreadCountChange = false;
+
+ if (oFolder) {
+ oFolder.interval = utc;
+
+ if (oItem.Hash) {
+ _Cache2.default.setFolderHash(oItem.Folder, oItem.Hash);
+ }
+
+ if (_Utils2.default.isNormal(oItem.MessageCount)) {
+ oFolder.messageCountAll(oItem.MessageCount);
+ }
+
+ if (_Utils2.default.isNormal(oItem.MessageUnseenCount)) {
+ if (_Utils2.default.pInt(oFolder.messageCountUnread()) !== _Utils2.default.pInt(oItem.MessageUnseenCount)) {
+ bUnreadCountChange = true;
+ }
+
+ oFolder.messageCountUnread(oItem.MessageUnseenCount);
+ }
+
+ if (bUnreadCountChange) {
+ _Cache2.default.clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw);
+ }
+
+ if (oItem.Hash !== sHash || '' === sHash) {
+ if (oFolder.fullNameRaw === _Folder2.default.currentFolderFullNameRaw()) {
+ _this6.reloadMessageList();
+ }
+ } else if (bUnreadCountChange) {
+ if (oFolder.fullNameRaw === _Folder2.default.currentFolderFullNameRaw()) {
+ var aList = _Message2.default.messageList();
+ if (_Utils2.default.isNonEmptyArray(aList)) {
+ _this6.folderInformation(oFolder.fullNameRaw, aList);
+ }
+ }
+ }
+ }
+ });
+
+ if (boot) {
+ _common._.delay(function () {
+ return _this6.folderInformationMultiply(true);
+ }, 2000);
+ }
+ })();
+ }
+ }
+ }, folders);
+ }
+ };
+
+ /**
+ * @param {string} sFolderFullNameRaw
+ * @param {string|bool} mUid
+ * @param {number} iSetAction
+ * @param {Array=} aMessages = null
+ */
+
+
+ AppUser.prototype.messageListAction = function messageListAction(sFolderFullNameRaw, mUid, iSetAction, aMessages) {
+
+ var oFolder = null,
+ aRootUids = [],
+ iAlreadyUnread = 0;
+
+ if (_Utils2.default.isUnd(aMessages)) {
+ aMessages = _Message2.default.messageListChecked();
+ }
+
+ aRootUids = _common._.uniq(_common._.compact(_common._.map(aMessages, function (oMessage) {
+ return oMessage && oMessage.uid ? oMessage.uid : null;
+ })));
+
+ if ('' !== sFolderFullNameRaw && 0 < aRootUids.length) {
+ switch (iSetAction) {
+ case Enums.MessageSetAction.SetSeen:
+
+ _common._.each(aRootUids, function (sSubUid) {
+ iAlreadyUnread += _Cache2.default.storeMessageFlagsToCacheBySetAction(sFolderFullNameRaw, sSubUid, iSetAction);
+ });
+
+ oFolder = _Cache2.default.getFolderFromCacheList(sFolderFullNameRaw);
+ if (oFolder) {
+ oFolder.messageCountUnread(oFolder.messageCountUnread() - iAlreadyUnread);
+ }
+
+ _Ajax2.default.messageSetSeen(_Utils2.default.emptyFunction, sFolderFullNameRaw, aRootUids, true);
+ break;
+
+ case Enums.MessageSetAction.UnsetSeen:
+
+ _common._.each(aRootUids, function (sSubUid) {
+ iAlreadyUnread += _Cache2.default.storeMessageFlagsToCacheBySetAction(sFolderFullNameRaw, sSubUid, iSetAction);
+ });
+
+ oFolder = _Cache2.default.getFolderFromCacheList(sFolderFullNameRaw);
+ if (oFolder) {
+ oFolder.messageCountUnread(oFolder.messageCountUnread() - iAlreadyUnread + aRootUids.length);
+ }
+
+ _Ajax2.default.messageSetSeen(_Utils2.default.emptyFunction, sFolderFullNameRaw, aRootUids, false);
+ break;
+
+ case Enums.MessageSetAction.SetFlag:
+
+ _common._.each(aRootUids, function (sSubUid) {
+ _Cache2.default.storeMessageFlagsToCacheBySetAction(sFolderFullNameRaw, sSubUid, iSetAction);
+ });
+
+ _Ajax2.default.messageSetFlagged(_Utils2.default.emptyFunction, sFolderFullNameRaw, aRootUids, true);
+ break;
+
+ case Enums.MessageSetAction.UnsetFlag:
+
+ _common._.each(aRootUids, function (sSubUid) {
+ _Cache2.default.storeMessageFlagsToCacheBySetAction(sFolderFullNameRaw, sSubUid, iSetAction);
+ });
+
+ _Ajax2.default.messageSetFlagged(_Utils2.default.emptyFunction, sFolderFullNameRaw, aRootUids, false);
+ break;
+ }
+
+ this.reloadFlagsCurrentMessageListAndMessageFromCache();
+ _Message2.default.message.viewTrigger(!_Message2.default.message.viewTrigger());
+ }
+ };
+
+ AppUser.prototype.googleConnect = function googleConnect() {
+ _common.window.open(_Links2.default.socialGoogle(), 'Google', 'left=200,top=100,width=650,height=600,menubar=no,status=no,resizable=yes,scrollbars=yes');
+ };
+
+ AppUser.prototype.twitterConnect = function twitterConnect() {
+ _common.window.open(_Links2.default.socialTwitter(), 'Twitter', 'left=200,top=100,width=650,height=350,menubar=no,status=no,resizable=yes,scrollbars=yes');
+ };
+
+ AppUser.prototype.facebookConnect = function facebookConnect() {
+ _common.window.open(_Links2.default.socialFacebook(), 'Facebook', 'left=200,top=100,width=650,height=335,menubar=no,status=no,resizable=yes,scrollbars=yes');
+ };
+
+ /**
+ * @param {boolean=} fireAllActions = false
+ */
+
+
+ AppUser.prototype.socialUsers = function socialUsers() {
+ var fireAllActions = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
+
+ if (true === fireAllActions) {
+ _Social2.default.google.loading(true);
+ _Social2.default.facebook.loading(true);
+ _Social2.default.twitter.loading(true);
+ }
+
+ _Ajax2.default.socialUsers(function (result, data) {
+
+ if (Enums.StorageResultType.Success === result && data && data.Result) {
+ _Social2.default.google.userName(data.Result.Google || '');
+ _Social2.default.facebook.userName(data.Result.Facebook || '');
+ _Social2.default.twitter.userName(data.Result.Twitter || '');
+ } else {
+ _Social2.default.google.userName('');
+ _Social2.default.facebook.userName('');
+ _Social2.default.twitter.userName('');
+ }
+
+ _Social2.default.google.loading(false);
+ _Social2.default.facebook.loading(false);
+ _Social2.default.twitter.loading(false);
+ });
+ };
+
+ AppUser.prototype.googleDisconnect = function googleDisconnect() {
+ _Social2.default.google.loading(true);
+ _Ajax2.default.googleDisconnect(this.socialUsers);
+ };
+
+ AppUser.prototype.facebookDisconnect = function facebookDisconnect() {
+ _Social2.default.facebook.loading(true);
+ _Ajax2.default.facebookDisconnect(this.socialUsers);
+ };
+
+ AppUser.prototype.twitterDisconnect = function twitterDisconnect() {
+ _Social2.default.twitter.loading(true);
+ _Ajax2.default.twitterDisconnect(this.socialUsers);
+ };
+
+ /**
+ * @param {string} query
+ * @param {Function} callback
+ */
+
+
+ AppUser.prototype.getAutocomplete = function getAutocomplete(query, callback) {
+ _Ajax2.default.suggestions(function (result, data) {
+ if (Enums.StorageResultType.Success === result && data && _Utils2.default.isArray(data.Result)) {
+ callback(_common._.compact(_common._.map(data.Result, function (item) {
+ return item && item[0] ? new _Email2.default(item[0], item[1]) : null;
+ })));
+ } else if (Enums.StorageResultType.Abort !== result) {
+ callback([]);
+ }
+ }, query);
+ };
+
+ /**
+ * @param {string} sFullNameHash
+ * @param {boolean} bExpanded
+ */
+
+
+ AppUser.prototype.setExpandedFolder = function setExpandedFolder(sFullNameHash, bExpanded) {
+ var aExpandedList = _Client2.default.get(Enums.ClientSideKeyName.ExpandedFolders);
+ if (!_Utils2.default.isArray(aExpandedList)) {
+ aExpandedList = [];
+ }
+
+ if (bExpanded) {
+ aExpandedList.push(sFullNameHash);
+ aExpandedList = _common._.uniq(aExpandedList);
+ } else {
+ aExpandedList = _common._.without(aExpandedList, sFullNameHash);
+ }
+
+ _Client2.default.set(Enums.ClientSideKeyName.ExpandedFolders, aExpandedList);
+ };
+
+ AppUser.prototype.initHorizontalLayoutResizer = function initHorizontalLayoutResizer(sClientSideKeyName) {
+
+ var iMinHeight = 200,
+ iMaxHeight = 500,
+ oTop = null,
+ oBottom = null,
+ fSetHeight = function fSetHeight(height) {
+ if (height) {
+ if (oTop) {
+ oTop.attr('style', 'height:' + height + 'px');
+ }
+
+ if (oBottom) {
+ oBottom.attr('style', 'top:' + (55 /* top toolbar */ + height) + 'px');
+ }
+ }
+ },
+ fResizeCreateFunction = function fResizeCreateFunction(event) {
+ if (event && event.target) {
+ var oResizableHandle = (0, _common.$)(event.target).find('.ui-resizable-handle');
+
+ oResizableHandle.on('mousedown', function () {
+ _Globals2.default.$html.addClass('rl-resizer');
+ }).on('mouseup', function () {
+ _Globals2.default.$html.removeClass('rl-resizer');
+ });
+ }
+ },
+ fResizeStartFunction = function fResizeStartFunction() {
+ _Globals2.default.$html.addClass('rl-resizer');
+ },
+ fResizeResizeFunction = _common._.debounce(function () {
+ _Globals2.default.$html.addClass('rl-resizer');
+ }, 500, true),
+ fResizeStopFunction = function fResizeStopFunction(oEvent, oObject) {
+ _Globals2.default.$html.removeClass('rl-resizer');
+ if (oObject && oObject.size && oObject.size.height) {
+ _Client2.default.set(sClientSideKeyName, oObject.size.height);
+
+ fSetHeight(oObject.size.height);
+
+ _Utils2.default.windowResize();
+ }
+ },
+ oOptions = {
+ helper: 'ui-resizable-helper-h',
+ minHeight: iMinHeight,
+ maxHeight: iMaxHeight,
+ handles: 's',
+ create: fResizeCreateFunction,
+ resize: fResizeResizeFunction,
+ start: fResizeStartFunction,
+ stop: fResizeStopFunction
+ },
+ fDisable = function fDisable(bDisable) {
+ if (bDisable) {
+ if (oTop && oTop.hasClass('ui-resizable')) {
+ oTop.resizable('destroy').removeAttr('style');
+ }
+
+ if (oBottom) {
+ oBottom.removeAttr('style');
+ }
+ } else if (_Globals2.default.$html.hasClass('rl-bottom-preview-pane')) {
+ oTop = (0, _common.$)('.b-message-list-wrapper');
+ oBottom = (0, _common.$)('.b-message-view-wrapper');
+
+ if (!oTop.hasClass('ui-resizable')) {
+ oTop.resizable(oOptions);
+ }
+
+ var iHeight = _Utils2.default.pInt(_Client2.default.get(sClientSideKeyName)) || 300;
+ fSetHeight(iHeight > iMinHeight ? iHeight : iMinHeight);
+ }
+ };
+
+ fDisable(false);
+
+ _Events2.default.sub('layout', function (layout) {
+ fDisable(Enums.Layout.BottomPreview !== layout);
+ });
+ };
+
+ AppUser.prototype.initVerticalLayoutResizer = function initVerticalLayoutResizer(sClientSideKeyName) {
+
+ var iDisabledWidth = 60,
+ iMinWidth = 155,
+ oLeft = (0, _common.$)('#rl-left'),
+ oRight = (0, _common.$)('#rl-right'),
+ mLeftWidth = _Client2.default.get(sClientSideKeyName) || null,
+ fSetWidth = function fSetWidth(iWidth) {
+ if (iWidth) {
+ _Globals2.default.leftPanelWidth(iWidth);
+
+ _Globals2.default.$html.removeClass('rl-resizer');
+
+ oLeft.css({
+ width: '' + iWidth + 'px'
+ });
+
+ oRight.css({
+ left: '' + iWidth + 'px'
+ });
+ }
+ },
+ fDisable = function fDisable(bDisable) {
+ if (bDisable) {
+ oLeft.resizable('disable');
+ fSetWidth(iDisabledWidth);
+ } else {
+ oLeft.resizable('enable');
+ var iWidth = _Utils2.default.pInt(_Client2.default.get(sClientSideKeyName)) || iMinWidth;
+ fSetWidth(iWidth > iMinWidth ? iWidth : iMinWidth);
+ }
+ },
+ fResizeCreateFunction = function fResizeCreateFunction(oEvent) {
+ if (oEvent && oEvent.target) {
+ (0, _common.$)(oEvent.target).find('.ui-resizable-handle').on('mousedown', function () {
+ _Globals2.default.$html.addClass('rl-resizer');
+ }).on('mouseup', function () {
+ _Globals2.default.$html.removeClass('rl-resizer');
+ });
+ }
+ },
+ fResizeResizeFunction = _common._.debounce(function () {
+ _Globals2.default.$html.addClass('rl-resizer');
+ }, 500, true),
+ fResizeStartFunction = function fResizeStartFunction() {
+ _Globals2.default.$html.addClass('rl-resizer');
+ },
+ fResizeStopFunction = function fResizeStopFunction(oEvent, oObject) {
+ _Globals2.default.$html.removeClass('rl-resizer');
+ if (oObject && oObject.size && oObject.size.width) {
+ _Client2.default.set(sClientSideKeyName, oObject.size.width);
+
+ _Globals2.default.leftPanelWidth(oObject.size.width);
+
+ oRight.css({
+ left: '' + oObject.size.width + 'px'
+ });
+
+ oLeft.css({
+ position: '',
+ top: '',
+ left: '',
+ height: ''
+ });
+ }
+ };
+
+ if (null !== mLeftWidth) {
+ fSetWidth(mLeftWidth > iMinWidth ? mLeftWidth : iMinWidth);
+ }
+
+ oLeft.resizable({
+ helper: 'ui-resizable-helper-w',
+ minWidth: iMinWidth,
+ maxWidth: 350,
+ handles: 'e',
+ create: fResizeCreateFunction,
+ resize: fResizeResizeFunction,
+ start: fResizeStartFunction,
+ stop: fResizeStopFunction
+ });
+
+ _Events2.default.sub('left-panel.off', function () {
+ fDisable(true);
+ });
+
+ _Events2.default.sub('left-panel.on', function () {
+ fDisable(false);
+ });
+ };
+
+ AppUser.prototype.logout = function logout() {
+ var _this7 = this;
+
+ _Ajax2.default.logout(function () {
+ _this7.loginAndLogoutReload(false, true, _Settings4.default.settingsGet('ParentEmail') && 0 < _Settings4.default.settingsGet('ParentEmail').length);
+ });
+ };
+
+ AppUser.prototype.bootstartTwoFactorScreen = function bootstartTwoFactorScreen() {
+ _Knoin2.default.showScreenPopup(__webpack_require__(/*! View/Popup/TwoFactorConfiguration */ 98), [true]);
+ };
+
+ AppUser.prototype.bootstartWelcomePopup = function bootstartWelcomePopup(url) {
+ _Knoin2.default.showScreenPopup(__webpack_require__(/*! View/Popup/WelcomePage */ 152), [url]);
+ };
+
+ AppUser.prototype.bootstartLoginScreen = function bootstartLoginScreen() {
+
+ _Globals2.default.$html.removeClass('rl-user-auth').addClass('rl-user-no-auth');
+
+ var customLoginLink = _Utils2.default.pString(_Settings4.default.appSettingsGet('customLoginLink'));
+ if (!customLoginLink) {
+ _Knoin2.default.startScreens([__webpack_require__(/*! Screen/User/Login */ 115)]);
+
+ _Plugins2.default.runHook('rl-start-login-screens');
+ _Events2.default.pub('rl.bootstart-login-screens');
+ } else {
+ _Knoin2.default.routeOff();
+ _Knoin2.default.setHash(_Links2.default.root(), true);
+ _Knoin2.default.routeOff();
+
+ _common._.defer(function () {
+ _common.window.location.href = customLoginLink;
+ });
+ }
+ };
+
+ AppUser.prototype.bootend = function bootend() {
+ if (_progressJs2.default) {
+ _Knoin2.default.hideLoading();
+
+ _progressJs2.default.onbeforeend(function () {
+ (0, _common.$)('.progressjs-container').hide();
+ _common._.delay(function () {
+ (0, _common.$)('.progressjs-container').remove();
+ }, 100);
+ });
+
+ _progressJs2.default.set(100).end();
+ } else {
+ _Knoin2.default.hideLoading();
+ }
+ };
+
+ AppUser.prototype.bootstart = function bootstart() {
+ var _this8 = this;
+
+ _AbstractApp.prototype.bootstart.call(this);
+
+ __webpack_require__(/*! Stores/User/App */ 24).populate();
+ __webpack_require__(/*! Stores/User/Settings */ 28).populate();
+ __webpack_require__(/*! Stores/User/Notification */ 60).populate();
+ __webpack_require__(/*! Stores/User/Account */ 31).populate();
+ __webpack_require__(/*! Stores/User/Contact */ 51).populate();
+
+ var $LAB = __webpack_require__(/*! $LAB */ 170),
+ sJsHash = _Settings4.default.appSettingsGet('jsHash'),
+ sStartupUrl = _Utils2.default.pString(_Settings4.default.settingsGet('StartupUrl')),
+ iContactsSyncInterval = _Utils2.default.pInt(_Settings4.default.settingsGet('ContactsSyncInterval')),
+ bGoogle = _Settings4.default.settingsGet('AllowGoogleSocial'),
+ bFacebook = _Settings4.default.settingsGet('AllowFacebookSocial'),
+ bTwitter = _Settings4.default.settingsGet('AllowTwitterSocial');
+
+ if (_progressJs2.default) {
+ _progressJs2.default.set(90);
+ }
+
+ _Globals2.default.leftPanelDisabled.subscribe(function (value) {
+ _Events2.default.pub('left-panel.' + (value ? 'off' : 'on'));
+ });
+
+ this.setWindowTitle('');
+ if (_Settings4.default.settingsGet('Auth')) {
+ _Globals2.default.$html.addClass('rl-user-auth');
+
+ if (_Settings4.default.capa(Enums.Capa.TwoFactor) && _Settings4.default.capa(Enums.Capa.TwoFactorForce) && _Settings4.default.settingsGet('RequireTwoFactor')) {
+ this.bootend();
+ this.bootstartTwoFactorScreen();
+ } else {
+ this.setWindowTitle(_Translator2.default.i18n('TITLES/LOADING'));
+
+ // require.ensure([], function() { // require code splitting
+
+ this.foldersReload(function (value) {
+
+ _this8.bootend();
+
+ if (value) {
+ if ('' !== sStartupUrl) {
+ _Knoin2.default.routeOff();
+ _Knoin2.default.setHash(_Links2.default.root(sStartupUrl), true);
+ _Knoin2.default.routeOn();
+ }
+
+ if ($LAB && _common.window.crypto && _common.window.crypto.getRandomValues && _Settings4.default.capa(Enums.Capa.OpenPGP)) {
+ (function () {
+ var openpgpCallback = function openpgpCallback(openpgp) {
+
+ _Pgp2.default.openpgp = openpgp;
+
+ if (_common.window.Worker) {
+ try {
+ // PgpStore.openpgp.initWorker(Links.openPgpWorkerJs()); // 1.2.0
+ _Pgp2.default.openpgp.initWorker({ path: _Links2.default.openPgpWorkerJs() }); // 2.3.0
+ } catch (e) {
+ _Utils2.default.log(e);
+ }
+ }
+
+ _Pgp2.default.openpgpKeyring = new openpgp.Keyring();
+ _Pgp2.default.capaOpenPGP(true);
+
+ _Events2.default.pub('openpgp.init');
+
+ _this8.reloadOpenPgpKeys();
+ };
+
+ if (_common.window.openpgp) {
+ openpgpCallback(_common.window.openpgp);
+ } else {
+ $LAB.script(_Links2.default.openPgpJs()).wait(function () {
+ if (_common.window.openpgp) {
+ openpgpCallback(_common.window.openpgp);
+ }
+ });
+ }
+ })();
+ } else {
+ _Pgp2.default.capaOpenPGP(false);
+ }
+
+ _Knoin2.default.startScreens([__webpack_require__(/*! Screen/User/MailBox */ 116), _Settings4.default.capa(Enums.Capa.Settings) ? __webpack_require__(/*! Screen/User/Settings */ 117) : null
+ // false ? require('Screen/User/About') : null
+ ]);
+
+ if (bGoogle || bFacebook || bTwitter) {
+ _this8.socialUsers(true);
+ }
+
+ _Events2.default.sub('interval.2m', function () {
+ return _this8.folderInformation(_Cache2.default.getFolderInboxName());
+ });
+ _Events2.default.sub('interval.3m', function () {
+ var sF = _Folder2.default.currentFolderFullNameRaw();
+ if (_Cache2.default.getFolderInboxName() !== sF) {
+ _this8.folderInformation(sF);
+ }
+ });
+
+ _Events2.default.sub('interval.2m-after5m', function () {
+ return _this8.folderInformationMultiply();
+ });
+ _Events2.default.sub('interval.15m', function () {
+ return _this8.quota();
+ });
+ _Events2.default.sub('interval.20m', function () {
+ return _this8.foldersReload();
+ });
+
+ iContactsSyncInterval = 5 <= iContactsSyncInterval ? iContactsSyncInterval : 20;
+ iContactsSyncInterval = 320 >= iContactsSyncInterval ? iContactsSyncInterval : 320;
+
+ _common._.delay(function () {
+ return _this8.contactsSync();
+ }, 10000);
+ _common._.delay(function () {
+ return _this8.folderInformationMultiply(true);
+ }, 2000);
+
+ _common.window.setInterval(function () {
+ return _this8.contactsSync();
+ }, iContactsSyncInterval * 60000 + 5000);
+
+ _this8.accountsAndIdentities(true);
+
+ _common._.delay(function () {
+ var sF = _Folder2.default.currentFolderFullNameRaw();
+ if (_Cache2.default.getFolderInboxName() !== sF) {
+ _this8.folderInformation(sF);
+ }
+ }, 1000);
+
+ _common._.delay(function () {
+ return _this8.quota();
+ }, 5000);
+ _common._.delay(function () {
+ return _Ajax2.default.appDelayStart(_Utils2.default.emptyFunction);
+ }, 35000);
+
+ _Events2.default.sub('rl.auto-logout', function () {
+ return _this8.logout();
+ });
+
+ _Plugins2.default.runHook('rl-start-user-screens');
+ _Events2.default.pub('rl.bootstart-user-screens');
+
+ if (_Settings4.default.settingsGet('WelcomePageUrl')) {
+ _common._.delay(function () {
+ return _this8.bootstartWelcomePopup(_Settings4.default.settingsGet('WelcomePageUrl'));
+ }, 1000);
+ }
+
+ if (!!_Settings4.default.settingsGet('AccountSignMe') && _common.window.navigator.registerProtocolHandler && _Settings4.default.capa(Enums.Capa.Composer)) {
+ _common._.delay(function () {
+ try {
+ _common.window.navigator.registerProtocolHandler('mailto', _common.window.location.protocol + '//' + _common.window.location.host + _common.window.location.pathname + '?mailto&to=%s', '' + (_Settings4.default.settingsGet('Title') || 'RainLoop'));
+ } catch (e) {/* eslint-disable-line no-empty */}
+
+ if (_Settings4.default.settingsGet('MailToEmail')) {
+ _Utils2.default.mailToHelper(_Settings4.default.settingsGet('MailToEmail'), __webpack_require__(/*! View/Popup/Compose */ 29));
+ }
+ }, 500);
+ }
+
+ if (!_Globals2.default.bMobileDevice) {
+ _common._.defer(function () {
+ return _this8.initVerticalLayoutResizer(Enums.ClientSideKeyName.FolderListSize);
+ });
+
+ if (_Tinycon2.default && _Settings4.default.appSettingsGet('faviconStatus') && !_Settings4.default.appSettingsGet('listPermanentFiltered')) {
+ _Tinycon2.default.setOptions({
+ fallback: false
+ });
+
+ _Events2.default.sub('mailbox.inbox-unread-count', function (iCount) {
+ return _Tinycon2.default.setBubble(0 < iCount ? 99 < iCount ? 99 : iCount : 0);
+ });
+ }
+ }
+ } else {
+ _this8.logout();
+ }
+ });
+
+ // }); // require code splitting
+ }
+ } else {
+ this.bootend();
+ this.bootstartLoginScreen();
+ }
+
+ if (bGoogle) {
+ _common.window['rl_' + sJsHash + '_google_service'] = function () {
+ _Social2.default.google.loading(true);
+ _this8.socialUsers();
+ };
+ }
+
+ if (bFacebook) {
+ _common.window['rl_' + sJsHash + '_facebook_service'] = function () {
+ _Social2.default.facebook.loading(true);
+ _this8.socialUsers();
+ };
+ }
+
+ if (bTwitter) {
+ _common.window['rl_' + sJsHash + '_twitter_service'] = function () {
+ _Social2.default.twitter.loading(true);
+ _this8.socialUsers();
+ };
+ }
+
+ _Events2.default.sub('interval.1m', function () {
+ return _Momentor2.default.reload();
+ });
+
+ _Plugins2.default.runHook('rl-start-screens');
+ _Events2.default.pub('rl.bootstart-end');
+ };
+
+ return AppUser;
+ }(_Abstract.AbstractApp);
+
+ exports.default = new AppUser();
+
+/***/ },
+/* 8 */
+/*!*******************************!*\
+ !*** ./dev/Common/Globals.js ***!
+ \*******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ /* global RL_COMMUNITY */
+
+ (function () {
+
+ 'use strict';
+
+ var
+ Globals = {},
+
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+ key = __webpack_require__(/*! key */ 18),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4)
+ ;
+
+ Globals.$win = $(window);
+ Globals.$doc = $(window.document);
+ Globals.$html = $('html');
+ Globals.$body = $('body');
+ Globals.$div = $('
');
+
+ Globals.$win.__sizes = [0, 0];
+
+ /**
+ * @type {?}
+ */
+ Globals.startMicrotime = (new window.Date()).getTime();
+
+ /**
+ * @type {boolean}
+ */
+ Globals.community = (true);
+
+ /**
+ * @type {?}
+ */
+ Globals.dropdownVisibility = ko.observable(false).extend({'rateLimit': 0});
+
+ /**
+ * @type {boolean}
+ */
+ Globals.useKeyboardShortcuts = ko.observable(true);
+
+ /**
+ * @type {number}
+ */
+ Globals.iAjaxErrorCount = 0;
+
+ /**
+ * @type {number}
+ */
+ Globals.iTokenErrorCount = 0;
+
+ /**
+ * @type {number}
+ */
+ Globals.iMessageBodyCacheCount = 0;
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bUnload = false;
+
+ /**
+ * @type {string}
+ */
+ Globals.sUserAgent = 'navigator' in window && 'userAgent' in window.navigator &&
+ window.navigator.userAgent.toLowerCase() || '';
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bIE = Globals.sUserAgent.indexOf('msie') > -1;
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bChrome = Globals.sUserAgent.indexOf('chrome') > -1;
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bSafari = !Globals.bChrome && Globals.sUserAgent.indexOf('safari') > -1;
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bMobileDevice =
+ /android/i.test(Globals.sUserAgent) ||
+ /iphone/i.test(Globals.sUserAgent) ||
+ /ipod/i.test(Globals.sUserAgent) ||
+ /ipad/i.test(Globals.sUserAgent) ||
+ /blackberry/i.test(Globals.sUserAgent)
+ ;
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bDisableNanoScroll = Globals.bMobileDevice;
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bAllowPdfPreview = !Globals.bMobileDevice;
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bAnimationSupported = !Globals.bMobileDevice &&
+ Globals.$html.hasClass('csstransitions') &&
+ Globals.$html.hasClass('cssanimations');
+
+ /**
+ * @type {boolean}
+ */
+ Globals.bXMLHttpRequestSupported = !!window.XMLHttpRequest;
+
+ /**
+ * @type {*}
+ */
+ Globals.__APP__ = null;
+
+ /**
+ * @type {Object}
+ */
+ Globals.oHtmlEditorDefaultConfig = {
+ 'title': false,
+ 'stylesSet': false,
+ 'customConfig': '',
+ 'contentsCss': '',
+ 'toolbarGroups': [
+ {name: 'spec'},
+ {name: 'styles'},
+ {name: 'basicstyles', groups: ['basicstyles', 'cleanup', 'bidi']},
+ {name: 'colors'},
+ Globals.bMobileDevice ? {} : {name: 'paragraph', groups: ['list', 'indent', 'blocks', 'align']},
+ {name: 'links'},
+ {name: 'insert'},
+ {name: 'document', groups: ['mode', 'document', 'doctools']},
+ {name: 'others'}
+ ],
+
+ 'removePlugins': 'liststyle',
+ 'removeButtons': 'Format,Undo,Redo,Cut,Copy,Paste,Anchor,Strike,Subscript,Superscript,Image,SelectAll,Source',
+ 'removeDialogTabs': 'link:advanced;link:target;image:advanced;images:advanced',
+
+ 'extraPlugins': 'plain,signature',
+
+ 'allowedContent': true,
+ 'extraAllowedContent': true,
+
+ 'fillEmptyBlocks': false,
+ 'ignoreEmptyParagraph': true,
+ 'disableNativeSpellChecker': false,
+
+ 'font_defaultLabel': 'Arial',
+ 'fontSize_defaultLabel': '13',
+ 'fontSize_sizes': '10/10px;12/12px;13/13px;14/14px;16/16px;18/18px;20/20px;24/24px;28/28px;36/36px;48/48px'
+ };
+
+ /**
+ * @type {Object}
+ */
+ Globals.oHtmlEditorLangsMap = {
+ 'bg_bg': 'bg',
+ 'de_de': 'de',
+ 'el_gr': 'el',
+ 'es_es': 'es',
+ 'fr_fr': 'fr',
+ 'hu_hu': 'hu',
+ 'is_is': 'is',
+ 'it_it': 'it',
+ 'ja_jp': 'ja',
+ 'ko_kr': 'ko',
+ 'lt_lt': 'lt',
+ 'lv_lv': 'lv',
+ 'nl_nl': 'nl',
+ 'bg_no': 'no',
+ 'pl_pl': 'pl',
+ 'pt_pt': 'pt',
+ 'pt_br': 'pt-br',
+ 'ro_ro': 'ro',
+ 'ru_ru': 'ru',
+ 'sk_sk': 'sk',
+ 'sl_si': 'sl',
+ 'sv_se': 'sv',
+ 'tr_tr': 'tr',
+ 'uk_ua': 'ru',
+ 'zh_tw': 'zh',
+ 'zh_cn': 'zh-cn'
+ };
+
+ if (Globals.bAllowPdfPreview && window.navigator && window.navigator.mimeTypes)
+ {
+ Globals.bAllowPdfPreview = !!_.find(window.navigator.mimeTypes, function (oType) {
+ return oType && 'application/pdf' === oType.type;
+ });
+
+ if (!Globals.bAllowPdfPreview)
+ {
+ Globals.bAllowPdfPreview = (typeof window.navigator.mimeTypes['application/pdf'] !== 'undefined');
+ }
+ }
+
+ Globals.aBootstrapDropdowns = [];
+
+ Globals.aViewModels = {
+ 'settings': [],
+ 'settings-removed': [],
+ 'settings-disabled': []
+ };
+
+ Globals.leftPanelDisabled = ko.observable(false);
+ Globals.leftPanelType = ko.observable('');
+ Globals.leftPanelWidth = ko.observable(0);
+
+ // popups
+ Globals.popupVisibilityNames = ko.observableArray([]);
+
+ Globals.popupVisibility = ko.computed(function () {
+ return 0 < Globals.popupVisibilityNames().length;
+ }, this);
+
+ Globals.popupVisibility.subscribe(function (bValue) {
+ Globals.$html.toggleClass('rl-modal', bValue);
+ });
+
+ // keys
+ Globals.keyScopeReal = ko.observable(Enums.KeyState.All);
+ Globals.keyScopeFake = ko.observable(Enums.KeyState.All);
+
+ Globals.keyScope = ko.computed({
+ 'owner': this,
+ 'read': function () {
+ return Globals.keyScopeFake();
+ },
+ 'write': function (sValue) {
+
+ if (Enums.KeyState.Menu !== sValue)
+ {
+ if (Enums.KeyState.Compose === sValue)
+ {
+ // disableKeyFilter
+ key.filter = function () {
+ return Globals.useKeyboardShortcuts();
+ };
+ }
+ else
+ {
+ // restoreKeyFilter
+ key.filter = function (event) {
+
+ if (Globals.useKeyboardShortcuts())
+ {
+ var
+ oElement = event.target || event.srcElement,
+ sTagName = oElement ? oElement.tagName : ''
+ ;
+
+ sTagName = sTagName.toUpperCase();
+ return !(sTagName === 'INPUT' || sTagName === 'SELECT' || sTagName === 'TEXTAREA' ||
+ (oElement && sTagName === 'DIV' && ('editorHtmlArea' === oElement.className || 'true' === '' + oElement.contentEditable))
+ );
+ }
+
+ return false;
+ };
+ }
+
+ Globals.keyScopeFake(sValue);
+ if (Globals.dropdownVisibility())
+ {
+ sValue = Enums.KeyState.Menu;
+ }
+ }
+
+ Globals.keyScopeReal(sValue);
+ }
+ });
+
+ Globals.keyScopeReal.subscribe(function (sValue) {
+ // window.console.log('keyScope=' + sValue); // DEBUG
+ key.setScope(sValue);
+ });
+
+ Globals.dropdownVisibility.subscribe(function (bValue) {
+ if (bValue)
+ {
+ Globals.keyScope(Enums.KeyState.Menu);
+ }
+ else if (Enums.KeyState.Menu === key.getScope())
+ {
+ Globals.keyScope(Globals.keyScopeFake());
+ }
+ });
+
+ module.exports = Globals;
+
+ }());
+
+/***/ },
+/* 9 */
+/*!**********************************!*\
+ !*** ./dev/Storage/Settings.jsx ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var SettingsStorage = function () {
+ function SettingsStorage() {
+ _classCallCheck(this, SettingsStorage);
+
+ this.settings = {};
+ this.appSettings = {};
+
+ this.settings = _common.window.rainloopAppData || {};
+ this.settings = _Utils2.default.isNormal(this.settings) ? this.settings : {};
+
+ this.appSettings = this.settings.System || null;
+ this.appSettings = _Utils2.default.isNormal(this.appSettings) ? this.appSettings : {};
+ }
+
+ /**
+ * @param {string} name
+ * @return {*}
+ */
+
+
+ SettingsStorage.prototype.settingsGet = function settingsGet(name) {
+ return _Utils2.default.isUnd(this.settings[name]) ? null : this.settings[name];
+ };
+
+ /**
+ * @param {string} name
+ * @param {*} value
+ */
+
+
+ SettingsStorage.prototype.settingsSet = function settingsSet(name, value) {
+ this.settings[name] = value;
+ };
+
+ /**
+ * @param {string} name
+ * @return {*}
+ */
+
+
+ SettingsStorage.prototype.appSettingsGet = function appSettingsGet(name) {
+ return _Utils2.default.isUnd(this.appSettings[name]) ? null : this.appSettings[name];
+ };
+
+ /**
+ * @param {string} name
+ * @return {boolean}
+ */
+
+
+ SettingsStorage.prototype.capa = function capa(name) {
+ var values = this.settingsGet('Capa');
+ return _Utils2.default.isArray(values) && _Utils2.default.isNormal(name) && -1 < _Utils2.default.inArray(name, values);
+ };
+
+ return SettingsStorage;
+ }();
+
+ module.exports = new SettingsStorage();
+
+/***/ },
+/* 10 */
+/*!***********************************!*\
+ !*** ./dev/Knoin/AbstractView.js ***!
+ \***********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Globals = __webpack_require__(/*! Common/Globals */ 8)
+ ;
+
+ /**
+ * @constructor
+ * @param {string=} sPosition = ''
+ * @param {string=} sTemplate = ''
+ */
+ function AbstractView(sPosition, sTemplate)
+ {
+ this.bDisabeCloseOnEsc = false;
+ this.sPosition = Utils.pString(sPosition);
+ this.sTemplate = Utils.pString(sTemplate);
+
+ this.sDefaultKeyScope = Enums.KeyState.None;
+ this.sCurrentKeyScope = this.sDefaultKeyScope;
+
+ this.viewModelVisibility = ko.observable(false);
+ this.modalVisibility = ko.observable(false).extend({'rateLimit': 0});
+
+ this.viewModelName = '';
+ this.viewModelNames = [];
+ this.viewModelDom = null;
+ }
+
+ /**
+ * @type {boolean}
+ */
+ AbstractView.prototype.bDisabeCloseOnEsc = false;
+
+ /**
+ * @type {string}
+ */
+ AbstractView.prototype.sPosition = '';
+
+ /**
+ * @type {string}
+ */
+ AbstractView.prototype.sTemplate = '';
+
+ /**
+ * @type {string}
+ */
+ AbstractView.prototype.sDefaultKeyScope = Enums.KeyState.None;
+
+ /**
+ * @type {string}
+ */
+ AbstractView.prototype.sCurrentKeyScope = Enums.KeyState.None;
+
+ /**
+ * @type {string}
+ */
+ AbstractView.prototype.viewModelName = '';
+
+ /**
+ * @type {Array}
+ */
+ AbstractView.prototype.viewModelNames = [];
+
+ /**
+ * @type {?}
+ */
+ AbstractView.prototype.viewModelDom = null;
+
+ /**
+ * @return {string}
+ */
+ AbstractView.prototype.viewModelTemplate = function ()
+ {
+ return this.sTemplate;
+ };
+
+ /**
+ * @return {string}
+ */
+ AbstractView.prototype.viewModelPosition = function ()
+ {
+ return this.sPosition;
+ };
+
+ AbstractView.prototype.cancelCommand = function () {};
+ AbstractView.prototype.closeCommand = function () {};
+
+ AbstractView.prototype.storeAndSetKeyScope = function ()
+ {
+ this.sCurrentKeyScope = Globals.keyScope();
+ Globals.keyScope(this.sDefaultKeyScope);
+ };
+
+ AbstractView.prototype.restoreKeyScope = function ()
+ {
+ Globals.keyScope(this.sCurrentKeyScope);
+ };
+
+ AbstractView.prototype.registerPopupKeyDown = function ()
+ {
+ var self = this;
+
+ Globals.$win.on('keydown', function (oEvent) {
+ if (oEvent && self.modalVisibility && self.modalVisibility())
+ {
+ if (!this.bDisabeCloseOnEsc && Enums.EventKeyCode.Esc === oEvent.keyCode)
+ {
+ Utils.delegateRun(self, 'cancelCommand');
+ return false;
+ }
+ else if (Enums.EventKeyCode.Backspace === oEvent.keyCode && !Utils.inFocus())
+ {
+ return false;
+ }
+ }
+
+ return true;
+ });
+ };
+
+ module.exports = AbstractView;
+
+ }());
+
+/***/ },
+/* 11 */
+/*!*************************!*\
+ !*** external "window" ***!
+ \*************************/
+/***/ function(module, exports) {
+
+ module.exports = window;
+
+/***/ },
+/* 12 */
+/*!******************************!*\
+ !*** ./dev/Common/Links.jsx ***!
+ \******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var Links = function () {
+ function Links() {
+ _classCallCheck(this, Links);
+
+ this.sBase = '#/';
+ this.sServer = './?';
+
+ this.sVersion = _Settings2.default.appSettingsGet('version');
+ this.sWebPrefix = _Settings2.default.appSettingsGet('webPath') || '';
+ this.sVersionPrefix = _Settings2.default.appSettingsGet('webVersionPath') || 'rainloop/v/' + this.sVersion + '/';
+ this.sAdminPath = _Settings2.default.appSettingsGet('adminPath') || 'admin';
+
+ this.sAuthSuffix = _Settings2.default.settingsGet('AuthAccountHash') || '0';
+
+ this.sStaticPrefix = this.sVersionPrefix + 'static/';
+ }
+
+ Links.prototype.populateAuthSuffix = function populateAuthSuffix() {
+ this.sAuthSuffix = _Settings2.default.settingsGet('AuthAccountHash') || '0';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.subQueryPrefix = function subQueryPrefix() {
+ return '&q[]=';
+ };
+
+ /**
+ * @param {string=} startupUrl
+ * @return {string}
+ */
+
+
+ Links.prototype.root = function root() {
+ var startupUrl = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
+
+ return this.sBase + _Utils2.default.pString(startupUrl);
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.rootAdmin = function rootAdmin() {
+ return this.sServer + this.sAdminPath;
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.rootUser = function rootUser() {
+ var mobile = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
+
+ return mobile ? './?/Mobile/' : './';
+ };
+
+ /**
+ * @param {string} type
+ * @param {string} download
+ * @param {string=} customSpecSuffix
+ * @return {string}
+ */
+
+
+ Links.prototype.attachmentRaw = function attachmentRaw(type, download, customSpecSuffix) {
+ customSpecSuffix = _Utils2.default.isUnd(customSpecSuffix) ? this.sAuthSuffix : customSpecSuffix;
+ return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + customSpecSuffix + '/' + type + '/' + this.subQueryPrefix() + '/' + download;
+ };
+
+ /**
+ * @param {string} download
+ * @param {string=} customSpecSuffix
+ * @return {string}
+ */
+
+
+ Links.prototype.attachmentDownload = function attachmentDownload(download, customSpecSuffix) {
+ return this.attachmentRaw('Download', download, customSpecSuffix);
+ };
+
+ /**
+ * @param {string} download
+ * @param {string=} customSpecSuffix
+ * @return {string}
+ */
+
+
+ Links.prototype.attachmentPreview = function attachmentPreview(download, customSpecSuffix) {
+ return this.attachmentRaw('View', download, customSpecSuffix);
+ };
+
+ /**
+ * @param {string} download
+ * @param {string=} customSpecSuffix
+ * @return {string}
+ */
+
+
+ Links.prototype.attachmentThumbnailPreview = function attachmentThumbnailPreview(download, customSpecSuffix) {
+ return this.attachmentRaw('ViewThumbnail', download, customSpecSuffix);
+ };
+
+ /**
+ * @param {string} download
+ * @param {string=} customSpecSuffix
+ * @return {string}
+ */
+
+
+ Links.prototype.attachmentPreviewAsPlain = function attachmentPreviewAsPlain(download, customSpecSuffix) {
+ return this.attachmentRaw('ViewAsPlain', download, customSpecSuffix);
+ };
+
+ /**
+ * @param {string} download
+ * @param {string=} customSpecSuffix
+ * @return {string}
+ */
+
+
+ Links.prototype.attachmentFramed = function attachmentFramed(download, customSpecSuffix) {
+ return this.attachmentRaw('FramedView', download, customSpecSuffix);
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.upload = function upload() {
+ return this.sServer + '/Upload/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.uploadContacts = function uploadContacts() {
+ return this.sServer + '/UploadContacts/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.uploadBackground = function uploadBackground() {
+ return this.sServer + '/UploadBackground/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.append = function append() {
+ return this.sServer + '/Append/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/';
+ };
+
+ /**
+ * @param {string} email
+ * @return {string}
+ */
+
+
+ Links.prototype.change = function change(email) {
+ return this.sServer + '/Change/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/' + _Utils2.default.encodeURIComponent(email) + '/';
+ };
+
+ /**
+ * @param {string} add
+ * @return {string}
+ */
+
+
+ Links.prototype.ajax = function ajax(add) {
+ return this.sServer + '/Ajax/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/' + add;
+ };
+
+ /**
+ * @param {string} requestHash
+ * @return {string}
+ */
+
+
+ Links.prototype.messageViewLink = function messageViewLink(requestHash) {
+ return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/ViewAsPlain/' + this.subQueryPrefix() + '/' + requestHash;
+ };
+
+ /**
+ * @param {string} requestHash
+ * @return {string}
+ */
+
+
+ Links.prototype.messageDownloadLink = function messageDownloadLink(requestHash) {
+ return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/Download/' + this.subQueryPrefix() + '/' + requestHash;
+ };
+
+ /**
+ * @param {string} email
+ * @return {string}
+ */
+
+
+ Links.prototype.avatarLink = function avatarLink(email) {
+ return this.sServer + '/Raw/0/Avatar/' + _Utils2.default.encodeURIComponent(email) + '/';
+ };
+
+ /**
+ * @param {string} hash
+ * @return {string}
+ */
+
+
+ Links.prototype.publicLink = function publicLink(hash) {
+ return this.sServer + '/Raw/0/Public/' + hash + '/';
+ };
+
+ /**
+ * @param {string} hash
+ * @return {string}
+ */
+
+
+ Links.prototype.userBackground = function userBackground(hash) {
+ return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/UserBackground/' + this.subQueryPrefix() + '/' + hash;
+ };
+
+ /**
+ * @param {string} inboxFolderName = 'INBOX'
+ * @return {string}
+ */
+
+
+ Links.prototype.inbox = function inbox() {
+ var inboxFolderName = arguments.length <= 0 || arguments[0] === undefined ? 'INBOX' : arguments[0];
+
+ return this.sBase + 'mailbox/' + inboxFolderName;
+ };
+
+ /**
+ * @param {string=} screenName
+ * @return {string}
+ */
+
+
+ Links.prototype.settings = function settings() {
+ var screenName = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
+
+ return this.sBase + 'settings' + (screenName ? '/' + screenName : '');
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.about = function about() {
+ return this.sBase + 'about';
+ };
+
+ /**
+ * @param {string} screenName
+ * @return {string}
+ */
+
+
+ Links.prototype.admin = function admin(screenName) {
+ var result = this.sBase;
+ switch (screenName) {
+ case 'AdminDomains':
+ result += 'domains';
+ break;
+ case 'AdminSecurity':
+ result += 'security';
+ break;
+ case 'AdminLicensing':
+ result += 'licensing';
+ break;
+ }
+
+ return result;
+ };
+
+ /**
+ * @param {string} folder
+ * @param {number=} page = 1
+ * @param {string=} search = ''
+ * @param {string=} threadUid = ''
+ * @return {string}
+ */
+
+
+ Links.prototype.mailBox = function mailBox(folder) {
+ var page = arguments.length <= 1 || arguments[1] === undefined ? 1 : arguments[1];
+ var search = arguments.length <= 2 || arguments[2] === undefined ? '' : arguments[2];
+ var threadUid = arguments.length <= 3 || arguments[3] === undefined ? '' : arguments[3];
+
+
+ page = _Utils2.default.isNormal(page) ? _Utils2.default.pInt(page) : 1;
+ search = _Utils2.default.pString(search);
+
+ var result = this.sBase + 'mailbox/';
+
+ if ('' !== folder) {
+ var resultThreadUid = _Utils2.default.pInt(threadUid);
+ result += _common.window.encodeURI(folder) + (0 < resultThreadUid ? '~' + resultThreadUid : '');
+ }
+
+ if (1 < page) {
+ result = result.replace(/[\/]+$/, '');
+ result += '/p' + page;
+ }
+
+ if ('' !== search) {
+ result = result.replace(/[\/]+$/, '');
+ result += '/' + _common.window.encodeURI(search);
+ }
+
+ return result;
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.phpInfo = function phpInfo() {
+ return this.sServer + 'Info';
+ };
+
+ /**
+ * @param {string} lang
+ * @param {boolean} admin
+ * @return {string}
+ */
+
+
+ Links.prototype.langLink = function langLink(lang, admin) {
+ return this.sServer + '/Lang/0/' + (admin ? 'Admin' : 'App') + '/' + _common.window.encodeURI(lang) + '/' + this.sVersion + '/';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.exportContactsVcf = function exportContactsVcf() {
+ return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/ContactsVcf/';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.exportContactsCsv = function exportContactsCsv() {
+ return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/ContactsCsv/';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.emptyContactPic = function emptyContactPic() {
+ return this.sStaticPrefix + 'css/images/empty-contact.png';
+ };
+
+ /**
+ * @param {string} fileName
+ * @return {string}
+ */
+
+
+ Links.prototype.sound = function sound(fileName) {
+ return this.sStaticPrefix + 'sounds/' + fileName;
+ };
+
+ /**
+ * @param {string} theme
+ * @return {string}
+ */
+
+
+ Links.prototype.themePreviewLink = function themePreviewLink(theme) {
+ var prefix = this.sVersionPrefix;
+ if ('@custom' === theme.substr(-7)) {
+ theme = _Utils2.default.trim(theme.substring(0, theme.length - 7));
+ prefix = this.sWebPrefix;
+ }
+
+ return prefix + 'themes/' + _common.window.encodeURI(theme) + '/images/preview.png';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.notificationMailIcon = function notificationMailIcon() {
+ return this.sStaticPrefix + 'css/images/icom-message-notification.png';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.openPgpJs = function openPgpJs() {
+ return this.sStaticPrefix + 'js/min/openpgp.min.js';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.openPgpWorkerJs = function openPgpWorkerJs() {
+ return this.sStaticPrefix + 'js/min/openpgp.worker.min.js';
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.openPgpWorkerPath = function openPgpWorkerPath() {
+ return this.sStaticPrefix + 'js/min/';
+ };
+
+ /**
+ * @param {boolean} xauth = false
+ * @return {string}
+ */
+
+
+ Links.prototype.socialGoogle = function socialGoogle() {
+ var xauth = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
+
+ return this.sServer + 'SocialGoogle' + ('' !== this.sAuthSuffix ? '/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/' : '') + (xauth ? '&xauth=1' : '');
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.socialTwitter = function socialTwitter() {
+ return this.sServer + 'SocialTwitter' + ('' !== this.sAuthSuffix ? '/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/' : '');
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ Links.prototype.socialFacebook = function socialFacebook() {
+ return this.sServer + 'SocialFacebook' + ('' !== this.sAuthSuffix ? '/' + this.subQueryPrefix() + '/' + this.sAuthSuffix + '/' : '');
+ };
+
+ return Links;
+ }();
+
+ module.exports = new Links();
+
+/***/ },
+/* 13 */
+/*!************************!*\
+ !*** ./dev/common.jsx ***!
+ \************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.key = exports.moment = exports.Q = exports._ = exports.JSON = exports.$ = exports.window = undefined;
+
+ var _window = __webpack_require__(/*! window */ 11);
+
+ var _window2 = _interopRequireDefault(_window);
+
+ var _$ = __webpack_require__(/*! $ */ 14);
+
+ var _$2 = _interopRequireDefault(_$);
+
+ var _JSON = __webpack_require__(/*! JSON */ 36);
+
+ var _JSON2 = _interopRequireDefault(_JSON);
+
+ var _2 = __webpack_require__(/*! _ */ 3);
+
+ var _3 = _interopRequireDefault(_2);
+
+ var _Q = __webpack_require__(/*! Q */ 48);
+
+ var _Q2 = _interopRequireDefault(_Q);
+
+ var _moment = __webpack_require__(/*! moment */ 82);
+
+ var _moment2 = _interopRequireDefault(_moment);
+
+ var _key = __webpack_require__(/*! key */ 18);
+
+ var _key2 = _interopRequireDefault(_key);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ exports.window = _window2.default;
+ exports.$ = _$2.default;
+ exports.JSON = _JSON2.default;
+ exports._ = _3.default;
+ exports.Q = _Q2.default;
+ exports.moment = _moment2.default;
+ exports.key = _key2.default;
+
+/***/ },
+/* 14 */
+/*!********************************!*\
+ !*** external "window.jQuery" ***!
+ \********************************/
+/***/ function(module, exports) {
+
+ module.exports = window.jQuery;
+
+/***/ },
+/* 15 */
+/*!*********************************!*\
+ !*** ./dev/Remote/User/Ajax.js ***!
+ \*********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Base64 = __webpack_require__(/*! Common/Base64 */ 161),
+
+ Cache = __webpack_require__(/*! Common/Cache */ 19),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+
+ AppStore = __webpack_require__(/*! Stores/User/App */ 24),
+ SettingsStore = __webpack_require__(/*! Stores/User/Settings */ 28),
+
+ AbstractAjaxRemote = __webpack_require__(/*! Remote/AbstractAjax */ 55)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractRemoteStorage
+ */
+ function RemoteUserAjax()
+ {
+ AbstractAjaxRemote.call(this);
+
+ this.oRequests = {};
+ }
+
+ _.extend(RemoteUserAjax.prototype, AbstractAjaxRemote.prototype);
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.folders = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'Folders', {
+ 'SentFolder': Settings.settingsGet('SentFolder'),
+ 'DraftFolder': Settings.settingsGet('DraftFolder'),
+ 'SpamFolder': Settings.settingsGet('SpamFolder'),
+ 'TrashFolder': Settings.settingsGet('TrashFolder'),
+ 'ArchiveFolder': Settings.settingsGet('ArchiveFolder')
+ }, null, '', ['Folders']);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sEmail
+ * @param {string} sLogin
+ * @param {string} sPassword
+ * @param {boolean} bSignMe
+ * @param {string=} sLanguage
+ * @param {string=} sAdditionalCode
+ * @param {boolean=} bAdditionalCodeSignMe
+ */
+ RemoteUserAjax.prototype.login = function (fCallback, sEmail, sLogin, sPassword, bSignMe, sLanguage, sAdditionalCode, bAdditionalCodeSignMe)
+ {
+ this.defaultRequest(fCallback, 'Login', {
+ 'Email': sEmail,
+ 'Login': sLogin,
+ 'Password': sPassword,
+ 'Language': sLanguage || '',
+ 'AdditionalCode': sAdditionalCode || '',
+ 'AdditionalCodeSignMe': bAdditionalCodeSignMe ? '1' : '0',
+ 'SignMe': bSignMe ? '1' : '0'
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.getTwoFactor = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'GetTwoFactorInfo');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.createTwoFactor = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'CreateTwoFactorSecret');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.clearTwoFactor = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'ClearTwoFactorInfo');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.showTwoFactorSecret = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'ShowTwoFactorSecret');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sCode
+ */
+ RemoteUserAjax.prototype.testTwoFactor = function (fCallback, sCode)
+ {
+ this.defaultRequest(fCallback, 'TestTwoFactorInfo', {
+ 'Code': sCode
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {boolean} bEnable
+ */
+ RemoteUserAjax.prototype.enableTwoFactor = function (fCallback, bEnable)
+ {
+ this.defaultRequest(fCallback, 'EnableTwoFactor', {
+ 'Enable': bEnable ? '1' : '0'
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.clearTwoFactorInfo = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'ClearTwoFactorInfo');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.contactsSync = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'ContactsSync', null, Consts.CONTACTS_SYNC_AJAX_TIMEOUT);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {boolean} bEnable
+ * @param {string} sUrl
+ * @param {string} sUser
+ * @param {string} sPassword
+ */
+ RemoteUserAjax.prototype.saveContactsSyncData = function (fCallback, bEnable, sUrl, sUser, sPassword)
+ {
+ this.defaultRequest(fCallback, 'SaveContactsSyncData', {
+ 'Enable': bEnable ? '1' : '0',
+ 'Url': sUrl,
+ 'User': sUser,
+ 'Password': sPassword
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sEmail
+ * @param {string} sPassword
+ * @param {boolean=} bNew
+ */
+ RemoteUserAjax.prototype.accountSetup = function (fCallback, sEmail, sPassword, bNew)
+ {
+ bNew = Utils.isUnd(bNew) ? true : !!bNew;
+
+ this.defaultRequest(fCallback, 'AccountSetup', {
+ 'Email': sEmail,
+ 'Password': sPassword,
+ 'New': bNew ? '1' : '0'
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sEmailToDelete
+ */
+ RemoteUserAjax.prototype.accountDelete = function (fCallback, sEmailToDelete)
+ {
+ this.defaultRequest(fCallback, 'AccountDelete', {
+ 'EmailToDelete': sEmailToDelete
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {Array} aAccounts
+ * @param {Array} aIdentities
+ */
+ RemoteUserAjax.prototype.accountsAndIdentitiesSortOrder = function (fCallback, aAccounts, aIdentities)
+ {
+ this.defaultRequest(fCallback, 'AccountsAndIdentitiesSortOrder', {
+ 'Accounts': aAccounts,
+ 'Identities': aIdentities
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sId
+ * @param {string} sEmail
+ * @param {string} sName
+ * @param {string} sReplyTo
+ * @param {string} sBcc
+ * @param {string} sSignature
+ * @param {boolean} bSignatureInsertBefore
+ */
+ RemoteUserAjax.prototype.identityUpdate = function (fCallback, sId, sEmail, sName, sReplyTo, sBcc,
+ sSignature, bSignatureInsertBefore)
+ {
+ this.defaultRequest(fCallback, 'IdentityUpdate', {
+ 'Id': sId,
+ 'Email': sEmail,
+ 'Name': sName,
+ 'ReplyTo': sReplyTo,
+ 'Bcc': sBcc,
+ 'Signature': sSignature,
+ 'SignatureInsertBefore': bSignatureInsertBefore ? '1' : '0'
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sIdToDelete
+ */
+ RemoteUserAjax.prototype.identityDelete = function (fCallback, sIdToDelete)
+ {
+ this.defaultRequest(fCallback, 'IdentityDelete', {
+ 'IdToDelete': sIdToDelete
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.accountsAndIdentities = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'AccountsAndIdentities');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.accountsCounts = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'AccountsCounts');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.filtersSave = function (fCallback,
+ aFilters, sRaw, bRawIsActive)
+ {
+ this.defaultRequest(fCallback, 'FiltersSave', {
+ 'Raw': sRaw,
+ 'RawIsActive': bRawIsActive ? '1' : '0',
+ 'Filters': _.map(aFilters, function (oItem) {
+ return oItem.toJson();
+ })
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.filtersGet = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'Filters', {});
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.templates = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'Templates', {});
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.templateGetById = function (fCallback, sID)
+ {
+ this.defaultRequest(fCallback, 'TemplateGetByID', {
+ 'ID': sID
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.templateDelete = function (fCallback, sID)
+ {
+ this.defaultRequest(fCallback, 'TemplateDelete', {
+ 'IdToDelete': sID
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.templateSetup = function (fCallback, sID, sName, sBody)
+ {
+ this.defaultRequest(fCallback, 'TemplateSetup', {
+ 'ID': sID,
+ 'Name': sName,
+ 'Body': sBody
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sFolderFullNameRaw
+ * @param {number=} iOffset = 0
+ * @param {number=} iLimit = 20
+ * @param {string=} sSearch = ''
+ * @param {string=} sThreadUid = ''
+ * @param {boolean=} bSilent = false
+ */
+ RemoteUserAjax.prototype.messageList = function (fCallback, sFolderFullNameRaw, iOffset, iLimit, sSearch, sThreadUid, bSilent)
+ {
+ sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw);
+
+ var
+ sFolderHash = Cache.getFolderHash(sFolderFullNameRaw),
+ bUseThreads = AppStore.threadsAllowed() && SettingsStore.useThreads(),
+ sInboxUidNext = Cache.getFolderInboxName() === sFolderFullNameRaw ? Cache.getFolderUidNext(sFolderFullNameRaw) : ''
+ ;
+
+ bSilent = Utils.isUnd(bSilent) ? false : !!bSilent;
+ iOffset = Utils.isUnd(iOffset) ? 0 : Utils.pInt(iOffset);
+ iLimit = Utils.isUnd(iOffset) ? 20 : Utils.pInt(iLimit);
+ sSearch = Utils.pString(sSearch);
+ sThreadUid = Utils.pString(sThreadUid);
+
+ if ('' !== sFolderHash && ('' === sSearch || -1 === sSearch.indexOf('is:')))
+ {
+ return this.defaultRequest(fCallback, 'MessageList', {},
+ '' === sSearch ? Consts.DEFAULT_AJAX_TIMEOUT : Consts.SEARCH_AJAX_TIMEOUT,
+ 'MessageList/' + Links.subQueryPrefix() + '/' + Base64.urlsafe_encode([
+ sFolderFullNameRaw,
+ iOffset,
+ iLimit,
+ sSearch,
+ AppStore.projectHash(),
+ sFolderHash,
+ sInboxUidNext,
+ bUseThreads ? '1' : '0',
+ bUseThreads ? sThreadUid : ''
+ ].join(String.fromCharCode(0))), bSilent ? [] : ['MessageList']);
+ }
+ else
+ {
+ return this.defaultRequest(fCallback, 'MessageList', {
+ 'Folder': sFolderFullNameRaw,
+ 'Offset': iOffset,
+ 'Limit': iLimit,
+ 'Search': sSearch,
+ 'UidNext': sInboxUidNext,
+ 'UseThreads': bUseThreads ? '1' : '0',
+ 'ThreadUid': bUseThreads ? sThreadUid : ''
+ }, '' === sSearch ? Consts.DEFAULT_AJAX_TIMEOUT : Consts.SEARCH_AJAX_TIMEOUT,
+ '', bSilent ? [] : ['MessageList']);
+ }
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {Array} aDownloads
+ */
+ RemoteUserAjax.prototype.messageUploadAttachments = function (fCallback, aDownloads)
+ {
+ this.defaultRequest(fCallback, 'MessageUploadAttachments', {
+ 'Attachments': aDownloads
+ }, 999000);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sFolderFullNameRaw
+ * @param {number} iUid
+ * @return {boolean}
+ */
+ RemoteUserAjax.prototype.message = function (fCallback, sFolderFullNameRaw, iUid)
+ {
+ sFolderFullNameRaw = Utils.pString(sFolderFullNameRaw);
+ iUid = Utils.pInt(iUid);
+
+ if (Cache.getFolderFromCacheList(sFolderFullNameRaw) && 0 < iUid)
+ {
+ this.defaultRequest(fCallback, 'Message', {}, null,
+ 'Message/' + Links.subQueryPrefix() + '/' + Base64.urlsafe_encode([
+ sFolderFullNameRaw,
+ iUid,
+ AppStore.projectHash(),
+ AppStore.threadsAllowed() && SettingsStore.useThreads() ? '1' : '0'
+ ].join(String.fromCharCode(0))), ['Message']);
+
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {Array} aExternals
+ */
+ RemoteUserAjax.prototype.composeUploadExternals = function (fCallback, aExternals)
+ {
+ this.defaultRequest(fCallback, 'ComposeUploadExternals', {
+ 'Externals': aExternals
+ }, 999000);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sUrl
+ * @param {string} sAccessToken
+ */
+ RemoteUserAjax.prototype.composeUploadDrive = function (fCallback, sUrl, sAccessToken)
+ {
+ this.defaultRequest(fCallback, 'ComposeUploadDrive', {
+ 'AccessToken': sAccessToken,
+ 'Url': sUrl
+ }, 999000);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sFolder
+ * @param {Array=} aList = []
+ */
+ RemoteUserAjax.prototype.folderInformation = function (fCallback, sFolder, aList)
+ {
+ var
+ bRequest = true,
+ aUids = []
+ ;
+
+ if (Utils.isArray(aList) && 0 < aList.length)
+ {
+ bRequest = false;
+ _.each(aList, function (oMessageListItem) {
+ if (!Cache.getMessageFlagsFromCache(oMessageListItem.folderFullNameRaw, oMessageListItem.uid))
+ {
+ aUids.push(oMessageListItem.uid);
+ }
+
+ if (0 < oMessageListItem.threads().length)
+ {
+ _.each(oMessageListItem.threads(), function (sUid) {
+ if (!Cache.getMessageFlagsFromCache(oMessageListItem.folderFullNameRaw, sUid))
+ {
+ aUids.push(sUid);
+ }
+ });
+ }
+ });
+
+ if (0 < aUids.length)
+ {
+ bRequest = true;
+ }
+ }
+
+ if (bRequest)
+ {
+ this.defaultRequest(fCallback, 'FolderInformation', {
+ 'Folder': sFolder,
+ 'FlagsUids': Utils.isArray(aUids) ? aUids.join(',') : '',
+ 'UidNext': Cache.getFolderInboxName() === sFolder ? Cache.getFolderUidNext(sFolder) : ''
+ });
+ }
+ else if (SettingsStore.useThreads())
+ {
+ __webpack_require__(/*! App/User */ 7).default.reloadFlagsCurrentMessageListAndMessageFromCache();
+ }
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {Array} aFolders
+ */
+ RemoteUserAjax.prototype.folderInformationMultiply = function (fCallback, aFolders)
+ {
+ this.defaultRequest(fCallback, 'FolderInformationMultiply', {
+ 'Folders': aFolders
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.logout = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'Logout');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sFolderFullNameRaw
+ * @param {Array} aUids
+ * @param {boolean} bSetFlagged
+ */
+ RemoteUserAjax.prototype.messageSetFlagged = function (fCallback, sFolderFullNameRaw, aUids, bSetFlagged)
+ {
+ this.defaultRequest(fCallback, 'MessageSetFlagged', {
+ 'Folder': sFolderFullNameRaw,
+ 'Uids': aUids.join(','),
+ 'SetAction': bSetFlagged ? '1' : '0'
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sFolderFullNameRaw
+ * @param {Array} aUids
+ * @param {boolean} bSetSeen
+ */
+ RemoteUserAjax.prototype.messageSetSeen = function (fCallback, sFolderFullNameRaw, aUids, bSetSeen)
+ {
+ this.defaultRequest(fCallback, 'MessageSetSeen', {
+ 'Folder': sFolderFullNameRaw,
+ 'Uids': aUids.join(','),
+ 'SetAction': bSetSeen ? '1' : '0'
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sFolderFullNameRaw
+ * @param {boolean} bSetSeen
+ */
+ RemoteUserAjax.prototype.messageSetSeenToAll = function (fCallback, sFolderFullNameRaw, bSetSeen)
+ {
+ this.defaultRequest(fCallback, 'MessageSetSeenToAll', {
+ 'Folder': sFolderFullNameRaw,
+ 'SetAction': bSetSeen ? '1' : '0'
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sIdentityID
+ * @param {string} sMessageFolder
+ * @param {string} sMessageUid
+ * @param {string} sDraftFolder
+ * @param {string} sTo
+ * @param {string} sCc
+ * @param {string} sBcc
+ * @param {string} sSubject
+ * @param {boolean} bTextIsHtml
+ * @param {string} sText
+ * @param {Array} aAttachments
+ * @param {(Array|null)} aDraftInfo
+ * @param {string} sInReplyTo
+ * @param {string} sReferences
+ * @param {boolean} bMarkAsImportant
+ */
+ RemoteUserAjax.prototype.saveMessage = function (fCallback, sIdentityID, sMessageFolder, sMessageUid, sDraftFolder,
+ sTo, sCc, sBcc, sReplyTo, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences, bMarkAsImportant)
+ {
+ this.defaultRequest(fCallback, 'SaveMessage', {
+ 'IdentityID': sIdentityID,
+ 'MessageFolder': sMessageFolder,
+ 'MessageUid': sMessageUid,
+ 'DraftFolder': sDraftFolder,
+ 'To': sTo,
+ 'Cc': sCc,
+ 'Bcc': sBcc,
+ 'ReplyTo': sReplyTo,
+ 'Subject': sSubject,
+ 'TextIsHtml': bTextIsHtml ? '1' : '0',
+ 'Text': sText,
+ 'DraftInfo': aDraftInfo,
+ 'InReplyTo': sInReplyTo,
+ 'References': sReferences,
+ 'MarkAsImportant': bMarkAsImportant ? '1' : '0',
+ 'Attachments': aAttachments
+ }, Consts.SAVE_MESSAGE_AJAX_TIMEOUT);
+ };
+
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sMessageFolder
+ * @param {string} sMessageUid
+ * @param {string} sReadReceipt
+ * @param {string} sSubject
+ * @param {string} sText
+ */
+ RemoteUserAjax.prototype.sendReadReceiptMessage = function (fCallback, sMessageFolder, sMessageUid, sReadReceipt, sSubject, sText)
+ {
+ this.defaultRequest(fCallback, 'SendReadReceiptMessage', {
+ 'MessageFolder': sMessageFolder,
+ 'MessageUid': sMessageUid,
+ 'ReadReceipt': sReadReceipt,
+ 'Subject': sSubject,
+ 'Text': sText
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sIdentityID
+ * @param {string} sMessageFolder
+ * @param {string} sMessageUid
+ * @param {string} sSentFolder
+ * @param {string} sTo
+ * @param {string} sCc
+ * @param {string} sBcc
+ * @param {string} sReplyTo
+ * @param {string} sSubject
+ * @param {boolean} bTextIsHtml
+ * @param {string} sText
+ * @param {Array} aAttachments
+ * @param {(Array|null)} aDraftInfo
+ * @param {string} sInReplyTo
+ * @param {string} sReferences
+ * @param {boolean} bRequestDsn
+ * @param {boolean} bRequestReadReceipt
+ * @param {boolean} bMarkAsImportant
+ */
+ RemoteUserAjax.prototype.sendMessage = function (fCallback, sIdentityID, sMessageFolder, sMessageUid, sSentFolder,
+ sTo, sCc, sBcc, sReplyTo, sSubject, bTextIsHtml, sText, aAttachments, aDraftInfo, sInReplyTo, sReferences,
+ bRequestDsn, bRequestReadReceipt, bMarkAsImportant)
+ {
+ this.defaultRequest(fCallback, 'SendMessage', {
+ 'IdentityID': sIdentityID,
+ 'MessageFolder': sMessageFolder,
+ 'MessageUid': sMessageUid,
+ 'SentFolder': sSentFolder,
+ 'To': sTo,
+ 'Cc': sCc,
+ 'Bcc': sBcc,
+ 'ReplyTo': sReplyTo,
+ 'Subject': sSubject,
+ 'TextIsHtml': bTextIsHtml ? '1' : '0',
+ 'Text': sText,
+ 'DraftInfo': aDraftInfo,
+ 'InReplyTo': sInReplyTo,
+ 'References': sReferences,
+ 'Dsn': bRequestDsn ? '1' : '0',
+ 'ReadReceiptRequest': bRequestReadReceipt ? '1' : '0',
+ 'MarkAsImportant': bMarkAsImportant ? '1' : '0',
+ 'Attachments': aAttachments
+ }, Consts.SEND_MESSAGE_AJAX_TIMEOUT);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {Object} oData
+ */
+ RemoteUserAjax.prototype.saveSystemFolders = function (fCallback, oData)
+ {
+ this.defaultRequest(fCallback, 'SystemFoldersUpdate', oData);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {Object} oData
+ */
+ RemoteUserAjax.prototype.saveSettings = function (fCallback, oData)
+ {
+ this.defaultRequest(fCallback, 'SettingsUpdate', oData);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sPrevPassword
+ * @param {string} sNewPassword
+ */
+ RemoteUserAjax.prototype.changePassword = function (fCallback, sPrevPassword, sNewPassword)
+ {
+ this.defaultRequest(fCallback, 'ChangePassword', {
+ 'PrevPassword': sPrevPassword,
+ 'NewPassword': sNewPassword
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sFolderFullNameRaw
+ */
+ RemoteUserAjax.prototype.folderClear = function (fCallback, sFolderFullNameRaw)
+ {
+ this.defaultRequest(fCallback, 'FolderClear', {
+ 'Folder': sFolderFullNameRaw
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sFolderFullNameRaw
+ * @param {boolean} bSubscribe
+ */
+ RemoteUserAjax.prototype.folderSetSubscribe = function (fCallback, sFolderFullNameRaw, bSubscribe)
+ {
+ this.defaultRequest(fCallback, 'FolderSubscribe', {
+ 'Folder': sFolderFullNameRaw,
+ 'Subscribe': bSubscribe ? '1' : '0'
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sFolderFullNameRaw
+ * @param {boolean} bCheckable
+ */
+ RemoteUserAjax.prototype.folderSetCheckable = function (fCallback, sFolderFullNameRaw, bCheckable)
+ {
+ this.defaultRequest(fCallback, 'FolderCheckable', {
+ 'Folder': sFolderFullNameRaw,
+ 'Checkable': bCheckable ? '1' : '0'
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sFolder
+ * @param {string} sToFolder
+ * @param {Array} aUids
+ * @param {string=} sLearning
+ * @param {boolean=} bMarkAsRead
+ */
+ RemoteUserAjax.prototype.messagesMove = function (fCallback, sFolder, sToFolder, aUids, sLearning, bMarkAsRead)
+ {
+ this.defaultRequest(fCallback, 'MessageMove', {
+ 'FromFolder': sFolder,
+ 'ToFolder': sToFolder,
+ 'Uids': aUids.join(','),
+ 'MarkAsRead': bMarkAsRead ? '1' : '0',
+ 'Learning': sLearning || ''
+ }, null, '', ['MessageList']);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sFolder
+ * @param {string} sToFolder
+ * @param {Array} aUids
+ */
+ RemoteUserAjax.prototype.messagesCopy = function (fCallback, sFolder, sToFolder, aUids)
+ {
+ this.defaultRequest(fCallback, 'MessageCopy', {
+ 'FromFolder': sFolder,
+ 'ToFolder': sToFolder,
+ 'Uids': aUids.join(',')
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sFolder
+ * @param {Array} aUids
+ */
+ RemoteUserAjax.prototype.messagesDelete = function (fCallback, sFolder, aUids)
+ {
+ this.defaultRequest(fCallback, 'MessageDelete', {
+ 'Folder': sFolder,
+ 'Uids': aUids.join(',')
+ }, null, '', ['MessageList']);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.appDelayStart = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'AppDelayStart');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.quota = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'Quota');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {number} iOffset
+ * @param {number} iLimit
+ * @param {string} sSearch
+ */
+ RemoteUserAjax.prototype.contacts = function (fCallback, iOffset, iLimit, sSearch)
+ {
+ this.defaultRequest(fCallback, 'Contacts', {
+ 'Offset': iOffset,
+ 'Limit': iLimit,
+ 'Search': sSearch
+ }, null, '', ['Contacts']);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sRequestUid
+ * @param {string} sUid
+ * @param {Array} aProperties
+ */
+ RemoteUserAjax.prototype.contactSave = function (fCallback, sRequestUid, sUid, aProperties)
+ {
+ this.defaultRequest(fCallback, 'ContactSave', {
+ 'RequestUid': sRequestUid,
+ 'Uid': Utils.trim(sUid),
+ 'Properties': aProperties
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {Array} aUids
+ */
+ RemoteUserAjax.prototype.contactsDelete = function (fCallback, aUids)
+ {
+ this.defaultRequest(fCallback, 'ContactsDelete', {
+ 'Uids': aUids.join(',')
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sQuery
+ * @param {number} iPage
+ */
+ RemoteUserAjax.prototype.suggestions = function (fCallback, sQuery, iPage)
+ {
+ this.defaultRequest(fCallback, 'Suggestions', {
+ 'Query': sQuery,
+ 'Page': iPage
+ }, null, '', ['Suggestions']);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.clearUserBackground = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'ClearUserBackground');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.facebookUser = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'SocialFacebookUserInformation');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.facebookDisconnect = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'SocialFacebookDisconnect');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.twitterUser = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'SocialTwitterUserInformation');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.twitterDisconnect = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'SocialTwitterDisconnect');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.googleUser = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'SocialGoogleUserInformation');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.googleDisconnect = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'SocialGoogleDisconnect');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ RemoteUserAjax.prototype.socialUsers = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'SocialUsers');
+ };
+
+ module.exports = new RemoteUserAjax();
+
+ }());
+
+/***/ },
+/* 16 */
+/*!************************************!*\
+ !*** ./dev/Component/Abstract.jsx ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.componentExportHelper = exports.AbstractComponent = undefined;
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var AbstractComponent = function () {
+ function AbstractComponent() {
+ _classCallCheck(this, AbstractComponent);
+
+ this.disposable = [];
+ }
+
+ AbstractComponent.prototype.dispose = function dispose() {
+ this.disposable.forEach(function (funcToDispose) {
+ if (funcToDispose && funcToDispose.dispose) {
+ funcToDispose.dispose();
+ }
+ });
+ };
+
+ return AbstractComponent;
+ }();
+
+ /**
+ * @param {*} ClassObject
+ * @param {string} templateID = ''
+ * @return {Object}
+ */
+
+
+ var componentExportHelper = function componentExportHelper(ClassObject) {
+ var templateID = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1];
+
+ return {
+ template: templateID ? { element: templateID } : '
',
+ viewModel: {
+ createViewModel: function createViewModel(params, componentInfo) {
+
+ params = params || {};
+ params.element = null;
+
+ if (componentInfo && componentInfo.element) {
+ params.component = componentInfo;
+ params.element = (0, _common.$)(componentInfo.element);
+
+ __webpack_require__(/*! Common/Translator */ 6).i18nToNodes(params.element);
+
+ if (!_Utils2.default.isUnd(params.inline) && _ko2.default.unwrap(params.inline)) {
+ params.element.css('display', 'inline-block');
+ }
+ }
+
+ return new ClassObject(params);
+ }
+ }
+ };
+ };
+
+ exports.AbstractComponent = AbstractComponent;
+ exports.componentExportHelper = componentExportHelper;
+
+/***/ },
+/* 17 */
+/*!*******************************!*\
+ !*** ./dev/Common/Consts.jsx ***!
+ \*******************************/
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ /* eslint max-len: 0 */
+
+ var MESSAGES_PER_PAGE = exports.MESSAGES_PER_PAGE = 20;
+
+ var MESSAGES_PER_PAGE_VALUES = exports.MESSAGES_PER_PAGE_VALUES = [10, 20, 30, 50, 100];
+
+ var CONTACTS_PER_PAGE = exports.CONTACTS_PER_PAGE = 50;
+
+ var DEFAULT_AJAX_TIMEOUT = exports.DEFAULT_AJAX_TIMEOUT = 30000;
+
+ var SEARCH_AJAX_TIMEOUT = exports.SEARCH_AJAX_TIMEOUT = 300000;
+
+ var SEND_MESSAGE_AJAX_TIMEOUT = exports.SEND_MESSAGE_AJAX_TIMEOUT = 300000;
+
+ var SAVE_MESSAGE_AJAX_TIMEOUT = exports.SAVE_MESSAGE_AJAX_TIMEOUT = 200000;
+
+ var CONTACTS_SYNC_AJAX_TIMEOUT = exports.CONTACTS_SYNC_AJAX_TIMEOUT = 200000;
+
+ var UNUSED_OPTION_VALUE = exports.UNUSED_OPTION_VALUE = '__UNUSE__';
+
+ var CLIENT_SIDE_STORAGE_INDEX_NAME = exports.CLIENT_SIDE_STORAGE_INDEX_NAME = 'rlcsc';
+
+ var IMAP_DEFAULT_PORT = exports.IMAP_DEFAULT_PORT = 143;
+
+ var IMAP_DEFAULT_SECURE_PORT = exports.IMAP_DEFAULT_SECURE_PORT = 993;
+
+ var SMTP_DEFAULT_PORT = exports.SMTP_DEFAULT_PORT = 25;
+
+ var SMTP_DEFAULT_SECURE_PORT = exports.SMTP_DEFAULT_SECURE_PORT = 465;
+
+ var SIEVE_DEFAULT_PORT = exports.SIEVE_DEFAULT_PORT = 4190;
+
+ var MESSAGE_BODY_CACHE_LIMIT = exports.MESSAGE_BODY_CACHE_LIMIT = 15;
+
+ var AJAX_ERROR_LIMIT = exports.AJAX_ERROR_LIMIT = 7;
+
+ var TOKEN_ERROR_LIMIT = exports.TOKEN_ERROR_LIMIT = 10;
+
+ var RAINLOOP_TRIAL_KEY = exports.RAINLOOP_TRIAL_KEY = 'RAINLOOP-TRIAL-KEY';
+
+ var DATA_IMAGE_USER_DOT_PIC = exports.DATA_IMAGE_USER_DOT_PIC = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAuCAYAAABXuSs3AAAHHklEQVRoQ7VZW08bVxCeXRuwIbTGXIwNtBBaqjwgVUiR8lDlbza9qe1DpVZ9aNQ/0KpPeaJK07SpcuEeCEmUAObm21bfrL9lONjexSYrWfbunj37zXdmvpkz9oIgCKTD0Wg0xPd94TDP83Q0zvWa50vzklSrdanVanqf4/D84GBGr+F+Op3S8fqoJxLOdnZgTvsO/nYhenHA+UC7CWF1uXwkb9++ldPTUwVerVbVqFQqpR8YPjQ0JCMjI5LNDijoRgP3PQVu5+5Eor2XGLg7IV4GkIdHJ/LmzRs5ODiIwNbrdR0O0GCcq4Xz4eFhmZyclP7+tDQaIik/BG5XKQn4SwG3zJTLZXn9+rUclI8UHD5YVoDDN8bSzXhONwL48fFxGR4eilzFZT1uFRIB5yT8BqCdnR3Z3d0VP9Un6XRawYJpggVrZBv38ME4XKtUKnLt2jUplUoy1PR/l3U7T6sVSAQcgMAkj8PDQ9ne3pajoyMRL7zeKsYZWHgWYDGmv78/mmdwcFA+mJlSgziHDWrERrsjEXDXegTi1tZW+DLxI2bxIrqFNYTXyDyCFweMAHCwb8e4RnTNuOsqe3t7sra21pTD0Kct666E8XlcZyzw9/RUUXK5nK5oUinUQI6TQ3cynO/v78vq6qrKXCNwlTiJJpyNGc3nZHp6uqV2dwrQWOCtZBDAV1ZWwsQk7f0wiQn5kffbAu/0/KWBYzIC1+XukfGx0RGZmppKlC2tIV0Bh4aDcZW7HhkfH8urLLZL7T2pihvlkMNnz56FiadHxicL41IsFpN41bkxsYxbRdFo9jwB8KdPn14J8KnSpBQKhQs63nPmbCVRcBUAR2Lq1VVmpksyMTFxAXjcEsQybiegESionjx5osCZOeNe1O4+EhCAX7bQSgQcxRHTMgAgcz5+/Dis/hL4uHU3/B4YGNASGHIKxuEql0k+l05AeIAF1vPnz5VxFFmdDlaJrMtZITJeSsXCOTlMunKxjLtMYOKNjQ158eJFuAuKkUOb5sEwgff19SkJUBVkThZUbnXZrtCKBQ6gbnWIkjZpyne3ejAWoGnA7Icz6irvBLgbOMicCM6TkxPx/LAkbXfgWcsazuE2kFRsKD5Z+CiqDumKncpZvieWcS6dDVD8xiYCNflpJdwcdwJOf9airLmVQ7DPzMxIYWLsXGXoVqLt5k0M3K3JUVPDZdbWNzsCp48TPFdvdnZWUz32nDha7bJ63kgAJPzSdRks9/Kf9xMJAQ1gq2NpaUmy2Yz4zar4nQC3xb99AQwCcGzLAAwuhG8YiWvcOKts+r4GOe5nMhm5efOm9lUA3E3vSZJRrKvE0fnPv//Jy5cvo5cTHIPQbSjhOoqq69evS19f6lxDKK4+sVhigZPtKJqbrQeqxd5+WR4+fKgqgT0k2XX3nhiPgETWXFhYkFzuPZ2yVq1GTSOXpE47/VjgNnD4m4GG7/LhsTx69EiwD4Vr2MwIIxgbAH18fKx1yfz8vEogNvGtWnCuhLZa9UTAreVWFsHy/b/+Vrbdl7E5REMQD2jDoUbByty+/ZnU64GkU2HzyJLhktU1cLv8nARgkYS2d3ajAgwG8qU2oLmDZ92CMaOjo7K4uCiZgbDWaRWgnZhPxLhrMUCvr69riwKZk1LHF7XqrWAO9hJxH6ozNzcnCx/PqztZg9mf6SQMscCtm2C5ke4BGMlHWTUp36036AJajDVrFMzBrhhWslQsSrFYiOqVpMriNYIgqFRq2j3FAb/zffT6zuxFXxsNzs3NTXn16lW4gYiW96w1FyedF+83xG/2FNGCRpU4NjamMsn+OZ9xE5RXqdaDdPpib6RWCzuwKF9RxqI2AVNQBwQYJoK0wdBejnqtEikP3pfP51XjUTESl12FqJEKxsEorARYDD44ONTeID7YpsEnrRvQfWAI2e8WfDaTUSIwJ0iBCmFOtOUAHvVMPp/TPwvYFVYFIuP8l+DBgwdaa2Miqwa0GgYwfeMltovbDfh6c1vIgMYcliSsKv4IWFr6VDHxvldvBAH+1sA+cnl5WYOPmmr9ir+1l9I0Cgz0yjhXjfJJ0JROnmezWbl165ayr/5fqwcBNr7IfhjMqKcvESSM4eRcCasQ3bDNObmKPLdGUGpZsN24cUNLBm9zazu4d++e6qpNBFaTuUS26U5dpuR1CxyA7J9ddrMRqlz4pwLLYawymPd++/2PADt2ugcGwq9gCCdhQ96C6xWwa6j1ceuq+I0EhW0i8MAIVJfeL3d/DVD8EKi12P6/2S2jV/EccVB54O/ejz/9HGCpoBBMta5rXMXLu53D1XAwjhXwvvv+h4BAXVe4bOu3O3ChxF08LiZFG3fel199G9CH3fLyqv24NcB44MRhpdK788U3CpyKwsCw590xmfSpzsBt0Fqc3ud3vtZigxWcVZCklVpSiN0w3q5E/h9TGMIUuA3+EQAAAABJRU5ErkJggg==';
+
+ var DATA_IMAGE_TRANSP_PIC = exports.DATA_IMAGE_TRANSP_PIC = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2NkAAIAAAoAAggA9GkAAAAASUVORK5CYII=';
+
+/***/ },
+/* 18 */
+/*!*****************************!*\
+ !*** external "window.key" ***!
+ \*****************************/
+/***/ function(module, exports) {
+
+ module.exports = window.key;
+
+/***/ },
+/* 19 */
+/*!******************************!*\
+ !*** ./dev/Common/Cache.jsx ***!
+ \******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Enums = __webpack_require__(/*! Common/Enums */ 4);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Links = __webpack_require__(/*! Common/Links */ 12);
+
+ var _Links2 = _interopRequireDefault(_Links);
+
+ var _Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var CacheUserStorage = function () {
+ function CacheUserStorage() {
+ _classCallCheck(this, CacheUserStorage);
+
+ this.oFoldersCache = {};
+ this.oFoldersNamesCache = {};
+ this.oFolderHashCache = {};
+ this.oFolderUidNextCache = {};
+ this.oMessageListHashCache = {};
+ this.oMessageFlagsCache = {};
+ this.oNewMessage = {};
+ this.oRequestedMessage = {};
+ this.bCapaGravatar = false;
+ this.inboxFolderName = '';
+
+ this.bCapaGravatar = _Settings2.default.capa(_Enums.Capa.Gravatar);
+ }
+
+ CacheUserStorage.prototype.clear = function clear() {
+ this.oFoldersCache = {};
+ this.oFoldersNamesCache = {};
+ this.oFolderHashCache = {};
+ this.oFolderUidNextCache = {};
+ this.oMessageListHashCache = {};
+ this.oMessageFlagsCache = {};
+ };
+
+ /**
+ * @param {string} email
+ * @param {Function} callback
+ * @return {string}
+ */
+
+
+ CacheUserStorage.prototype.getUserPic = function getUserPic(email, callback) {
+ email = _Utils2.default.trim(email);
+ callback(this.bCapaGravatar && '' !== email ? _Links2.default.avatarLink(email) : '', email);
+ };
+
+ /**
+ * @param {string} folderFullNameRaw
+ * @param {string} uid
+ * @return {string}
+ */
+
+
+ CacheUserStorage.prototype.getMessageKey = function getMessageKey(folderFullNameRaw, uid) {
+ return folderFullNameRaw + '#' + uid;
+ };
+
+ /**
+ * @param {string} folder
+ * @param {string} uid
+ */
+
+
+ CacheUserStorage.prototype.addRequestedMessage = function addRequestedMessage(folder, uid) {
+ this.oRequestedMessage[this.getMessageKey(folder, uid)] = true;
+ };
+
+ /**
+ * @param {string} folder
+ * @param {string} uid
+ * @return {boolean}
+ */
+
+
+ CacheUserStorage.prototype.hasRequestedMessage = function hasRequestedMessage(folder, uid) {
+ return true === this.oRequestedMessage[this.getMessageKey(folder, uid)];
+ };
+
+ /**
+ * @param {string} folderFullNameRaw
+ * @param {string} uid
+ */
+
+
+ CacheUserStorage.prototype.addNewMessageCache = function addNewMessageCache(folderFullNameRaw, uid) {
+ this.oNewMessage[this.getMessageKey(folderFullNameRaw, uid)] = true;
+ };
+
+ /**
+ * @param {string} folderFullNameRaw
+ * @param {string} uid
+ */
+
+
+ CacheUserStorage.prototype.hasNewMessageAndRemoveFromCache = function hasNewMessageAndRemoveFromCache(folderFullNameRaw, uid) {
+ if (this.oNewMessage[this.getMessageKey(folderFullNameRaw, uid)]) {
+ this.oNewMessage[this.getMessageKey(folderFullNameRaw, uid)] = null;
+ return true;
+ }
+ return false;
+ };
+
+ CacheUserStorage.prototype.clearNewMessageCache = function clearNewMessageCache() {
+ this.oNewMessage = {};
+ };
+
+ /**
+ * @return {string}
+ */
+
+
+ CacheUserStorage.prototype.getFolderInboxName = function getFolderInboxName() {
+ return '' === this.inboxFolderName ? 'INBOX' : this.inboxFolderName;
+ };
+
+ /**
+ * @param {string} folderHash
+ * @return {string}
+ */
+
+
+ CacheUserStorage.prototype.getFolderFullNameRaw = function getFolderFullNameRaw(folderHash) {
+ return '' !== folderHash && this.oFoldersNamesCache[folderHash] ? this.oFoldersNamesCache[folderHash] : '';
+ };
+
+ /**
+ * @param {string} folderHash
+ * @param {string} folderFullNameRaw
+ */
+
+
+ CacheUserStorage.prototype.setFolderFullNameRaw = function setFolderFullNameRaw(folderHash, folderFullNameRaw) {
+ this.oFoldersNamesCache[folderHash] = folderFullNameRaw;
+ if ('INBOX' === folderFullNameRaw || '' === this.inboxFolderName) {
+ this.inboxFolderName = folderFullNameRaw;
+ }
+ };
+
+ /**
+ * @param {string} folderFullNameRaw
+ * @return {string}
+ */
+
+
+ CacheUserStorage.prototype.getFolderHash = function getFolderHash(folderFullNameRaw) {
+ return '' !== folderFullNameRaw && this.oFolderHashCache[folderFullNameRaw] ? this.oFolderHashCache[folderFullNameRaw] : '';
+ };
+
+ /**
+ * @param {string} folderFullNameRaw
+ * @param {string} folderHash
+ */
+
+
+ CacheUserStorage.prototype.setFolderHash = function setFolderHash(folderFullNameRaw, folderHash) {
+ if ('' !== folderFullNameRaw) {
+ this.oFolderHashCache[folderFullNameRaw] = folderHash;
+ }
+ };
+
+ /**
+ * @param {string} folderFullNameRaw
+ * @return {string}
+ */
+
+
+ CacheUserStorage.prototype.getFolderUidNext = function getFolderUidNext(folderFullNameRaw) {
+ return '' !== folderFullNameRaw && this.oFolderUidNextCache[folderFullNameRaw] ? this.oFolderUidNextCache[folderFullNameRaw] : '';
+ };
+
+ /**
+ * @param {string} folderFullNameRaw
+ * @param {string} uidNext
+ */
+
+
+ CacheUserStorage.prototype.setFolderUidNext = function setFolderUidNext(folderFullNameRaw, uidNext) {
+ this.oFolderUidNextCache[folderFullNameRaw] = uidNext;
+ };
+
+ /**
+ * @param {string} folderFullNameRaw
+ * @return {?FolderModel}
+ */
+
+
+ CacheUserStorage.prototype.getFolderFromCacheList = function getFolderFromCacheList(folderFullNameRaw) {
+ return '' !== folderFullNameRaw && this.oFoldersCache[folderFullNameRaw] ? this.oFoldersCache[folderFullNameRaw] : null;
+ };
+
+ /**
+ * @param {string} folderFullNameRaw
+ * @param {?FolderModel} folder
+ */
+
+
+ CacheUserStorage.prototype.setFolderToCacheList = function setFolderToCacheList(folderFullNameRaw, folder) {
+ this.oFoldersCache[folderFullNameRaw] = folder;
+ };
+
+ /**
+ * @param {string} folderFullNameRaw
+ */
+
+
+ CacheUserStorage.prototype.removeFolderFromCacheList = function removeFolderFromCacheList(folderFullNameRaw) {
+ this.setFolderToCacheList(folderFullNameRaw, null);
+ };
+
+ /**
+ * @param {string} folderFullName
+ * @param {string} uid
+ * @return {?Array}
+ */
+
+
+ CacheUserStorage.prototype.getMessageFlagsFromCache = function getMessageFlagsFromCache(folderFullName, uid) {
+ return this.oMessageFlagsCache[folderFullName] && this.oMessageFlagsCache[folderFullName][uid] ? this.oMessageFlagsCache[folderFullName][uid] : null;
+ };
+
+ /**
+ * @param {string} folderFullName
+ * @param {string} uid
+ * @param {Array} flagsCache
+ */
+
+
+ CacheUserStorage.prototype.setMessageFlagsToCache = function setMessageFlagsToCache(folderFullName, uid, flagsCache) {
+ if (!this.oMessageFlagsCache[folderFullName]) {
+ this.oMessageFlagsCache[folderFullName] = {};
+ }
+
+ this.oMessageFlagsCache[folderFullName][uid] = flagsCache;
+ };
+
+ /**
+ * @param {string} folderFullName
+ */
+
+
+ CacheUserStorage.prototype.clearMessageFlagsFromCacheByFolder = function clearMessageFlagsFromCacheByFolder(folderFullName) {
+ this.oMessageFlagsCache[folderFullName] = {};
+ };
+
+ /**
+ * @param {(MessageModel|null)} message
+ */
+
+
+ CacheUserStorage.prototype.initMessageFlagsFromCache = function initMessageFlagsFromCache(message) {
+ var _this = this;
+
+ if (message) {
+ (function () {
+ var uid = message.uid,
+ flags = _this.getMessageFlagsFromCache(message.folderFullNameRaw, uid);
+
+ if (flags && 0 < flags.length) {
+ message.flagged(!!flags[1]);
+
+ if (!message.__simple_message__) {
+ message.unseen(!!flags[0]);
+ message.answered(!!flags[2]);
+ message.forwarded(!!flags[3]);
+ message.isReadReceipt(!!flags[4]);
+ message.deletedMark(!!flags[5]);
+ }
+ }
+
+ if (0 < message.threads().length) {
+ var unseenSubUid = _common._.find(message.threads(), function (sSubUid) {
+ if (uid !== sSubUid) {
+ var subFlags = _this.getMessageFlagsFromCache(message.folderFullNameRaw, sSubUid);
+ return subFlags && 0 < subFlags.length && !!subFlags[0];
+ }
+ return false;
+ });
+
+ var flaggedSubUid = _common._.find(message.threads(), function (sSubUid) {
+ if (uid !== sSubUid) {
+ var subFlags = _this.getMessageFlagsFromCache(message.folderFullNameRaw, sSubUid);
+ return subFlags && 0 < subFlags.length && !!subFlags[1];
+ }
+ return false;
+ });
+
+ message.hasUnseenSubMessage(unseenSubUid && 0 < _Utils2.default.pInt(unseenSubUid));
+ message.hasFlaggedSubMessage(flaggedSubUid && 0 < _Utils2.default.pInt(flaggedSubUid));
+ }
+ })();
+ }
+ };
+
+ /**
+ * @param {(MessageModel|null)} message
+ */
+
+
+ CacheUserStorage.prototype.storeMessageFlagsToCache = function storeMessageFlagsToCache(message) {
+ if (message) {
+ this.setMessageFlagsToCache(message.folderFullNameRaw, message.uid, [message.unseen(), message.flagged(), message.answered(), message.forwarded(), message.isReadReceipt(), message.deletedMark()]);
+ }
+ };
+
+ /**
+ * @param {string} folder
+ * @param {string} uid
+ * @param {Array} flags
+ */
+
+
+ CacheUserStorage.prototype.storeMessageFlagsToCacheByFolderAndUid = function storeMessageFlagsToCacheByFolderAndUid(folder, uid, flags) {
+ if (_Utils2.default.isArray(flags) && 0 < flags.length) {
+ this.setMessageFlagsToCache(folder, uid, flags);
+ }
+ };
+
+ /**
+ * @param {string} folder
+ * @param {string} uid
+ * @param {number} setAction
+ */
+
+
+ CacheUserStorage.prototype.storeMessageFlagsToCacheBySetAction = function storeMessageFlagsToCacheBySetAction(folder, uid, setAction) {
+
+ var unread = 0;
+ var flags = this.getMessageFlagsFromCache(folder, uid);
+
+ if (_Utils2.default.isArray(flags) && 0 < flags.length) {
+ if (flags[0]) {
+ unread = 1;
+ }
+
+ switch (setAction) {
+ case _Enums.MessageSetAction.SetSeen:
+ flags[0] = false;
+ break;
+ case _Enums.MessageSetAction.UnsetSeen:
+ flags[0] = true;
+ break;
+ case _Enums.MessageSetAction.SetFlag:
+ flags[1] = true;
+ break;
+ case _Enums.MessageSetAction.UnsetFlag:
+ flags[1] = false;
+ break;
+ }
+
+ this.setMessageFlagsToCache(folder, uid, flags);
+ }
+
+ return unread;
+ };
+
+ return CacheUserStorage;
+ }();
+
+ module.exports = new CacheUserStorage();
+
+/***/ },
+/* 20 */,
+/* 21 */
+/*!***********************************!*\
+ !*** ./dev/Stores/User/Folder.js ***!
+ \***********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ Cache = __webpack_require__(/*! Common/Cache */ 19)
+ ;
+
+ /**
+ * @constructor
+ */
+ function FolderUserStore()
+ {
+ this.displaySpecSetting = ko.observable(true);
+
+ this.sentFolder = ko.observable('');
+ this.draftFolder = ko.observable('');
+ this.spamFolder = ko.observable('');
+ this.trashFolder = ko.observable('');
+ this.archiveFolder = ko.observable('');
+
+ this.namespace = '';
+
+ this.folderList = ko.observableArray([]);
+ this.folderList.optimized = ko.observable(false);
+ this.folderList.error = ko.observable('');
+
+ this.foldersLoading = ko.observable(false);
+ this.foldersCreating = ko.observable(false);
+ this.foldersDeleting = ko.observable(false);
+ this.foldersRenaming = ko.observable(false);
+
+ this.foldersInboxUnreadCount = ko.observable(0);
+
+ this.currentFolder = ko.observable(null).extend({'toggleSubscribe': [null,
+ function (oPrev) { if (oPrev) { oPrev.selected(false); }},
+ function (oNext) { if (oNext) { oNext.selected(true); }}
+ ]});
+
+ this.computers();
+ this.subscribers();
+ }
+
+ FolderUserStore.prototype.computers = function ()
+ {
+ this.draftFolderNotEnabled = ko.computed(function () {
+ return '' === this.draftFolder() || Consts.UNUSED_OPTION_VALUE === this.draftFolder();
+ }, this);
+
+ this.foldersListWithSingleInboxRootFolder = ko.computed(function () {
+ return !_.find(this.folderList(), function (oFolder) {
+ return oFolder && !oFolder.isSystemFolder() && oFolder.visible();
+ });
+ }, this);
+
+ this.currentFolderFullNameRaw = ko.computed(function () {
+ return this.currentFolder() ? this.currentFolder().fullNameRaw : '';
+ }, this);
+
+ this.currentFolderFullName = ko.computed(function () {
+ return this.currentFolder() ? this.currentFolder().fullName : '';
+ }, this);
+
+ this.currentFolderFullNameHash = ko.computed(function () {
+ return this.currentFolder() ? this.currentFolder().fullNameHash : '';
+ }, this);
+
+ this.foldersChanging = ko.computed(function () {
+ var
+ bLoading = this.foldersLoading(),
+ bCreating = this.foldersCreating(),
+ bDeleting = this.foldersDeleting(),
+ bRenaming = this.foldersRenaming()
+ ;
+ return bLoading || bCreating || bDeleting || bRenaming;
+ }, this);
+
+ this.folderListSystemNames = ko.computed(function () {
+
+ var
+ aList = [Cache.getFolderInboxName()],
+ aFolders = this.folderList(),
+ sSentFolder = this.sentFolder(),
+ sDraftFolder = this.draftFolder(),
+ sSpamFolder = this.spamFolder(),
+ sTrashFolder = this.trashFolder(),
+ sArchiveFolder = this.archiveFolder()
+ ;
+
+ if (Utils.isArray(aFolders) && 0 < aFolders.length)
+ {
+ if ('' !== sSentFolder && Consts.UNUSED_OPTION_VALUE !== sSentFolder)
+ {
+ aList.push(sSentFolder);
+ }
+ if ('' !== sDraftFolder && Consts.UNUSED_OPTION_VALUE !== sDraftFolder)
+ {
+ aList.push(sDraftFolder);
+ }
+ if ('' !== sSpamFolder && Consts.UNUSED_OPTION_VALUE !== sSpamFolder)
+ {
+ aList.push(sSpamFolder);
+ }
+ if ('' !== sTrashFolder && Consts.UNUSED_OPTION_VALUE !== sTrashFolder)
+ {
+ aList.push(sTrashFolder);
+ }
+ if ('' !== sArchiveFolder && Consts.UNUSED_OPTION_VALUE !== sArchiveFolder)
+ {
+ aList.push(sArchiveFolder);
+ }
+ }
+
+ return aList;
+
+ }, this);
+
+ this.folderListSystem = ko.computed(function () {
+ return _.compact(_.map(this.folderListSystemNames(), function (sName) {
+ return Cache.getFolderFromCacheList(sName);
+ }));
+ }, this);
+
+ this.folderMenuForMove = ko.computed(function () {
+ return Utils.folderListOptionsBuilder(this.folderListSystem(), this.folderList(), [
+ this.currentFolderFullNameRaw()
+ ], null, null, null, null, function (oItem) {
+ return oItem ? oItem.localName() : '';
+ });
+ }, this);
+
+ this.folderMenuForFilters = ko.computed(function () {
+ return Utils.folderListOptionsBuilder(this.folderListSystem(), this.folderList(),
+ ['INBOX'], [['', '']], null, null, null, function (oItem) {
+ return oItem ? oItem.localName() : '';
+ }
+ );
+ }, this);
+ };
+
+ FolderUserStore.prototype.subscribers = function ()
+ {
+ var
+ fRemoveSystemFolderType = function (observable) {
+ return function () {
+ var oFolder = Cache.getFolderFromCacheList(observable());
+ if (oFolder)
+ {
+ oFolder.type(Enums.FolderType.User);
+ }
+ };
+ },
+ fSetSystemFolderType = function (iType) {
+ return function (sValue) {
+ var oFolder = Cache.getFolderFromCacheList(sValue);
+ if (oFolder)
+ {
+ oFolder.type(iType);
+ }
+ };
+ }
+ ;
+
+ this.sentFolder.subscribe(fRemoveSystemFolderType(this.sentFolder), this, 'beforeChange');
+ this.draftFolder.subscribe(fRemoveSystemFolderType(this.draftFolder), this, 'beforeChange');
+ this.spamFolder.subscribe(fRemoveSystemFolderType(this.spamFolder), this, 'beforeChange');
+ this.trashFolder.subscribe(fRemoveSystemFolderType(this.trashFolder), this, 'beforeChange');
+ this.archiveFolder.subscribe(fRemoveSystemFolderType(this.archiveFolder), this, 'beforeChange');
+
+ this.sentFolder.subscribe(fSetSystemFolderType(Enums.FolderType.SentItems), this);
+ this.draftFolder.subscribe(fSetSystemFolderType(Enums.FolderType.Draft), this);
+ this.spamFolder.subscribe(fSetSystemFolderType(Enums.FolderType.Spam), this);
+ this.trashFolder.subscribe(fSetSystemFolderType(Enums.FolderType.Trash), this);
+ this.archiveFolder.subscribe(fSetSystemFolderType(Enums.FolderType.Archive), this);
+ };
+
+ /**
+ * @return {Array}
+ */
+ FolderUserStore.prototype.getNextFolderNames = function ()
+ {
+ var
+ aResult = [],
+ iLimit = 5,
+ iUtc = __webpack_require__(/*! Common/Momentor */ 26).momentNowUnix(),
+ iTimeout = iUtc - 60 * 5,
+ aTimeouts = [],
+ sInboxFolderName = Cache.getFolderInboxName(),
+ fSearchFunction = function (aList) {
+ _.each(aList, function (oFolder) {
+ if (oFolder && sInboxFolderName !== oFolder.fullNameRaw &&
+ oFolder.selectable && oFolder.existen &&
+ iTimeout > oFolder.interval &&
+ (oFolder.isSystemFolder() || (oFolder.subScribed() && oFolder.checkable()))
+ )
+ {
+ aTimeouts.push([oFolder.interval, oFolder.fullNameRaw]);
+ }
+
+ if (oFolder && 0 < oFolder.subFolders().length)
+ {
+ fSearchFunction(oFolder.subFolders());
+ }
+ });
+ }
+ ;
+
+ fSearchFunction(this.folderList());
+
+ aTimeouts.sort(function(a, b) {
+ if (a[0] < b[0]) {
+ return -1;
+ } else if (a[0] > b[0]) {
+ return 1;
+ }
+
+ return 0;
+ });
+
+ _.find(aTimeouts, function (aItem) {
+ var oFolder = Cache.getFolderFromCacheList(aItem[1]);
+ if (oFolder)
+ {
+ oFolder.interval = iUtc;
+ aResult.push(aItem[1]);
+ }
+
+ return iLimit <= aResult.length;
+ });
+
+ aResult = _.uniq(aResult);
+
+ return aResult;
+ };
+
+ module.exports = new FolderUserStore();
+
+ }());
+
+
+/***/ },
+/* 22 */,
+/* 23 */
+/*!********************************!*\
+ !*** ./dev/Common/Plugins.jsx ***!
+ \********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ var _Globals2 = _interopRequireDefault(_Globals);
+
+ var _Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var Plugins = function () {
+ function Plugins() {
+ _classCallCheck(this, Plugins);
+
+ this.oSimpleHooks = {};
+ this.aUserViewModelsHooks = [];
+ this.aAdminViewModelsHooks = [];
+ }
+
+ /**
+ * @param {string} name
+ * @param {Function} callback
+ */
+
+
+ Plugins.prototype.addHook = function addHook(name, callback) {
+ if (_Utils2.default.isFunc(callback)) {
+ if (!_Utils2.default.isArray(this.oSimpleHooks[name])) {
+ this.oSimpleHooks[name] = [];
+ }
+
+ this.oSimpleHooks[name].push(callback);
+ }
+ };
+
+ /**
+ * @param {string} name
+ * @param {Array=} args
+ */
+
+
+ Plugins.prototype.runHook = function runHook(name) {
+ var args = arguments.length <= 1 || arguments[1] === undefined ? [] : arguments[1];
+
+ if (_Utils2.default.isArray(this.oSimpleHooks[name])) {
+ _common._.each(this.oSimpleHooks[name], function (callback) {
+ callback.apply(null, args);
+ });
+ }
+ };
+
+ /**
+ * @param {string} name
+ * @return {?}
+ */
+
+
+ Plugins.prototype.mainSettingsGet = function mainSettingsGet(name) {
+ return _Settings2.default.settingsGet(name);
+ };
+
+ /**
+ * @param {Function} callback
+ * @param {string} action
+ * @param {Object=} parameters
+ * @param {?number=} timeout
+ */
+
+
+ Plugins.prototype.remoteRequest = function remoteRequest(callback, action, parameters, timeout) {
+ if (_Globals2.default.__APP__) {
+ _Globals2.default.__APP__.remote().defaultRequest(callback, 'Plugin' + action, parameters, timeout);
+ }
+ };
+
+ /**
+ * @param {Function} SettingsViewModelClass
+ * @param {string} labelName
+ * @param {string} template
+ * @param {string} route
+ */
+
+
+ Plugins.prototype.addSettingsViewModel = function addSettingsViewModel(SettingsViewModelClass, template, labelName, route) {
+ this.aUserViewModelsHooks.push([SettingsViewModelClass, template, labelName, route]);
+ };
+
+ /**
+ * @param {Function} SettingsViewModelClass
+ * @param {string} labelName
+ * @param {string} template
+ * @param {string} route
+ */
+
+
+ Plugins.prototype.addSettingsViewModelForAdmin = function addSettingsViewModelForAdmin(SettingsViewModelClass, template, labelName, route) {
+ this.aAdminViewModelsHooks.push([SettingsViewModelClass, template, labelName, route]);
+ };
+
+ /**
+ * @param {boolean} admin
+ */
+
+
+ Plugins.prototype.runSettingsViewModelHooks = function runSettingsViewModelHooks(admin) {
+ var Knoin = __webpack_require__(/*! Knoin/Knoin */ 5);
+ _common._.each(admin ? this.aAdminViewModelsHooks : this.aUserViewModelsHooks, function (view) {
+ Knoin.addSettingsViewModel(view[0], view[1], view[2], view[3]);
+ });
+ };
+
+ /**
+ * @param {string} pluginSection
+ * @param {string} name
+ * @return {?}
+ */
+
+
+ Plugins.prototype.settingsGet = function settingsGet(pluginSection, name) {
+ var plugins = _Settings2.default.settingsGet('Plugins');
+ plugins = plugins && !_Utils2.default.isUnd(plugins[pluginSection]) ? plugins[pluginSection] : null;
+ return plugins ? _Utils2.default.isUnd(plugins[name]) ? null : plugins[name] : null;
+ };
+
+ return Plugins;
+ }();
+
+ module.exports = new Plugins();
+
+/***/ },
+/* 24 */
+/*!*********************************!*\
+ !*** ./dev/Stores/User/App.jsx ***!
+ \*********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Enums = __webpack_require__(/*! Common/Enums */ 4);
+
+ var _Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ var _Globals2 = _interopRequireDefault(_Globals);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ var _AbstractApp = __webpack_require__(/*! Stores/AbstractApp */ 76);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var AppUserStore = function (_AbstractAppStore) {
+ _inherits(AppUserStore, _AbstractAppStore);
+
+ function AppUserStore() {
+ _classCallCheck(this, AppUserStore);
+
+ var _this = _possibleConstructorReturn(this, _AbstractAppStore.call(this));
+
+ _this.currentAudio = _ko2.default.observable('');
+
+ _this.focusedState = _ko2.default.observable(_Enums.Focused.None);
+
+ _this.focusedState.subscribe(function (value) {
+
+ switch (value) {
+ default:
+ break;
+ case _Enums.Focused.MessageList:
+ _Globals2.default.keyScope(_Enums.KeyState.MessageList);
+ break;
+ case _Enums.Focused.MessageView:
+ _Globals2.default.keyScope(_Enums.KeyState.MessageView);
+ break;
+ case _Enums.Focused.FolderList:
+ _Globals2.default.keyScope(_Enums.KeyState.FolderList);
+ break;
+ }
+ }, _this);
+
+ _this.projectHash = _ko2.default.observable('');
+ _this.threadsAllowed = _ko2.default.observable(false);
+
+ _this.composeInEdit = _ko2.default.observable(false);
+
+ _this.contactsAutosave = _ko2.default.observable(false);
+ _this.useLocalProxyForExternalImages = _ko2.default.observable(false);
+
+ _this.contactsIsAllowed = _ko2.default.observable(false);
+
+ _this.attachmentsActions = _ko2.default.observableArray([]);
+
+ _this.devEmail = '';
+ _this.devPassword = '';
+ return _this;
+ }
+
+ AppUserStore.prototype.populate = function populate() {
+
+ _AbstractAppStore.prototype.populate.call(this);
+
+ this.projectHash(_Settings2.default.settingsGet('ProjectHash'));
+
+ this.contactsAutosave(!!_Settings2.default.settingsGet('ContactsAutosave'));
+ this.useLocalProxyForExternalImages(!!_Settings2.default.settingsGet('UseLocalProxyForExternalImages'));
+
+ this.contactsIsAllowed(!!_Settings2.default.settingsGet('ContactsIsAllowed'));
+
+ var attachmentsActions = _Settings2.default.appSettingsGet('attachmentsActions');
+ this.attachmentsActions(_Utils2.default.isNonEmptyArray(attachmentsActions) ? attachmentsActions : []);
+
+ this.devEmail = _Settings2.default.settingsGet('DevEmail');
+ this.devPassword = _Settings2.default.settingsGet('DevPassword');
+ };
+
+ return AppUserStore;
+ }(_AbstractApp.AbstractAppStore);
+
+ module.exports = new AppUserStore();
+
+/***/ },
+/* 25 */
+/*!*******************************!*\
+ !*** ./dev/Common/Events.jsx ***!
+ \*******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Plugins = __webpack_require__(/*! Common/Plugins */ 23);
+
+ var _Plugins2 = _interopRequireDefault(_Plugins);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var Events = function () {
+ function Events() {
+ _classCallCheck(this, Events);
+
+ this.subs = {};
+ }
+
+ /**
+ * @param {string|Object} name
+ * @param {Function} func
+ * @param {Object=} context
+ * @return {Events}
+ */
+
+
+ Events.prototype.sub = function sub(name, func, context) {
+ var _this = this;
+
+ if (_Utils2.default.isObject(name)) {
+ context = func || null;
+ func = null;
+
+ _common._.each(name, function (subFunc, subName) {
+ _this.sub(subName, subFunc, context);
+ }, this);
+ } else {
+ if (_Utils2.default.isUnd(this.subs[name])) {
+ this.subs[name] = [];
+ }
+
+ this.subs[name].push([func, context]);
+ }
+
+ return this;
+ };
+
+ /**
+ * @param {string} name
+ * @param {Array=} args
+ * @return {Events}
+ */
+
+
+ Events.prototype.pub = function pub(name, args) {
+
+ _Plugins2.default.runHook('rl-pub', [name, args]);
+
+ if (!_Utils2.default.isUnd(this.subs[name])) {
+ _common._.each(this.subs[name], function (items) {
+ if (items[0]) {
+ items[0].apply(items[1] || null, args || []);
+ }
+ });
+ }
+
+ return this;
+ };
+
+ return Events;
+ }();
+
+ module.exports = new Events();
+
+/***/ },
+/* 26 */
+/*!*********************************!*\
+ !*** ./dev/Common/Momentor.jsx ***!
+ \*********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Translator = __webpack_require__(/*! Common/Translator */ 6);
+
+ var _Translator2 = _interopRequireDefault(_Translator);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var Momentor = function () {
+ function Momentor() {
+ var _this = this;
+
+ _classCallCheck(this, Momentor);
+
+ this._moment = null;
+ this._momentNow = 0;
+
+ this.updateMomentNow = _common._.debounce(function () {
+ _this._moment = (0, _common.moment)();
+ }, 500, true);
+
+ this.updateMomentNowUnix = _common._.debounce(function () {
+ _this._momentNow = (0, _common.moment)().unix();
+ }, 500, true);
+
+ this.format = _common._.bind(this.format, this);
+ }
+
+ Momentor.prototype.momentNow = function momentNow() {
+ this.updateMomentNow();
+ return this._moment || (0, _common.moment)();
+ };
+
+ Momentor.prototype.momentNowUnix = function momentNowUnix() {
+ this.updateMomentNowUnix();
+ return this._momentNow || 0;
+ };
+
+ /**
+ * @param {number} date
+ * @return {string}
+ */
+
+
+ Momentor.prototype.searchSubtractFormatDateHelper = function searchSubtractFormatDateHelper(date) {
+ return this.momentNow().clone().subtract('days', date).format('YYYY.MM.DD');
+ };
+
+ /**
+ * @param {Object} m
+ * @return {string}
+ */
+
+
+ Momentor.prototype.formatCustomShortDate = function formatCustomShortDate(m) {
+
+ var now = this.momentNow();
+ if (m && now) {
+ switch (true) {
+ case 4 >= now.diff(m, 'hours'):
+ return m.fromNow();
+ case now.format('L') === m.format('L'):
+ return _Translator2.default.i18n('MESSAGE_LIST/TODAY_AT', {
+ TIME: m.format('LT')
+ });
+ case now.clone().subtract('days', 1).format('L') === m.format('L'):
+ return _Translator2.default.i18n('MESSAGE_LIST/YESTERDAY_AT', {
+ TIME: m.format('LT')
+ });
+ case now.year() === m.year():
+ return m.format('D MMM.');
+ }
+ }
+
+ return m ? m.format('LL') : '';
+ };
+
+ /**
+ * @param {number} timeStampInUTC
+ * @param {string} format
+ * @return {string}
+ */
+
+
+ Momentor.prototype.format = function format(timeStampInUTC, _format) {
+
+ var m = null,
+ result = '';
+
+ var now = this.momentNowUnix();
+
+ timeStampInUTC = 0 < timeStampInUTC ? timeStampInUTC : 0 === timeStampInUTC ? now : 0;
+ timeStampInUTC = now < timeStampInUTC ? now : timeStampInUTC;
+
+ m = 0 < timeStampInUTC ? _common.moment.unix(timeStampInUTC) : null;
+
+ if (m && 1970 === m.year()) {
+ m = null;
+ }
+
+ if (m) {
+ switch (_format) {
+ case 'FROMNOW':
+ result = m.fromNow();
+ break;
+ case 'SHORT':
+ result = this.formatCustomShortDate(m);
+ break;
+ case 'FULL':
+ result = m.format('LLL');
+ break;
+ default:
+ result = m.format(_format);
+ break;
+ }
+ }
+
+ return result;
+ };
+
+ /**
+ * @param {Object} element
+ */
+
+
+ Momentor.prototype.momentToNode = function momentToNode(element) {
+
+ var key = '',
+ time = 0,
+ $el = (0, _common.$)(element);
+
+ time = $el.data('moment-time');
+ if (time) {
+ key = $el.data('moment-format');
+ if (key) {
+ $el.text(this.format(time, key));
+ }
+
+ key = $el.data('moment-format-title');
+ if (key) {
+ $el.attr('title', this.format(time, key));
+ }
+ }
+ };
+
+ /**
+ * @param {Object} elements
+ */
+
+
+ Momentor.prototype.momentToNodes = function momentToNodes(elements) {
+ var _this2 = this;
+
+ _common._.defer(function () {
+ (0, _common.$)('.moment', elements).each(function (index, item) {
+ _this2.momentToNode(item);
+ });
+ });
+ };
+
+ Momentor.prototype.reload = function reload() {
+ this.momentToNodes(_common.window.document);
+ };
+
+ return Momentor;
+ }();
+
+ module.exports = new Momentor();
+
+/***/ },
+/* 27 */
+/*!************************************!*\
+ !*** ./dev/Knoin/AbstractModel.js ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1)
+ ;
+
+ /**
+ * @constructor
+ *
+ * @param {string} sModelName
+ */
+ function AbstractModel(sModelName)
+ {
+ this.sModelName = sModelName || '';
+ this.disposables = [];
+ }
+
+ /**
+ * @param {Array|Object} mInputValue
+ */
+ AbstractModel.prototype.regDisposables = function (mInputValue)
+ {
+ if (Utils.isArray(mInputValue))
+ {
+ _.each(mInputValue, function (mValue) {
+ this.disposables.push(mValue);
+ }, this);
+ }
+ else if (mInputValue)
+ {
+ this.disposables.push(mInputValue);
+ }
+
+ };
+
+ AbstractModel.prototype.onDestroy = function ()
+ {
+ Utils.disposeObject(this);
+ };
+
+ module.exports = AbstractModel;
+
+ }());
+
+
+
+/***/ },
+/* 28 */
+/*!*************************************!*\
+ !*** ./dev/Stores/User/Settings.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Events = __webpack_require__(/*! Common/Events */ 25),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function SettingsUserStore()
+ {
+ this.iAutoLogoutTimer = 0;
+
+ this.layout = ko.observable(Enums.Layout.SidePreview)
+ .extend({'limitedList': [
+ Enums.Layout.SidePreview, Enums.Layout.BottomPreview, Enums.Layout.NoPreview
+ ]});
+
+ this.editorDefaultType = ko.observable(Enums.EditorDefaultType.Html)
+ .extend({'limitedList': [
+ Enums.EditorDefaultType.Html, Enums.EditorDefaultType.Plain,
+ Enums.EditorDefaultType.HtmlForced, Enums.EditorDefaultType.PlainForced
+ ]});
+
+ this.messagesPerPage = ko.observable(Consts.MESSAGES_PER_PAGE)
+ .extend({'limitedList': Consts.MESSAGES_PER_PAGE_VALUES});
+
+ this.showImages = ko.observable(false);
+ this.useCheckboxesInList = ko.observable(true);
+ this.useThreads = ko.observable(false);
+ this.replySameFolder = ko.observable(false);
+
+ this.autoLogout = ko.observable(30);
+
+ this.computers();
+ this.subscribers();
+ }
+
+ SettingsUserStore.prototype.computers = function ()
+ {
+ this.usePreviewPane = ko.computed(function () {
+ return Enums.Layout.NoPreview !== this.layout();
+ }, this);
+ };
+
+ SettingsUserStore.prototype.subscribers = function ()
+ {
+ this.layout.subscribe(function (nValue) {
+
+ Globals.$html.toggleClass('rl-no-preview-pane', Enums.Layout.NoPreview === nValue);
+ Globals.$html.toggleClass('rl-side-preview-pane', Enums.Layout.SidePreview === nValue);
+ Globals.$html.toggleClass('rl-bottom-preview-pane', Enums.Layout.BottomPreview === nValue);
+ Globals.$html.toggleClass('rl-mobile-layout', Enums.Layout.Mobile === nValue);
+
+ Events.pub('layout', [nValue]);
+ });
+ };
+
+ SettingsUserStore.prototype.populate = function ()
+ {
+ this.layout(Utils.pInt(Settings.settingsGet('Layout')));
+ this.editorDefaultType(Settings.settingsGet('EditorDefaultType'));
+
+ this.autoLogout(Utils.pInt(Settings.settingsGet('AutoLogout')));
+ this.messagesPerPage(Settings.settingsGet('MPP'));
+
+ this.showImages(!!Settings.settingsGet('ShowImages'));
+ this.useCheckboxesInList(!!Settings.settingsGet('UseCheckboxesInList'));
+ this.useThreads(!!Settings.settingsGet('UseThreads'));
+ this.replySameFolder(!!Settings.settingsGet('ReplySameFolder'));
+
+ var self = this;
+
+ Events.sub('rl.auto-logout-refresh', function () {
+ window.clearTimeout(self.iAutoLogoutTimer);
+ if (0 < self.autoLogout())
+ {
+ self.iAutoLogoutTimer = window.setTimeout(function () {
+ Events.pub('rl.auto-logout');
+ }, self.autoLogout() * 1000 * 60);
+ }
+ });
+
+ Events.pub('rl.auto-logout-refresh');
+ };
+
+ module.exports = new SettingsUserStore();
+
+ }());
+
+
+/***/ },
+/* 29 */
+/*!***********************************!*\
+ !*** ./dev/View/Popup/Compose.js ***!
+ \***********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ /* global require, module */
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+ JSON = __webpack_require__(/*! JSON */ 36),
+ Jua = __webpack_require__(/*! Jua */ 80),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Events = __webpack_require__(/*! Common/Events */ 25),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+ HtmlEditor = __webpack_require__(/*! Common/HtmlEditor */ 45),
+
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+ Momentor = __webpack_require__(/*! Common/Momentor */ 26),
+
+ Cache = __webpack_require__(/*! Common/Cache */ 19),
+
+ AppStore = __webpack_require__(/*! Stores/User/App */ 24),
+ SettingsStore = __webpack_require__(/*! Stores/User/Settings */ 28),
+ IdentityStore = __webpack_require__(/*! Stores/User/Identity */ 53),
+ AccountStore = __webpack_require__(/*! Stores/User/Account */ 31),
+ FolderStore = __webpack_require__(/*! Stores/User/Folder */ 21),
+ PgpStore = __webpack_require__(/*! Stores/User/Pgp */ 33),
+ MessageStore = __webpack_require__(/*! Stores/User/Message */ 32),
+ SocialStore = __webpack_require__(/*! Stores/Social */ 34),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15),
+
+ ComposeAttachmentModel = __webpack_require__(/*! Model/ComposeAttachment */ 102),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function ComposePopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsCompose');
+
+ var
+ self = this,
+ fEmailOutInHelper = function (self, oIdentity, sName, bIn) {
+ if (oIdentity && self && oIdentity[sName]() && (bIn ? true : self[sName]()))
+ {
+ var
+ sIdentityEmail = oIdentity[sName](),
+ aList = Utils.trim(self[sName]()).split(/[,]/)
+ ;
+
+ aList = _.filter(aList, function (sEmail) {
+ sEmail = Utils.trim(sEmail);
+ return sEmail && Utils.trim(sIdentityEmail) !== sEmail;
+ });
+
+ if (bIn)
+ {
+ aList.push(sIdentityEmail);
+ }
+
+ self[sName](aList.join(','));
+ }
+ }
+ ;
+
+ this.oLastMessage = null;
+ this.oEditor = null;
+ this.aDraftInfo = null;
+ this.sInReplyTo = '';
+ this.bFromDraft = false;
+ this.sReferences = '';
+
+ this.sLastFocusedField = 'to';
+
+ this.resizerTrigger = _.bind(this.resizerTrigger, this);
+
+ this.allowContacts = !!AppStore.contactsIsAllowed();
+ this.allowFolders = !!Settings.capa(Enums.Capa.Folders);
+
+ this.bSkipNextHide = false;
+ this.composeInEdit = AppStore.composeInEdit;
+ this.editorDefaultType = SettingsStore.editorDefaultType;
+
+ this.capaOpenPGP = PgpStore.capaOpenPGP;
+
+ this.identitiesDropdownTrigger = ko.observable(false);
+
+ this.to = ko.observable('');
+ this.to.focused = ko.observable(false);
+ this.cc = ko.observable('');
+ this.cc.focused = ko.observable(false);
+ this.bcc = ko.observable('');
+ this.bcc.focused = ko.observable(false);
+ this.replyTo = ko.observable('');
+ this.replyTo.focused = ko.observable(false);
+
+ ko.computed(function () {
+ switch (true)
+ {
+ case this.to.focused():
+ this.sLastFocusedField = 'to';
+ break;
+ case this.cc.focused():
+ this.sLastFocusedField = 'cc';
+ break;
+ case this.bcc.focused():
+ this.sLastFocusedField = 'bcc';
+ break;
+ }
+ }, this).extend({'notify': 'always'});
+
+ this.subject = ko.observable('');
+ this.subject.focused = ko.observable(false);
+
+ this.isHtml = ko.observable(false);
+
+ this.requestDsn = ko.observable(false);
+ this.requestReadReceipt = ko.observable(false);
+ this.markAsImportant = ko.observable(false);
+
+ this.sendError = ko.observable(false);
+ this.sendSuccessButSaveError = ko.observable(false);
+ this.savedError = ko.observable(false);
+
+ this.sendButtonSuccess = ko.computed(function () {
+ return !this.sendError() && !this.sendSuccessButSaveError();
+ }, this);
+
+ this.sendErrorDesc = ko.observable('');
+ this.savedErrorDesc = ko.observable('');
+
+ this.sendError.subscribe(function (bValue) {
+ if (!bValue)
+ {
+ this.sendErrorDesc('');
+ }
+ }, this);
+
+ this.savedError.subscribe(function (bValue) {
+ if (!bValue)
+ {
+ this.savedErrorDesc('');
+ }
+ }, this);
+
+ this.sendSuccessButSaveError.subscribe(function (bValue) {
+ if (!bValue)
+ {
+ this.savedErrorDesc('');
+ }
+ }, this);
+
+ this.savedTime = ko.observable(0);
+ this.savedTimeText = ko.computed(function () {
+ return 0 < this.savedTime() ? Translator.i18n('COMPOSE/SAVED_TIME', {
+ 'TIME': Momentor.format(this.savedTime() - 1, 'LT')
+ }) : '';
+ }, this);
+
+ this.emptyToError = ko.observable(false);
+ this.emptyToErrorTooltip = ko.computed(function () {
+ return this.emptyToError() ? Translator.i18n('COMPOSE/EMPTY_TO_ERROR_DESC') : '';
+ }, this);
+
+ this.attachmentsInProcessError = ko.observable(false);
+ this.attachmentsInErrorError = ko.observable(false);
+
+ this.attachmentsErrorTooltip = ko.computed(function () {
+
+ var sResult = '';
+ switch (true)
+ {
+ case this.attachmentsInProcessError():
+ sResult = Translator.i18n('COMPOSE/ATTACHMENTS_UPLOAD_ERROR_DESC');
+ break;
+ case this.attachmentsInErrorError():
+ sResult = Translator.i18n('COMPOSE/ATTACHMENTS_ERROR_DESC');
+ break;
+ }
+
+ return sResult;
+
+ }, this);
+
+ this.showCc = ko.observable(false);
+ this.showBcc = ko.observable(false);
+ this.showReplyTo = ko.observable(false);
+
+ this.cc.subscribe(function (aValue) {
+ if (false === self.showCc() && 0 < aValue.length)
+ {
+ self.showCc(true);
+ }
+ }, this);
+
+ this.bcc.subscribe(function (aValue) {
+ if (false === self.showBcc() && 0 < aValue.length)
+ {
+ self.showBcc(true);
+ }
+ }, this);
+
+ this.replyTo.subscribe(function (aValue) {
+ if (false === self.showReplyTo() && 0 < aValue.length)
+ {
+ self.showReplyTo(true);
+ }
+ }, this);
+
+ this.draftFolder = ko.observable('');
+ this.draftUid = ko.observable('');
+ this.sending = ko.observable(false);
+ this.saving = ko.observable(false);
+ this.attachments = ko.observableArray([]);
+
+ this.attachmentsInProcess = this.attachments.filter(function (oItem) {
+ return oItem && !oItem.complete();
+ });
+
+ this.attachmentsInReady = this.attachments.filter(function (oItem) {
+ return oItem && oItem.complete();
+ });
+
+ this.attachmentsInError = this.attachments.filter(function (oItem) {
+ return oItem && '' !== oItem.error();
+ });
+
+ this.attachmentsCount = ko.computed(function () {
+ return this.attachments().length;
+ }, this);
+
+ this.attachmentsInErrorCount = ko.computed(function () {
+ return this.attachmentsInError().length;
+ }, this);
+
+ this.attachmentsInProcessCount = ko.computed(function () {
+ return this.attachmentsInProcess().length;
+ }, this);
+
+ this.isDraftFolderMessage = ko.computed(function () {
+ return '' !== this.draftFolder() && '' !== this.draftUid();
+ }, this);
+
+ this.attachmentsPlace = ko.observable(false);
+
+ this.attachments.subscribe(this.resizerTrigger);
+ this.attachmentsPlace.subscribe(this.resizerTrigger);
+
+ this.attachmentsInErrorCount.subscribe(function (iN) {
+ if (0 === iN)
+ {
+ this.attachmentsInErrorError(false);
+ }
+ }, this);
+
+ this.composeUploaderButton = ko.observable(null);
+ this.composeUploaderDropPlace = ko.observable(null);
+ this.dragAndDropEnabled = ko.observable(false);
+ this.dragAndDropOver = ko.observable(false).extend({'throttle': 1});
+ this.dragAndDropVisible = ko.observable(false).extend({'throttle': 1});
+ this.attacheMultipleAllowed = ko.observable(false);
+ this.addAttachmentEnabled = ko.observable(false);
+
+ this.composeEditorArea = ko.observable(null);
+
+ this.identities = IdentityStore.identities;
+ this.identitiesOptions = ko.computed(function () {
+ return _.map(IdentityStore.identities(), function (oItem) {
+ return {
+ 'item': oItem,
+ 'optValue': oItem.id(),
+ 'optText': oItem.formattedName()
+ };
+ });
+ }, this);
+
+ this.currentIdentity = ko.observable(
+ this.identities()[0] ? this.identities()[0] : null);
+
+ this.currentIdentity.extend({'toggleSubscribe': [this,
+ function (oIdentity) {
+ fEmailOutInHelper(this, oIdentity, 'bcc');
+ fEmailOutInHelper(this, oIdentity, 'replyTo');
+ }, function (oIdentity) {
+ fEmailOutInHelper(this, oIdentity, 'bcc', true);
+ fEmailOutInHelper(this, oIdentity, 'replyTo', true);
+ }
+ ]});
+
+ this.currentIdentityView = ko.computed(function () {
+ var oItem = this.currentIdentity();
+ return oItem ? oItem.formattedName() : 'unknown';
+ }, this);
+
+ this.to.subscribe(function (sValue) {
+ if (this.emptyToError() && 0 < sValue.length)
+ {
+ this.emptyToError(false);
+ }
+ }, this);
+
+ this.attachmentsInProcess.subscribe(function (aValue) {
+ if (this.attachmentsInProcessError() && Utils.isArray(aValue) && 0 === aValue.length)
+ {
+ this.attachmentsInProcessError(false);
+ }
+ }, this);
+
+ this.resizer = ko.observable(false).extend({'throttle': 50});
+
+ this.resizer.subscribe(_.bind(function () {
+ if (this.oEditor){
+ this.oEditor.resize();
+ }
+ }, this));
+
+ this.canBeSentOrSaved = ko.computed(function () {
+ return !this.sending() && !this.saving();
+ }, this);
+
+ this.deleteCommand = Utils.createCommand(this, function () {
+
+ __webpack_require__(/*! App/User */ 7).default.deleteMessagesFromFolderWithoutCheck(this.draftFolder(), [this.draftUid()]);
+ kn.hideScreenPopup(ComposePopupView);
+
+ }, function () {
+ return this.isDraftFolderMessage();
+ });
+
+ this.sendMessageResponse = _.bind(this.sendMessageResponse, this);
+ this.saveMessageResponse = _.bind(this.saveMessageResponse, this);
+
+ this.sendCommand = Utils.createCommand(this, function () {
+
+ var
+ sTo = Utils.trim(this.to()),
+ sCc = Utils.trim(this.cc()),
+ sBcc = Utils.trim(this.bcc()),
+ sSentFolder = FolderStore.sentFolder(),
+ aFlagsCache = []
+ ;
+
+ this.attachmentsInProcessError(false);
+ this.attachmentsInErrorError(false);
+ this.emptyToError(false);
+
+ if (0 < this.attachmentsInProcess().length)
+ {
+ this.attachmentsInProcessError(true);
+ this.attachmentsPlace(true);
+ }
+ else if (0 < this.attachmentsInError().length)
+ {
+ this.attachmentsInErrorError(true);
+ this.attachmentsPlace(true);
+ }
+
+ if ('' === sTo && '' === sCc && '' === sBcc)
+ {
+ this.emptyToError(true);
+ }
+
+ if (!this.emptyToError() && !this.attachmentsInErrorError() && !this.attachmentsInProcessError())
+ {
+ if (SettingsStore.replySameFolder())
+ {
+ if (Utils.isArray(this.aDraftInfo) && 3 === this.aDraftInfo.length && Utils.isNormal(this.aDraftInfo[2]) && 0 < this.aDraftInfo[2].length)
+ {
+ sSentFolder = this.aDraftInfo[2];
+ }
+ }
+
+ if (!this.allowFolders)
+ {
+ sSentFolder = Consts.UNUSED_OPTION_VALUE;
+ }
+
+ if ('' === sSentFolder)
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/FolderSystem */ 52), [Enums.SetSystemFoldersNotification.Sent]);
+ }
+ else
+ {
+ this.sendError(false);
+ this.sending(true);
+
+ if (Utils.isArray(this.aDraftInfo) && 3 === this.aDraftInfo.length)
+ {
+ aFlagsCache = Cache.getMessageFlagsFromCache(this.aDraftInfo[2], this.aDraftInfo[1]);
+ if (aFlagsCache)
+ {
+ if ('forward' === this.aDraftInfo[0])
+ {
+ aFlagsCache[3] = true;
+ }
+ else
+ {
+ aFlagsCache[2] = true;
+ }
+
+ Cache.setMessageFlagsToCache(this.aDraftInfo[2], this.aDraftInfo[1], aFlagsCache);
+ __webpack_require__(/*! App/User */ 7).default.reloadFlagsCurrentMessageListAndMessageFromCache();
+ Cache.setFolderHash(this.aDraftInfo[2], '');
+ }
+ }
+
+ sSentFolder = Consts.UNUSED_OPTION_VALUE === sSentFolder ? '' : sSentFolder;
+
+ Cache.setFolderHash(this.draftFolder(), '');
+ Cache.setFolderHash(sSentFolder, '');
+
+ Remote.sendMessage(
+ this.sendMessageResponse,
+ this.currentIdentity() ? this.currentIdentity().id() : '',
+ this.draftFolder(),
+ this.draftUid(),
+ sSentFolder,
+ sTo,
+ this.cc(),
+ this.bcc(),
+ this.replyTo(),
+ this.subject(),
+ this.oEditor ? this.oEditor.isHtml() : false,
+ this.oEditor ? this.oEditor.getData(true, true) : '',
+ this.prepearAttachmentsForSendOrSave(),
+ this.aDraftInfo,
+ this.sInReplyTo,
+ this.sReferences,
+ this.requestDsn(),
+ this.requestReadReceipt(),
+ this.markAsImportant()
+ );
+ }
+ }
+
+ }, this.canBeSentOrSaved);
+
+ this.saveCommand = Utils.createCommand(this, function () {
+
+ if (!this.allowFolders)
+ {
+ return false;
+ }
+
+ if (FolderStore.draftFolderNotEnabled())
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/FolderSystem */ 52), [Enums.SetSystemFoldersNotification.Draft]);
+ }
+ else
+ {
+ this.savedError(false);
+ this.saving(true);
+
+ this.autosaveStart();
+
+ Cache.setFolderHash(FolderStore.draftFolder(), '');
+
+ Remote.saveMessage(
+ this.saveMessageResponse,
+ this.currentIdentity() ? this.currentIdentity().id() : '',
+ this.draftFolder(),
+ this.draftUid(),
+ FolderStore.draftFolder(),
+ this.to(),
+ this.cc(),
+ this.bcc(),
+ this.replyTo(),
+ this.subject(),
+ this.oEditor ? this.oEditor.isHtml() : false,
+ this.oEditor ? this.oEditor.getData(true) : '',
+ this.prepearAttachmentsForSendOrSave(),
+ this.aDraftInfo,
+ this.sInReplyTo,
+ this.sReferences,
+ this.markAsImportant()
+ );
+ }
+
+ }, this.canBeSentOrSaved);
+
+ this.skipCommand = Utils.createCommand(this, function () {
+
+ this.bSkipNextHide = true;
+
+ if (this.modalVisibility() && !this.saving() && !this.sending() &&
+ !FolderStore.draftFolderNotEnabled())
+ {
+ this.saveCommand();
+ }
+
+ this.tryToClosePopup();
+
+ }, this.canBeSentOrSaved);
+
+ this.contactsCommand = Utils.createCommand(this, function () {
+
+ if (this.allowContacts)
+ {
+ this.skipCommand();
+
+ var self = this;
+
+ _.delay(function () {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/Contacts */ 62),
+ [true, self.sLastFocusedField]);
+ }, 200);
+ }
+
+ }, function () {
+ return this.allowContacts;
+ });
+
+ Events.sub('interval.2m', function () {
+
+ if (this.modalVisibility() && !FolderStore.draftFolderNotEnabled() && !this.isEmptyForm(false) &&
+ !this.saving() && !this.sending() && !this.savedError())
+ {
+ this.saveCommand();
+ }
+ }, this);
+
+ this.showCc.subscribe(this.resizerTrigger);
+ this.showBcc.subscribe(this.resizerTrigger);
+ this.showReplyTo.subscribe(this.resizerTrigger);
+
+ this.dropboxEnabled = SocialStore.dropbox.enabled;
+ this.dropboxApiKey = SocialStore.dropbox.apiKey;
+
+ this.dropboxCommand = Utils.createCommand(this, function () {
+
+ if (window.Dropbox)
+ {
+ window.Dropbox.choose({
+ 'success': function(aFiles) {
+
+ if (aFiles && aFiles[0] && aFiles[0]['link'])
+ {
+ self.addDropboxAttachment(aFiles[0]);
+ }
+ },
+ 'linkType': 'direct',
+ 'multiselect': false
+ });
+ }
+
+ return true;
+
+ }, function () {
+ return this.dropboxEnabled();
+ });
+
+ this.driveEnabled = ko.observable(Globals.bXMLHttpRequestSupported &&
+ !!Settings.settingsGet('AllowGoogleSocial') && !!Settings.settingsGet('AllowGoogleSocialDrive') &&
+ !!Settings.settingsGet('GoogleClientID') && !!Settings.settingsGet('GoogleApiKey'));
+
+ this.driveVisible = ko.observable(false);
+
+ this.driveCommand = Utils.createCommand(this, function () {
+
+ this.driveOpenPopup();
+ return true;
+
+ }, function () {
+ return this.driveEnabled();
+ });
+
+ this.driveCallback = _.bind(this.driveCallback, this);
+
+ this.onMessageUploadAttachments = _.bind(this.onMessageUploadAttachments, this);
+
+ this.bDisabeCloseOnEsc = true;
+ this.sDefaultKeyScope = Enums.KeyState.Compose;
+
+ this.tryToClosePopup = _.debounce(_.bind(this.tryToClosePopup, this), 200);
+
+ this.emailsSource = _.bind(this.emailsSource, this);
+ this.autosaveFunction = _.bind(this.autosaveFunction, this);
+
+ this.iTimer = 0;
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/Compose', 'PopupsComposeViewModel'], ComposePopupView);
+ _.extend(ComposePopupView.prototype, AbstractView.prototype);
+
+ ComposePopupView.prototype.autosaveFunction = function ()
+ {
+ if (this.modalVisibility() && !FolderStore.draftFolderNotEnabled() && !this.isEmptyForm(false) &&
+ !this.saving() && !this.sending() && !this.savedError())
+ {
+ this.saveCommand();
+ }
+
+ this.autosaveStart();
+ };
+
+ ComposePopupView.prototype.autosaveStart = function ()
+ {
+ window.clearTimeout(this.iTimer);
+ this.iTimer = window.setTimeout(this.autosaveFunction, 1000 * 60 * 1);
+ };
+
+ ComposePopupView.prototype.autosaveStop = function ()
+ {
+ window.clearTimeout(this.iTimer);
+ };
+
+ ComposePopupView.prototype.emailsSource = function (oData, fResponse)
+ {
+ __webpack_require__(/*! App/User */ 7).default.getAutocomplete(oData.term, function (aData) {
+ fResponse(_.map(aData, function (oEmailItem) {
+ return oEmailItem.toLine(false);
+ }));
+ });
+ };
+
+ ComposePopupView.prototype.openOpenPgpPopup = function ()
+ {
+ if (PgpStore.capaOpenPGP() && this.oEditor && !this.oEditor.isHtml())
+ {
+ var self = this;
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/ComposeOpenPgp */ 145), [
+ function (sResult) {
+ self.editor(function (oEditor) {
+ oEditor.setPlain(sResult);
+ });
+ },
+ this.oEditor.getData(false, true),
+ this.currentIdentity(),
+ this.to(),
+ this.cc(),
+ this.bcc()
+ ]);
+ }
+ };
+
+ ComposePopupView.prototype.reloadDraftFolder = function ()
+ {
+ var
+ sDraftFolder = FolderStore.draftFolder()
+ ;
+
+ if ('' !== sDraftFolder && Consts.UNUSED_OPTION_VALUE !== sDraftFolder)
+ {
+ Cache.setFolderHash(sDraftFolder, '');
+ if (FolderStore.currentFolderFullNameRaw() === sDraftFolder)
+ {
+ __webpack_require__(/*! App/User */ 7).default.reloadMessageList(true);
+ }
+ else
+ {
+ __webpack_require__(/*! App/User */ 7).default.folderInformation(sDraftFolder);
+ }
+ }
+ };
+
+ ComposePopupView.prototype.findIdentityByMessage = function (sComposeType, oMessage)
+ {
+ var
+ aIdentities = IdentityStore.identities(),
+ iResultIndex = 1000,
+ oResultIdentity = null,
+ oIdentitiesCache = {},
+
+ fEachHelper = function (oItem) {
+
+ if (oItem && oItem.email && oIdentitiesCache[oItem.email])
+ {
+ if (!oResultIdentity || iResultIndex > oIdentitiesCache[oItem.email][1])
+ {
+ oResultIdentity = oIdentitiesCache[oItem.email][0];
+ iResultIndex = oIdentitiesCache[oItem.email][1];
+ }
+ }
+ }
+ ;
+
+ _.each(aIdentities, function (oItem, iIndex) {
+ oIdentitiesCache[oItem.email()] = [oItem, iIndex];
+ });
+
+ if (oMessage)
+ {
+ switch (sComposeType)
+ {
+ case Enums.ComposeType.Empty:
+ break;
+ case Enums.ComposeType.Reply:
+ case Enums.ComposeType.ReplyAll:
+ case Enums.ComposeType.Forward:
+ case Enums.ComposeType.ForwardAsAttachment:
+ _.each(_.union(oMessage.to, oMessage.cc, oMessage.bcc), fEachHelper);
+ if (!oResultIdentity) {
+ _.each(oMessage.deliveredTo, fEachHelper);
+ }
+ break;
+ case Enums.ComposeType.Draft:
+ _.each(_.union(oMessage.from, oMessage.replyTo), fEachHelper);
+ break;
+ }
+ }
+
+ return oResultIdentity || aIdentities[0] || null;
+ };
+
+ ComposePopupView.prototype.selectIdentity = function (oIdentity)
+ {
+ if (oIdentity && oIdentity.item)
+ {
+ this.currentIdentity(oIdentity.item);
+ this.setSignatureFromIdentity(oIdentity.item);
+ }
+ };
+
+ ComposePopupView.prototype.sendMessageResponse = function (sResult, oData)
+ {
+ var
+ bResult = false,
+ sMessage = ''
+ ;
+
+ this.sending(false);
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ bResult = true;
+ if (this.modalVisibility())
+ {
+ Utils.delegateRun(this, 'closeCommand');
+ }
+ }
+
+ if (this.modalVisibility() && !bResult)
+ {
+ if (oData && Enums.Notification.CantSaveMessage === oData.ErrorCode)
+ {
+ this.sendSuccessButSaveError(true);
+ this.savedErrorDesc(Utils.trim(Translator.i18n('COMPOSE/SAVED_ERROR_ON_SEND')));
+ }
+ else
+ {
+ sMessage = Translator.getNotification(oData && oData.ErrorCode ? oData.ErrorCode : Enums.Notification.CantSendMessage,
+ oData && oData.ErrorMessage ? oData.ErrorMessage : '');
+
+ this.sendError(true);
+ this.sendErrorDesc(sMessage || Translator.getNotification(Enums.Notification.CantSendMessage));
+ }
+ }
+
+ this.reloadDraftFolder();
+ };
+
+ ComposePopupView.prototype.saveMessageResponse = function (sResult, oData)
+ {
+ var
+ bResult = false,
+ oMessage = null
+ ;
+
+ this.saving(false);
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ if (oData.Result.NewFolder && oData.Result.NewUid)
+ {
+ bResult = true;
+
+ if (this.bFromDraft)
+ {
+ oMessage = MessageStore.message();
+ if (oMessage && this.draftFolder() === oMessage.folderFullNameRaw && this.draftUid() === oMessage.uid)
+ {
+ MessageStore.message(null);
+ }
+ }
+
+ this.draftFolder(oData.Result.NewFolder);
+ this.draftUid(oData.Result.NewUid);
+
+ this.savedTime(window.Math.round((new window.Date()).getTime() / 1000));
+
+ if (this.bFromDraft)
+ {
+ Cache.setFolderHash(this.draftFolder(), '');
+ }
+ }
+ }
+
+ if (!bResult)
+ {
+ this.savedError(true);
+ this.savedErrorDesc(Translator.getNotification(Enums.Notification.CantSaveMessage));
+ }
+
+ this.reloadDraftFolder();
+ };
+
+ ComposePopupView.prototype.onHide = function ()
+ {
+ this.autosaveStop();
+
+ if (!this.bSkipNextHide)
+ {
+ AppStore.composeInEdit(false);
+ this.reset();
+ }
+
+ this.bSkipNextHide = false;
+
+ this.to.focused(false);
+
+ kn.routeOn();
+ };
+
+ ComposePopupView.prototype.editor = function (fOnInit)
+ {
+ if (fOnInit)
+ {
+ var self = this;
+ if (!this.oEditor && this.composeEditorArea())
+ {
+ //_.delay(function () {
+ self.oEditor = new HtmlEditor(self.composeEditorArea(), null, function () {
+ fOnInit(self.oEditor);
+ self.resizerTrigger();
+ }, function (bHtml) {
+ self.isHtml(!!bHtml);
+ });
+ //}, 1000);
+ }
+ else if (this.oEditor)
+ {
+ fOnInit(this.oEditor);
+ this.resizerTrigger();
+ }
+ }
+ };
+
+ ComposePopupView.prototype.converSignature = function (sSignature)
+ {
+ var
+ iLimit = 10,
+ oMatch = null,
+ aMoments = [],
+ oMomentRegx = /{{MOMENT:([^}]+)}}/g,
+ sFrom = ''
+ ;
+
+ sSignature = sSignature.replace(/[\r]/g, '');
+
+ sFrom = this.oLastMessage ? this.emailArrayToStringLineHelper(this.oLastMessage.from, true) : '';
+ if ('' !== sFrom)
+ {
+ sSignature = sSignature.replace(/{{FROM-FULL}}/g, sFrom);
+
+ if (-1 === sFrom.indexOf(' ') && 0 < sFrom.indexOf('@'))
+ {
+ sFrom = sFrom.replace(/@[\S]+/, '');
+ }
+
+ sSignature = sSignature.replace(/{{FROM}}/g, sFrom);
+ }
+
+ sSignature = sSignature.replace(/[\s]{1,2}{{FROM}}/g, '{{FROM}}');
+ sSignature = sSignature.replace(/[\s]{1,2}{{FROM-FULL}}/g, '{{FROM-FULL}}');
+
+ sSignature = sSignature.replace(/{{FROM}}/g, '');
+ sSignature = sSignature.replace(/{{FROM-FULL}}/g, '');
+
+ if (-1 < sSignature.indexOf('{{DATE}}'))
+ {
+ sSignature = sSignature.replace(/{{DATE}}/g, Momentor.format(0, 'llll'));
+ }
+
+ if (-1 < sSignature.indexOf('{{TIME}}'))
+ {
+ sSignature = sSignature.replace(/{{TIME}}/g, Momentor.format(0, 'LT'));
+ }
+ if (-1 < sSignature.indexOf('{{MOMENT:'))
+ {
+ try
+ {
+ while ((oMatch = oMomentRegx.exec(sSignature)) !== null)
+ {
+ if (oMatch && oMatch[0] && oMatch[1])
+ {
+ aMoments.push([oMatch[0], oMatch[1]]);
+ }
+
+ iLimit--;
+ if (0 === iLimit)
+ {
+ break;
+ }
+ }
+
+ if (aMoments && 0 < aMoments.length)
+ {
+ _.each(aMoments, function (aData) {
+ sSignature = sSignature.replace(
+ aData[0], Momentor.format(0, aData[1]));
+ });
+ }
+
+ sSignature = sSignature.replace(/{{MOMENT:[^}]+}}/g, '');
+ }
+ catch(e) {}
+ }
+
+ return sSignature;
+ };
+
+ ComposePopupView.prototype.setSignatureFromIdentity = function (oIdentity)
+ {
+ if (oIdentity)
+ {
+ var self = this;
+ this.editor(function (oEditor) {
+ var bHtml = false, sSignature = oIdentity.signature();
+ if ('' !== sSignature)
+ {
+ if (':HTML:' === sSignature.substr(0, 6))
+ {
+ bHtml = true;
+ sSignature = sSignature.substr(6);
+ }
+ }
+
+ oEditor.setSignature(self.converSignature(sSignature),
+ bHtml, !!oIdentity.signatureInsertBefore());
+ });
+ }
+ };
+
+ /**
+ * @param {string=} sType = Enums.ComposeType.Empty
+ * @param {?MessageModel|Array=} oMessageOrArray = null
+ * @param {Array=} aToEmails = null
+ * @param {Array=} aCcEmails = null
+ * @param {Array=} aBccEmails = null
+ * @param {string=} sCustomSubject = null
+ * @param {string=} sCustomPlainText = null
+ */
+ ComposePopupView.prototype.onShow = function (sType, oMessageOrArray,
+ aToEmails, aCcEmails, aBccEmails, sCustomSubject, sCustomPlainText)
+ {
+ kn.routeOff();
+
+ this.autosaveStart();
+
+ if (AppStore.composeInEdit())
+ {
+ sType = sType || Enums.ComposeType.Empty;
+
+ var self = this;
+
+ if (Enums.ComposeType.Empty !== sType)
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/Ask */ 43), [Translator.i18n('COMPOSE/DISCARD_UNSAVED_DATA'), function () {
+ self.initOnShow(sType, oMessageOrArray, aToEmails, aCcEmails, aBccEmails, sCustomSubject, sCustomPlainText);
+ }, null, null, null, false]);
+ }
+ else
+ {
+ this.addEmailsTo(this.to, aToEmails);
+ this.addEmailsTo(this.cc, aCcEmails);
+ this.addEmailsTo(this.bcc, aBccEmails);
+
+ if (Utils.isNormal(sCustomSubject) && '' !== sCustomSubject &&
+ '' === this.subject())
+ {
+ this.subject(sCustomSubject);
+ }
+ }
+ }
+ else
+ {
+ this.initOnShow(sType, oMessageOrArray, aToEmails, aCcEmails, aBccEmails, sCustomSubject, sCustomPlainText);
+ }
+ };
+
+ /**
+ * @param {Function} fKoValue
+ * @param {Array} aEmails
+ */
+ ComposePopupView.prototype.addEmailsTo = function (fKoValue, aEmails)
+ {
+ var
+ sValue = Utils.trim(fKoValue()),
+ aValue = []
+ ;
+
+ if (Utils.isNonEmptyArray(aEmails))
+ {
+ aValue = _.uniq(_.compact(_.map(aEmails, function (oItem) {
+ return oItem ? oItem.toLine(false) : null;
+ })));
+
+ fKoValue(sValue + ('' === sValue ? '' : ', ') + Utils.trim(aValue.join(', ')));
+ }
+ };
+
+ /**
+ *
+ * @param {Array} aList
+ * @param {boolean} bFriendly
+ * @return {string}
+ */
+ ComposePopupView.prototype.emailArrayToStringLineHelper = function (aList, bFriendly)
+ {
+ var
+ iIndex = 0,
+ iLen = aList.length,
+ aResult = []
+ ;
+
+ for (; iIndex < iLen; iIndex++)
+ {
+ aResult.push(aList[iIndex].toLine(!!bFriendly));
+ }
+
+ return aResult.join(', ');
+ };
+
+ /**
+ * @param {string=} sType = Enums.ComposeType.Empty
+ * @param {?MessageModel|Array=} oMessageOrArray = null
+ * @param {Array=} aToEmails = null
+ * @param {Array=} aCcEmails = null
+ * @param {Array=} aBccEmails = null
+ * @param {string=} sCustomSubject = null
+ * @param {string=} sCustomPlainText = null
+ */
+ ComposePopupView.prototype.initOnShow = function (sType, oMessageOrArray,
+ aToEmails, aCcEmails, aBccEmails, sCustomSubject, sCustomPlainText)
+ {
+ AppStore.composeInEdit(true);
+
+ var
+ self = this,
+ sFrom = '',
+ sTo = '',
+ sCc = '',
+ sDate = '',
+ sSubject = '',
+ oText = null,
+ sText = '',
+ sReplyTitle = '',
+ aResplyAllParts = [],
+ oExcludeEmail = {},
+ oIdentity = null,
+ mEmail = AccountStore.email(),
+ aDownloads = [],
+ aDraftInfo = null,
+ oMessage = null,
+ sComposeType = sType || Enums.ComposeType.Empty
+ ;
+
+ oMessageOrArray = oMessageOrArray || null;
+ if (oMessageOrArray && Utils.isNormal(oMessageOrArray))
+ {
+ oMessage = Utils.isArray(oMessageOrArray) && 1 === oMessageOrArray.length ? oMessageOrArray[0] :
+ (!Utils.isArray(oMessageOrArray) ? oMessageOrArray : null);
+ }
+
+ this.oLastMessage = oMessage;
+
+ if (null !== mEmail)
+ {
+ oExcludeEmail[mEmail] = true;
+ }
+
+ this.reset();
+
+ oIdentity = this.findIdentityByMessage(sComposeType, oMessage);
+ if (oIdentity)
+ {
+ oExcludeEmail[oIdentity.email()] = true;
+ }
+
+ if (Utils.isNonEmptyArray(aToEmails))
+ {
+ this.to(this.emailArrayToStringLineHelper(aToEmails));
+ }
+
+ if (Utils.isNonEmptyArray(aCcEmails))
+ {
+ this.cc(this.emailArrayToStringLineHelper(aCcEmails));
+ }
+
+ if (Utils.isNonEmptyArray(aBccEmails))
+ {
+ this.bcc(this.emailArrayToStringLineHelper(aBccEmails));
+ }
+
+ if ('' !== sComposeType && oMessage)
+ {
+ sDate = Momentor.format(oMessage.dateTimeStampInUTC(), 'FULL');
+ sSubject = oMessage.subject();
+ aDraftInfo = oMessage.aDraftInfo;
+
+ oText = $(oMessage.body).clone();
+ if (oText)
+ {
+ oText.find('blockquote.rl-bq-switcher').removeClass('rl-bq-switcher hidden-bq');
+ oText.find('.rlBlockquoteSwitcher').off('.rlBlockquoteSwitcher').remove();
+ oText.find('[data-html-editor-font-wrapper]').removeAttr('data-html-editor-font-wrapper');
+
+ // (function () {
+ //
+ // var oTmp = null, iLimit = 0;
+ //
+ // while (true)
+ // {
+ // iLimit++;
+ //
+ // oTmp = oText.children();
+ // if (10 > iLimit && oTmp.is('div') && 1 === oTmp.length)
+ // {
+ // oTmp.children().unwrap();
+ // continue;
+ // }
+ //
+ // break;
+ // }
+ //
+ // }());
+
+ sText = oText.html();
+ }
+
+ switch (sComposeType)
+ {
+ case Enums.ComposeType.Empty:
+ break;
+
+ case Enums.ComposeType.Reply:
+ this.to(this.emailArrayToStringLineHelper(oMessage.replyEmails(oExcludeEmail)));
+ this.subject(Utils.replySubjectAdd('Re', sSubject));
+ this.prepearMessageAttachments(oMessage, sComposeType);
+ this.aDraftInfo = ['reply', oMessage.uid, oMessage.folderFullNameRaw];
+ this.sInReplyTo = oMessage.sMessageId;
+ this.sReferences = Utils.trim(this.sInReplyTo + ' ' + oMessage.sReferences);
+ break;
+
+ case Enums.ComposeType.ReplyAll:
+ aResplyAllParts = oMessage.replyAllEmails(oExcludeEmail);
+ this.to(this.emailArrayToStringLineHelper(aResplyAllParts[0]));
+ this.cc(this.emailArrayToStringLineHelper(aResplyAllParts[1]));
+ this.subject(Utils.replySubjectAdd('Re', sSubject));
+ this.prepearMessageAttachments(oMessage, sComposeType);
+ this.aDraftInfo = ['reply', oMessage.uid, oMessage.folderFullNameRaw];
+ this.sInReplyTo = oMessage.sMessageId;
+ this.sReferences = Utils.trim(this.sInReplyTo + ' ' + oMessage.references());
+ break;
+
+ case Enums.ComposeType.Forward:
+ this.subject(Utils.replySubjectAdd('Fwd', sSubject));
+ this.prepearMessageAttachments(oMessage, sComposeType);
+ this.aDraftInfo = ['forward', oMessage.uid, oMessage.folderFullNameRaw];
+ this.sInReplyTo = oMessage.sMessageId;
+ this.sReferences = Utils.trim(this.sInReplyTo + ' ' + oMessage.sReferences);
+ break;
+
+ case Enums.ComposeType.ForwardAsAttachment:
+ this.subject(Utils.replySubjectAdd('Fwd', sSubject));
+ this.prepearMessageAttachments(oMessage, sComposeType);
+ this.aDraftInfo = ['forward', oMessage.uid, oMessage.folderFullNameRaw];
+ this.sInReplyTo = oMessage.sMessageId;
+ this.sReferences = Utils.trim(this.sInReplyTo + ' ' + oMessage.sReferences);
+ break;
+
+ case Enums.ComposeType.Draft:
+ this.to(this.emailArrayToStringLineHelper(oMessage.to));
+ this.cc(this.emailArrayToStringLineHelper(oMessage.cc));
+ this.bcc(this.emailArrayToStringLineHelper(oMessage.bcc));
+ this.replyTo(this.emailArrayToStringLineHelper(oMessage.replyTo));
+
+ this.bFromDraft = true;
+
+ this.draftFolder(oMessage.folderFullNameRaw);
+ this.draftUid(oMessage.uid);
+
+ this.subject(sSubject);
+ this.prepearMessageAttachments(oMessage, sComposeType);
+
+ this.aDraftInfo = Utils.isNonEmptyArray(aDraftInfo) && 3 === aDraftInfo.length ? aDraftInfo : null;
+ this.sInReplyTo = oMessage.sInReplyTo;
+ this.sReferences = oMessage.sReferences;
+ break;
+
+ case Enums.ComposeType.EditAsNew:
+ this.to(this.emailArrayToStringLineHelper(oMessage.to));
+ this.cc(this.emailArrayToStringLineHelper(oMessage.cc));
+ this.bcc(this.emailArrayToStringLineHelper(oMessage.bcc));
+ this.replyTo(this.emailArrayToStringLineHelper(oMessage.replyTo));
+
+ this.subject(sSubject);
+ this.prepearMessageAttachments(oMessage, sComposeType);
+
+ this.aDraftInfo = Utils.isNonEmptyArray(aDraftInfo) && 3 === aDraftInfo.length ? aDraftInfo : null;
+ this.sInReplyTo = oMessage.sInReplyTo;
+ this.sReferences = oMessage.sReferences;
+ break;
+ }
+
+ switch (sComposeType)
+ {
+ case Enums.ComposeType.Reply:
+ case Enums.ComposeType.ReplyAll:
+ sFrom = oMessage.fromToLine(false, true);
+ sReplyTitle = Translator.i18n('COMPOSE/REPLY_MESSAGE_TITLE', {
+ 'DATETIME': sDate,
+ 'EMAIL': sFrom
+ });
+
+ sText = '
' + sReplyTitle + ':' +
+ '
' + Utils.trim(sText) + ' ';
+ // '
' + Utils.trim(sText) + '
';
+
+ break;
+
+ case Enums.ComposeType.Forward:
+ sFrom = oMessage.fromToLine(false, true);
+ sTo = oMessage.toToLine(false, true);
+ sCc = oMessage.ccToLine(false, true);
+ sText = '
' + Translator.i18n('COMPOSE/FORWARD_MESSAGE_TOP_TITLE') +
+ '
' + Translator.i18n('COMPOSE/FORWARD_MESSAGE_TOP_FROM') + ': ' + sFrom +
+ '
' + Translator.i18n('COMPOSE/FORWARD_MESSAGE_TOP_TO') + ': ' + sTo +
+ (0 < sCc.length ? '
' + Translator.i18n('COMPOSE/FORWARD_MESSAGE_TOP_CC') + ': ' + sCc : '') +
+ '
' + Translator.i18n('COMPOSE/FORWARD_MESSAGE_TOP_SENT') + ': ' + Utils.encodeHtml(sDate) +
+ '
' + Translator.i18n('COMPOSE/FORWARD_MESSAGE_TOP_SUBJECT') + ': ' + Utils.encodeHtml(sSubject) +
+ '
' + Utils.trim(sText) + '
';
+ break;
+
+ case Enums.ComposeType.ForwardAsAttachment:
+ sText = '';
+ break;
+ }
+
+ this.editor(function (oEditor) {
+
+ oEditor.setHtml(sText, false);
+
+ if (Enums.EditorDefaultType.PlainForced === self.editorDefaultType() ||
+ (!oMessage.isHtml() && Enums.EditorDefaultType.HtmlForced !== self.editorDefaultType()))
+ {
+ oEditor.modeToggle(false);
+ }
+
+ if (oIdentity && Enums.ComposeType.Draft !== sComposeType && Enums.ComposeType.EditAsNew !== sComposeType)
+ {
+ self.setSignatureFromIdentity(oIdentity);
+ }
+
+ self.setFocusInPopup();
+ });
+ }
+ else if (Enums.ComposeType.Empty === sComposeType)
+ {
+ this.subject(Utils.isNormal(sCustomSubject) ? '' + sCustomSubject : '');
+
+ sText = Utils.isNormal(sCustomPlainText) ? '' + sCustomPlainText : '';
+
+ this.editor(function (oEditor) {
+
+ oEditor.setHtml(sText, false);
+
+ if (Enums.EditorDefaultType.Html !== self.editorDefaultType() &&
+ Enums.EditorDefaultType.HtmlForced !== self.editorDefaultType())
+ {
+ oEditor.modeToggle(false);
+ }
+
+ if (oIdentity)
+ {
+ self.setSignatureFromIdentity(oIdentity);
+ }
+
+ self.setFocusInPopup();
+ });
+ }
+ else if (Utils.isNonEmptyArray(oMessageOrArray))
+ {
+ _.each(oMessageOrArray, function (oMessage) {
+ self.addMessageAsAttachment(oMessage);
+ });
+
+ this.editor(function (oEditor) {
+
+ oEditor.setHtml('', false);
+
+ if (Enums.EditorDefaultType.Html !== self.editorDefaultType() &&
+ Enums.EditorDefaultType.HtmlForced !== self.editorDefaultType())
+ {
+ oEditor.modeToggle(false);
+ }
+
+ if (oIdentity && Enums.ComposeType.Draft !== sComposeType && Enums.ComposeType.EditAsNew !== sComposeType)
+ {
+ self.setSignatureFromIdentity(oIdentity);
+ }
+
+ self.setFocusInPopup();
+ });
+ }
+ else
+ {
+ this.setFocusInPopup();
+ }
+
+ aDownloads = this.getAttachmentsDownloadsForUpload();
+ if (Utils.isNonEmptyArray(aDownloads))
+ {
+ Remote.messageUploadAttachments(this.onMessageUploadAttachments, aDownloads);
+ }
+
+ if (oIdentity)
+ {
+ this.currentIdentity(oIdentity);
+ }
+
+ this.resizerTrigger();
+ };
+
+ ComposePopupView.prototype.onMessageUploadAttachments = function (sResult, oData)
+ {
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ var
+ oAttachment = null,
+ sTempName = ''
+ ;
+
+ if (!this.viewModelVisibility())
+ {
+ for (sTempName in oData.Result)
+ {
+ if (oData.Result.hasOwnProperty(sTempName))
+ {
+ oAttachment = this.getAttachmentById(oData.Result[sTempName]);
+ if (oAttachment)
+ {
+ oAttachment.tempName(sTempName);
+ oAttachment.waiting(false).uploading(false).complete(true);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ this.setMessageAttachmentFailedDownloadText();
+ }
+ };
+
+ ComposePopupView.prototype.setFocusInPopup = function ()
+ {
+ if (!Globals.bMobileDevice)
+ {
+ var self = this;
+ _.delay(function () {
+
+ if ('' === self.to())
+ {
+ self.to.focused(true);
+ }
+ else if (self.oEditor)
+ {
+ if (!self.to.focused())
+ {
+ self.oEditor.focus();
+ }
+ }
+
+ }, 100);
+ }
+ };
+
+ ComposePopupView.prototype.onShowWithDelay = function ()
+ {
+ this.resizerTrigger();
+ };
+
+ ComposePopupView.prototype.tryToClosePopup = function ()
+ {
+ var
+ self = this,
+ PopupsAskViewModel = __webpack_require__(/*! View/Popup/Ask */ 43)
+ ;
+
+ if (!kn.isPopupVisible(PopupsAskViewModel) && this.modalVisibility())
+ {
+ if (this.bSkipNextHide || (this.isEmptyForm() && !this.draftUid()))
+ {
+ Utils.delegateRun(self, 'closeCommand');
+ }
+ else
+ {
+ kn.showScreenPopup(PopupsAskViewModel, [Translator.i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'), function () {
+ if (self.modalVisibility())
+ {
+ Utils.delegateRun(self, 'closeCommand');
+ }
+ }]);
+ }
+ }
+ };
+
+ ComposePopupView.prototype.onBuild = function ()
+ {
+ this.initUploader();
+
+ var
+ self = this,
+ oScript = null
+ ;
+
+ key('ctrl+q, command+q, ctrl+w, command+w', Enums.KeyState.Compose, function () {
+ return false;
+ });
+
+ key('`', Enums.KeyState.Compose, function () {
+ if (self.oEditor && !self.oEditor.hasFocus() && !Utils.inFocus())
+ {
+ self.identitiesDropdownTrigger(true);
+ return false;
+ }
+ });
+
+ key('ctrl+`', Enums.KeyState.Compose, function () {
+ self.identitiesDropdownTrigger(true);
+ return false;
+ });
+
+ key('esc, ctrl+down, command+down', Enums.KeyState.Compose, function () {
+ self.skipCommand();
+ return false;
+ });
+
+ if (this.allowFolders)
+ {
+ key('ctrl+s, command+s', Enums.KeyState.Compose, function () {
+ self.saveCommand();
+ return false;
+ });
+ }
+
+ if (!!Settings.appSettingsGet('allowCtrlEnterOnCompose'))
+ {
+ key('ctrl+enter, command+enter', Enums.KeyState.Compose, function () {
+ self.sendCommand();
+ return false;
+ });
+ }
+
+ key('shift+esc', Enums.KeyState.Compose, function () {
+ if (self.modalVisibility())
+ {
+ self.tryToClosePopup();
+ }
+ return false;
+ });
+
+ Events.sub('window.resize.real', this.resizerTrigger);
+ Events.sub('window.resize.real', _.debounce(this.resizerTrigger, 50));
+
+ if (this.dropboxEnabled() && this.dropboxApiKey() && !window.Dropbox)
+ {
+ oScript = window.document.createElement('script');
+ oScript.type = 'text/javascript';
+ oScript.src = 'https://www.dropbox.com/static/api/2/dropins.js';
+ $(oScript).attr('id', 'dropboxjs').attr('data-app-key', self.dropboxApiKey());
+
+ window.document.body.appendChild(oScript);
+ }
+
+ if (this.driveEnabled())
+ {
+ $.getScript('https://apis.google.com/js/api.js', function () {
+ if (window.gapi)
+ {
+ self.driveVisible(true);
+ }
+ });
+ }
+
+ window.setInterval(function () {
+ if (self.modalVisibility() && self.oEditor)
+ {
+ self.oEditor.resize();
+ }
+ }, 5000);
+ };
+
+ ComposePopupView.prototype.driveCallback = function (sAccessToken, oData)
+ {
+ if (oData && window.XMLHttpRequest && window.google &&
+ oData[window.google.picker.Response.ACTION] === window.google.picker.Action.PICKED &&
+ oData[window.google.picker.Response.DOCUMENTS] && oData[window.google.picker.Response.DOCUMENTS][0] &&
+ oData[window.google.picker.Response.DOCUMENTS][0]['id'])
+ {
+ var
+ self = this,
+ oRequest = new window.XMLHttpRequest()
+ ;
+
+ oRequest.open('GET', 'https://www.googleapis.com/drive/v2/files/' + oData[window.google.picker.Response.DOCUMENTS][0]['id']);
+ oRequest.setRequestHeader('Authorization', 'Bearer ' + sAccessToken);
+ oRequest.addEventListener('load', function() {
+ if (oRequest && oRequest.responseText)
+ {
+ var oItem = JSON.parse(oRequest.responseText), fExport = function (oItem, sMimeType, sExt) {
+ if (oItem && oItem['exportLinks'])
+ {
+ if (oItem['exportLinks'][sMimeType])
+ {
+ oItem['downloadUrl'] = oItem['exportLinks'][sMimeType];
+ oItem['title'] = oItem['title'] + '.' + sExt;
+ oItem['mimeType'] = sMimeType;
+ }
+ else if (oItem['exportLinks']['application/pdf'])
+ {
+ oItem['downloadUrl'] = oItem['exportLinks']['application/pdf'];
+ oItem['title'] = oItem['title'] + '.pdf';
+ oItem['mimeType'] = 'application/pdf';
+ }
+ }
+ };
+
+ if (oItem && !oItem['downloadUrl'] && oItem['mimeType'] && oItem['exportLinks'])
+ {
+ switch (oItem['mimeType'].toString().toLowerCase())
+ {
+ case 'application/vnd.google-apps.document':
+ fExport(oItem, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'docx');
+ break;
+ case 'application/vnd.google-apps.spreadsheet':
+ fExport(oItem, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xlsx');
+ break;
+ case 'application/vnd.google-apps.drawing':
+ fExport(oItem, 'image/png', 'png');
+ break;
+ case 'application/vnd.google-apps.presentation':
+ fExport(oItem, 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'pptx');
+ break;
+ default:
+ fExport(oItem, 'application/pdf', 'pdf');
+ break;
+ }
+ }
+
+ if (oItem && oItem['downloadUrl'])
+ {
+ self.addDriveAttachment(oItem, sAccessToken);
+ }
+ }
+ });
+
+ oRequest.send();
+ }
+ };
+
+ ComposePopupView.prototype.driveCreatePiker = function (oOauthToken)
+ {
+ if (window.gapi && oOauthToken && oOauthToken.access_token)
+ {
+ var self = this;
+
+ window.gapi.load('picker', {'callback': function () {
+
+ if (window.google && window.google.picker)
+ {
+ var drivePicker = new window.google.picker.PickerBuilder()
+ // .addView(window.google.picker.ViewId.FOLDERS)
+ .addView(window.google.picker.ViewId.DOCS)
+ .setAppId(Settings.settingsGet('GoogleClientID'))
+ .setOAuthToken(oOauthToken.access_token)
+ .setCallback(_.bind(self.driveCallback, self, oOauthToken.access_token))
+ .enableFeature(window.google.picker.Feature.NAV_HIDDEN)
+ // .setOrigin(window.location.protocol + '//' + window.location.host)
+ .build()
+ ;
+
+ drivePicker.setVisible(true);
+ }
+ }});
+ }
+ };
+
+ ComposePopupView.prototype.driveOpenPopup = function ()
+ {
+ if (window.gapi)
+ {
+ var self = this;
+
+ window.gapi.load('auth', {'callback': function () {
+
+ var
+ oAuthToken = window.gapi.auth.getToken(),
+ fResult = function (oAuthResult) {
+ if (oAuthResult && !oAuthResult.error)
+ {
+ var oAuthToken = window.gapi.auth.getToken();
+ if (oAuthToken)
+ {
+ self.driveCreatePiker(oAuthToken);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+ ;
+
+ if (!oAuthToken)
+ {
+ window.gapi.auth.authorize({
+ 'client_id': Settings.settingsGet('GoogleClientID'),
+ 'scope': 'https://www.googleapis.com/auth/drive.readonly',
+ 'immediate': true
+ }, function (oAuthResult) {
+
+ if (!fResult(oAuthResult))
+ {
+ window.gapi.auth.authorize({
+ 'client_id': Settings.settingsGet('GoogleClientID'),
+ 'scope': 'https://www.googleapis.com/auth/drive.readonly',
+ 'immediate': false
+ }, fResult);
+ }
+ });
+ }
+ else
+ {
+ self.driveCreatePiker(oAuthToken);
+ }
+ }});
+ }
+ };
+
+ /**
+ * @param {string} sId
+ * @return {?Object}
+ */
+ ComposePopupView.prototype.getAttachmentById = function (sId)
+ {
+ var
+ aAttachments = this.attachments(),
+ iIndex = 0,
+ iLen = aAttachments.length
+ ;
+
+ for (; iIndex < iLen; iIndex++)
+ {
+ if (aAttachments[iIndex] && sId === aAttachments[iIndex].id)
+ {
+ return aAttachments[iIndex];
+ }
+ }
+
+ return null;
+ };
+
+ ComposePopupView.prototype.cancelAttachmentHelper = function (sId, oJua) {
+
+ var self = this;
+ return function () {
+
+ var oItem = _.find(self.attachments(), function (oItem) {
+ return oItem && oItem.id === sId;
+ });
+
+ if (oItem)
+ {
+ self.attachments.remove(oItem);
+ Utils.delegateRunOnDestroy(oItem);
+
+ if (oJua)
+ {
+ oJua.cancel(sId);
+ }
+ }
+ };
+
+ };
+
+ ComposePopupView.prototype.initUploader = function ()
+ {
+ if (this.composeUploaderButton())
+ {
+ var
+ oUploadCache = {},
+ iAttachmentSizeLimit = Utils.pInt(Settings.settingsGet('AttachmentLimit')),
+ oJua = new Jua({
+ 'action': Links.upload(),
+ 'name': 'uploader',
+ 'queueSize': 2,
+ 'multipleSizeLimit': 50,
+ 'clickElement': this.composeUploaderButton(),
+ 'dragAndDropElement': this.composeUploaderDropPlace()
+ })
+ ;
+
+ if (oJua)
+ {
+ oJua
+ // .on('onLimitReached', function (iLimit) {
+ // alert(iLimit);
+ // })
+ .on('onDragEnter', _.bind(function () {
+ this.dragAndDropOver(true);
+ }, this))
+ .on('onDragLeave', _.bind(function () {
+ this.dragAndDropOver(false);
+ }, this))
+ .on('onBodyDragEnter', _.bind(function () {
+ this.attachmentsPlace(true);
+ this.dragAndDropVisible(true);
+ }, this))
+ .on('onBodyDragLeave', _.bind(function () {
+ this.dragAndDropVisible(false);
+ }, this))
+ .on('onProgress', _.bind(function (sId, iLoaded, iTotal) {
+ var oItem = null;
+ if (Utils.isUnd(oUploadCache[sId]))
+ {
+ oItem = this.getAttachmentById(sId);
+ if (oItem)
+ {
+ oUploadCache[sId] = oItem;
+ }
+ }
+ else
+ {
+ oItem = oUploadCache[sId];
+ }
+
+ if (oItem)
+ {
+ oItem.progress(window.Math.floor(iLoaded / iTotal * 100));
+ }
+
+ }, this))
+ .on('onSelect', _.bind(function (sId, oData) {
+
+ this.dragAndDropOver(false);
+
+ var
+ that = this,
+ sFileName = Utils.isUnd(oData.FileName) ? '' : oData.FileName.toString(),
+ mSize = Utils.isNormal(oData.Size) ? Utils.pInt(oData.Size) : null,
+ oAttachment = new ComposeAttachmentModel(sId, sFileName, mSize)
+ ;
+
+ oAttachment.cancel = that.cancelAttachmentHelper(sId, oJua);
+
+ this.attachments.push(oAttachment);
+
+ this.attachmentsPlace(true);
+
+ if (0 < mSize && 0 < iAttachmentSizeLimit && iAttachmentSizeLimit < mSize)
+ {
+ oAttachment
+ .waiting(false).uploading(true).complete(true)
+ .error(Translator.i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG'));
+
+ return false;
+ }
+
+ return true;
+
+ }, this))
+ .on('onStart', _.bind(function (sId) {
+
+ var
+ oItem = null
+ ;
+
+ if (Utils.isUnd(oUploadCache[sId]))
+ {
+ oItem = this.getAttachmentById(sId);
+ if (oItem)
+ {
+ oUploadCache[sId] = oItem;
+ }
+ }
+ else
+ {
+ oItem = oUploadCache[sId];
+ }
+
+ if (oItem)
+ {
+ oItem.waiting(false).uploading(true).complete(false);
+ }
+
+ }, this))
+ .on('onComplete', _.bind(function (sId, bResult, oData) {
+
+ var
+ sError = '',
+ mErrorCode = null,
+ oAttachmentJson = null,
+ oAttachment = this.getAttachmentById(sId)
+ ;
+
+ oAttachmentJson = bResult && oData && oData.Result && oData.Result.Attachment ? oData.Result.Attachment : null;
+ mErrorCode = oData && oData.Result && oData.Result.ErrorCode ? oData.Result.ErrorCode : null;
+
+ if (null !== mErrorCode)
+ {
+ sError = Translator.getUploadErrorDescByCode(mErrorCode);
+ }
+ else if (!oAttachmentJson)
+ {
+ sError = Translator.i18n('UPLOAD/ERROR_UNKNOWN');
+ }
+
+ if (oAttachment)
+ {
+ if ('' !== sError && 0 < sError.length)
+ {
+ oAttachment
+ .waiting(false)
+ .uploading(false)
+ .complete(true)
+ .error(sError)
+ ;
+ }
+ else if (oAttachmentJson)
+ {
+ oAttachment
+ .waiting(false)
+ .uploading(false)
+ .complete(true)
+ ;
+
+ oAttachment.initByUploadJson(oAttachmentJson);
+ }
+
+ if (Utils.isUnd(oUploadCache[sId]))
+ {
+ delete (oUploadCache[sId]);
+ }
+ }
+
+ }, this))
+ ;
+
+ this
+ .addAttachmentEnabled(true)
+ .dragAndDropEnabled(oJua.isDragAndDropSupported())
+ ;
+ }
+ else
+ {
+ this
+ .addAttachmentEnabled(false)
+ .dragAndDropEnabled(false)
+ ;
+ }
+ }
+ };
+
+ /**
+ * @return {Object}
+ */
+ ComposePopupView.prototype.prepearAttachmentsForSendOrSave = function ()
+ {
+ var oResult = {};
+ _.each(this.attachmentsInReady(), function (oItem) {
+ if (oItem && '' !== oItem.tempName() && oItem.enabled())
+ {
+ oResult[oItem.tempName()] = [
+ oItem.fileName(),
+ oItem.isInline ? '1' : '0',
+ oItem.CID,
+ oItem.contentLocation
+ ];
+ }
+ });
+
+ return oResult;
+ };
+
+ /**
+ * @param {MessageModel} oMessage
+ */
+ ComposePopupView.prototype.addMessageAsAttachment = function (oMessage)
+ {
+ if (oMessage)
+ {
+ var
+ oAttachment = null,
+ sTemp = oMessage.subject()
+ ;
+
+ sTemp = '.eml' === sTemp.substr(-4).toLowerCase() ? sTemp : sTemp + '.eml';
+ oAttachment = new ComposeAttachmentModel(
+ oMessage.requestHash, sTemp, oMessage.size()
+ );
+
+ oAttachment.fromMessage = true;
+ oAttachment.cancel = this.cancelAttachmentHelper(oMessage.requestHash);
+ oAttachment.waiting(false).uploading(true).complete(true);
+
+ this.attachments.push(oAttachment);
+ }
+ };
+
+ /**
+ * @param {Object} oDropboxFile
+ * @return {boolean}
+ */
+ ComposePopupView.prototype.addDropboxAttachment = function (oDropboxFile)
+ {
+ var
+ oAttachment = null,
+ iAttachmentSizeLimit = Utils.pInt(Settings.settingsGet('AttachmentLimit')),
+ mSize = oDropboxFile['bytes']
+ ;
+
+ oAttachment = new ComposeAttachmentModel(
+ oDropboxFile['link'], oDropboxFile['name'], mSize
+ );
+
+ oAttachment.fromMessage = false;
+ oAttachment.cancel = this.cancelAttachmentHelper(oDropboxFile['link']);
+ oAttachment.waiting(false).uploading(true).complete(false);
+
+ this.attachments.push(oAttachment);
+
+ this.attachmentsPlace(true);
+
+ if (0 < mSize && 0 < iAttachmentSizeLimit && iAttachmentSizeLimit < mSize)
+ {
+ oAttachment.uploading(false).complete(true);
+ oAttachment.error(Translator.i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG'));
+ return false;
+ }
+
+ Remote.composeUploadExternals(function (sResult, oData) {
+
+ var bResult = false;
+ oAttachment.uploading(false).complete(true);
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ if (oData.Result[oAttachment.id])
+ {
+ bResult = true;
+ oAttachment.tempName(oData.Result[oAttachment.id]);
+ }
+ }
+
+ if (!bResult)
+ {
+ oAttachment.error(Translator.getUploadErrorDescByCode(Enums.UploadErrorCode.FileNoUploaded));
+ }
+
+ }, [oDropboxFile['link']]);
+
+ return true;
+ };
+
+ /**
+ * @param {Object} oDriveFile
+ * @param {string} sAccessToken
+ * @return {boolean}
+ */
+ ComposePopupView.prototype.addDriveAttachment = function (oDriveFile, sAccessToken)
+ {
+ var
+ iAttachmentSizeLimit = Utils.pInt(Settings.settingsGet('AttachmentLimit')),
+ oAttachment = null,
+ mSize = oDriveFile['fileSize'] ? Utils.pInt(oDriveFile['fileSize']) : 0
+ ;
+
+ oAttachment = new ComposeAttachmentModel(
+ oDriveFile['downloadUrl'], oDriveFile['title'], mSize
+ );
+
+ oAttachment.fromMessage = false;
+ oAttachment.cancel = this.cancelAttachmentHelper(oDriveFile['downloadUrl']);
+ oAttachment.waiting(false).uploading(true).complete(false);
+
+ this.attachments.push(oAttachment);
+
+ this.attachmentsPlace(true);
+
+ if (0 < mSize && 0 < iAttachmentSizeLimit && iAttachmentSizeLimit < mSize)
+ {
+ oAttachment.uploading(false).complete(true);
+ oAttachment.error(Translator.i18n('UPLOAD/ERROR_FILE_IS_TOO_BIG'));
+ return false;
+ }
+
+ Remote.composeUploadDrive(function (sResult, oData) {
+
+ var bResult = false;
+ oAttachment.uploading(false).complete(true);
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ if (oData.Result[oAttachment.id])
+ {
+ bResult = true;
+ oAttachment.tempName(oData.Result[oAttachment.id][0]);
+ oAttachment.size(Utils.pInt(oData.Result[oAttachment.id][1]));
+ }
+ }
+
+ if (!bResult)
+ {
+ oAttachment.error(Translator.getUploadErrorDescByCode(Enums.UploadErrorCode.FileNoUploaded));
+ }
+
+ }, oDriveFile['downloadUrl'], sAccessToken);
+
+ return true;
+ };
+
+ /**
+ * @param {MessageModel} oMessage
+ * @param {string} sType
+ */
+ ComposePopupView.prototype.prepearMessageAttachments = function (oMessage, sType)
+ {
+ if (oMessage)
+ {
+ var
+ aAttachments = Utils.isNonEmptyArray(oMessage.attachments()) ? oMessage.attachments() : [],
+ iIndex = 0,
+ iLen = aAttachments.length,
+ oAttachment = null,
+ oItem = null,
+ bAdd = false
+ ;
+
+ if (Enums.ComposeType.ForwardAsAttachment === sType)
+ {
+ this.addMessageAsAttachment(oMessage);
+ }
+ else
+ {
+ for (; iIndex < iLen; iIndex++)
+ {
+ oItem = aAttachments[iIndex];
+
+ bAdd = false;
+ switch (sType) {
+ case Enums.ComposeType.Reply:
+ case Enums.ComposeType.ReplyAll:
+ bAdd = oItem.isLinked;
+ break;
+
+ case Enums.ComposeType.Forward:
+ case Enums.ComposeType.Draft:
+ case Enums.ComposeType.EditAsNew:
+ bAdd = true;
+ break;
+ }
+
+ if (bAdd)
+ {
+ oAttachment = new ComposeAttachmentModel(
+ oItem.download, oItem.fileName, oItem.estimatedSize,
+ oItem.isInline, oItem.isLinked, oItem.cid, oItem.contentLocation
+ );
+
+ oAttachment.fromMessage = true;
+ oAttachment.cancel = this.cancelAttachmentHelper(oItem.download);
+ oAttachment.waiting(false).uploading(true).complete(false);
+
+ this.attachments.push(oAttachment);
+ }
+ }
+ }
+ }
+ };
+
+ ComposePopupView.prototype.removeLinkedAttachments = function ()
+ {
+ var oItem = _.find(this.attachments(), function (oItem) {
+ return oItem && oItem.isLinked;
+ });
+
+ if (oItem)
+ {
+ this.attachments.remove(oItem);
+ Utils.delegateRunOnDestroy(oItem);
+ }
+ };
+
+ ComposePopupView.prototype.setMessageAttachmentFailedDownloadText = function ()
+ {
+ _.each(this.attachments(), function(oAttachment) {
+ if (oAttachment && oAttachment.fromMessage)
+ {
+ oAttachment
+ .waiting(false)
+ .uploading(false)
+ .complete(true)
+ .error(Translator.getUploadErrorDescByCode(Enums.UploadErrorCode.FileNoUploaded))
+ ;
+ }
+ }, this);
+ };
+
+ /**
+ * @param {boolean=} bIncludeAttachmentInProgress = true
+ * @return {boolean}
+ */
+ ComposePopupView.prototype.isEmptyForm = function (bIncludeAttachmentInProgress)
+ {
+ bIncludeAttachmentInProgress = Utils.isUnd(bIncludeAttachmentInProgress) ? true : !!bIncludeAttachmentInProgress;
+ var bWithoutAttach = bIncludeAttachmentInProgress ?
+ 0 === this.attachments().length : 0 === this.attachmentsInReady().length;
+
+ return 0 === this.to().length &&
+ 0 === this.cc().length &&
+ 0 === this.bcc().length &&
+ 0 === this.replyTo().length &&
+ 0 === this.subject().length &&
+ bWithoutAttach &&
+ (!this.oEditor || '' === this.oEditor.getData())
+ ;
+ };
+
+ ComposePopupView.prototype.reset = function ()
+ {
+ this.to('');
+ this.cc('');
+ this.bcc('');
+ this.replyTo('');
+ this.subject('');
+
+ this.requestDsn(false);
+ this.requestReadReceipt(false);
+ this.markAsImportant(false);
+
+ this.attachmentsPlace(false);
+
+ this.aDraftInfo = null;
+ this.sInReplyTo = '';
+ this.bFromDraft = false;
+ this.sReferences = '';
+
+ this.sendError(false);
+ this.sendSuccessButSaveError(false);
+ this.savedError(false);
+ this.savedTime(0);
+ this.emptyToError(false);
+ this.attachmentsInProcessError(false);
+
+ this.showCc(false);
+ this.showBcc(false);
+ this.showReplyTo(false);
+
+ Utils.delegateRunOnDestroy(this.attachments());
+ this.attachments([]);
+
+ this.dragAndDropOver(false);
+ this.dragAndDropVisible(false);
+
+ this.draftFolder('');
+ this.draftUid('');
+
+ this.sending(false);
+ this.saving(false);
+
+ if (this.oEditor)
+ {
+ this.oEditor.clear(false);
+ }
+ };
+
+ /**
+ * @return {Array}
+ */
+ ComposePopupView.prototype.getAttachmentsDownloadsForUpload = function ()
+ {
+ return _.map(_.filter(this.attachments(), function (oItem) {
+ return oItem && '' === oItem.tempName();
+ }), function (oItem) {
+ return oItem.id;
+ });
+ };
+
+ ComposePopupView.prototype.resizerTrigger = function ()
+ {
+ this.resizer(!this.resizer());
+ };
+
+ module.exports = ComposePopupView;
+
+ }());
+
+
+/***/ },
+/* 30 */
+/*!****************************!*\
+ !*** ./dev/Model/Email.js ***!
+ \****************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ Utils = __webpack_require__(/*! Common/Utils */ 1)
+ ;
+
+ /**
+ * @param {string=} sEmail
+ * @param {string=} sName
+ * @param {string=} sDkimStatus
+ * @param {string=} sDkimValue
+ *
+ * @constructor
+ */
+ function EmailModel(sEmail, sName, sDkimStatus, sDkimValue)
+ {
+ this.email = sEmail || '';
+ this.name = sName || '';
+ this.dkimStatus = sDkimStatus || 'none';
+ this.dkimValue = sDkimValue || '';
+
+ this.clearDuplicateName();
+ }
+
+ /**
+ * @static
+ * @param {AjaxJsonEmail} oJsonEmail
+ * @return {?EmailModel}
+ */
+ EmailModel.newInstanceFromJson = function (oJsonEmail)
+ {
+ var oEmailModel = new EmailModel();
+ return oEmailModel.initByJson(oJsonEmail) ? oEmailModel : null;
+ };
+
+ /**
+ * @static
+ * @param {string} sLine
+ * @param {string=} sDelimiter = ';'
+ * @return {Array}
+ */
+ EmailModel.splitHelper = function (sLine, sDelimiter)
+ {
+ sDelimiter = sDelimiter || ';';
+
+ sLine = sLine.replace(/[\r\n]+/g, '; ').replace(/[\s]+/g, ' ');
+
+ var
+ iIndex = 0,
+ iLen = sLine.length,
+ bAt = false,
+ sChar = '',
+ sResult = ''
+ ;
+
+ for (; iIndex < iLen; iIndex++)
+ {
+ sChar = sLine.charAt(iIndex);
+ switch (sChar)
+ {
+ case '@':
+ bAt = true;
+ break;
+ case ' ':
+ if (bAt)
+ {
+ bAt = false;
+ sResult += sDelimiter;
+ }
+ break;
+ }
+
+ sResult += sChar;
+ }
+
+ return sResult.split(sDelimiter);
+ };
+
+ /**
+ * @type {string}
+ */
+ EmailModel.prototype.name = '';
+
+ /**
+ * @type {string}
+ */
+ EmailModel.prototype.email = '';
+
+ /**
+ * @type {string}
+ */
+ EmailModel.prototype.dkimStatus = 'none';
+
+ /**
+ * @type {string}
+ */
+ EmailModel.prototype.dkimValue = '';
+
+ EmailModel.prototype.clear = function ()
+ {
+ this.email = '';
+ this.name = '';
+
+ this.dkimStatus = 'none';
+ this.dkimValue = '';
+ };
+
+ /**
+ * @return {boolean}
+ */
+ EmailModel.prototype.validate = function ()
+ {
+ return '' !== this.name || '' !== this.email;
+ };
+
+ /**
+ * @param {boolean} bWithoutName = false
+ * @return {string}
+ */
+ EmailModel.prototype.hash = function (bWithoutName)
+ {
+ return '#' + (bWithoutName ? '' : this.name) + '#' + this.email + '#';
+ };
+
+ EmailModel.prototype.clearDuplicateName = function ()
+ {
+ if (this.name === this.email)
+ {
+ this.name = '';
+ }
+ };
+
+ /**
+ * @param {string} sQuery
+ * @return {boolean}
+ */
+ EmailModel.prototype.search = function (sQuery)
+ {
+ return -1 < (this.name + ' ' + this.email).toLowerCase().indexOf(sQuery.toLowerCase());
+ };
+
+ /**
+ * @param {string} sString
+ */
+ EmailModel.prototype.parse = function (sString)
+ {
+ this.clear();
+
+ sString = Utils.trim(sString);
+
+ var
+ mRegex = /(?:"([^"]+)")? ?[<]?(.*?@[^>,]+)>?,? ?/g,
+ mMatch = mRegex.exec(sString)
+ ;
+
+ if (mMatch)
+ {
+ this.name = mMatch[1] || '';
+ this.email = mMatch[2] || '';
+
+ this.clearDuplicateName();
+ }
+ else if ((/^[^@]+@[^@]+$/).test(sString))
+ {
+ this.name = '';
+ this.email = sString;
+ }
+ };
+
+ /**
+ * @param {AjaxJsonEmail} oJsonEmail
+ * @return {boolean}
+ */
+ EmailModel.prototype.initByJson = function (oJsonEmail)
+ {
+ var bResult = false;
+ if (oJsonEmail && 'Object/Email' === oJsonEmail['@Object'])
+ {
+ this.name = Utils.trim(oJsonEmail.Name);
+ this.email = Utils.trim(oJsonEmail.Email);
+ this.dkimStatus = Utils.trim(oJsonEmail.DkimStatus || '');
+ this.dkimValue = Utils.trim(oJsonEmail.DkimValue || '');
+
+ bResult = '' !== this.email;
+ this.clearDuplicateName();
+ }
+
+ return bResult;
+ };
+
+ /**
+ * @param {boolean} bFriendlyView
+ * @param {boolean=} bWrapWithLink = false
+ * @param {boolean=} bEncodeHtml = false
+ * @return {string}
+ */
+ EmailModel.prototype.toLine = function (bFriendlyView, bWrapWithLink, bEncodeHtml)
+ {
+ var sResult = '';
+ if ('' !== this.email)
+ {
+ bWrapWithLink = Utils.isUnd(bWrapWithLink) ? false : !!bWrapWithLink;
+ bEncodeHtml = Utils.isUnd(bEncodeHtml) ? false : !!bEncodeHtml;
+
+ if (bFriendlyView && '' !== this.name)
+ {
+ sResult = bWrapWithLink ? '
') +
+ '" target="_blank" tabindex="-1">' + Utils.encodeHtml(this.name) + ' ' :
+ (bEncodeHtml ? Utils.encodeHtml(this.name) : this.name);
+ }
+ else
+ {
+ sResult = this.email;
+ if ('' !== this.name)
+ {
+ if (bWrapWithLink)
+ {
+ sResult = Utils.encodeHtml('"' + this.name + '" <') +
+ '
') + '" target="_blank" tabindex="-1">' + Utils.encodeHtml(sResult) + ' ' + Utils.encodeHtml('>');
+ }
+ else
+ {
+ sResult = '"' + this.name + '" <' + sResult + '>';
+ if (bEncodeHtml)
+ {
+ sResult = Utils.encodeHtml(sResult);
+ }
+ }
+ }
+ else if (bWrapWithLink)
+ {
+ sResult = '
' + Utils.encodeHtml(this.email) + ' ';
+ }
+ }
+ }
+
+ return sResult;
+ };
+
+ /**
+ * @param {string} $sEmailAddress
+ * @return {boolean}
+ */
+ EmailModel.prototype.mailsoParse = function ($sEmailAddress)
+ {
+ $sEmailAddress = Utils.trim($sEmailAddress);
+ if ('' === $sEmailAddress)
+ {
+ return false;
+ }
+
+ var
+ substr = function (str, start, len) {
+ str += '';
+ var end = str.length;
+
+ if (start < 0) {
+ start += end;
+ }
+
+ end = typeof len === 'undefined' ? end : (len < 0 ? len + end : len + start);
+
+ return start >= str.length || start < 0 || start > end ? false : str.slice(start, end);
+ },
+
+ substr_replace = function (str, replace, start, length) {
+ if (start < 0) {
+ start = start + str.length;
+ }
+ length = length !== undefined ? length : str.length;
+ if (length < 0) {
+ length = length + str.length - start;
+ }
+ return str.slice(0, start) + replace.substr(0, length) + replace.slice(length) + str.slice(start + length);
+ },
+
+ $sName = '',
+ $sEmail = '',
+ $sComment = '',
+
+ $bInName = false,
+ $bInAddress = false,
+ $bInComment = false,
+
+ $aRegs = null,
+
+ $iStartIndex = 0,
+ $iEndIndex = 0,
+ $iCurrentIndex = 0
+ ;
+
+ while ($iCurrentIndex < $sEmailAddress.length)
+ {
+ switch ($sEmailAddress.substr($iCurrentIndex, 1))
+ {
+ case '"':
+ if ((!$bInName) && (!$bInAddress) && (!$bInComment))
+ {
+ $bInName = true;
+ $iStartIndex = $iCurrentIndex;
+ }
+ else if ((!$bInAddress) && (!$bInComment))
+ {
+ $iEndIndex = $iCurrentIndex;
+ $sName = substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
+ $sEmailAddress = substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+ $iStartIndex = 0;
+ $bInName = false;
+ }
+ break;
+ case '<':
+ if ((!$bInName) && (!$bInAddress) && (!$bInComment))
+ {
+ if ($iCurrentIndex > 0 && $sName.length === 0)
+ {
+ $sName = substr($sEmailAddress, 0, $iCurrentIndex);
+ }
+
+ $bInAddress = true;
+ $iStartIndex = $iCurrentIndex;
+ }
+ break;
+ case '>':
+ if ($bInAddress)
+ {
+ $iEndIndex = $iCurrentIndex;
+ $sEmail = substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
+ $sEmailAddress = substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+ $iStartIndex = 0;
+ $bInAddress = false;
+ }
+ break;
+ case '(':
+ if ((!$bInName) && (!$bInAddress) && (!$bInComment))
+ {
+ $bInComment = true;
+ $iStartIndex = $iCurrentIndex;
+ }
+ break;
+ case ')':
+ if ($bInComment)
+ {
+ $iEndIndex = $iCurrentIndex;
+ $sComment = substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
+ $sEmailAddress = substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
+ $iEndIndex = 0;
+ $iCurrentIndex = 0;
+ $iStartIndex = 0;
+ $bInComment = false;
+ }
+ break;
+ case '\\':
+ $iCurrentIndex++;
+ break;
+ }
+
+ $iCurrentIndex++;
+ }
+
+ if ($sEmail.length === 0)
+ {
+ $aRegs = $sEmailAddress.match(/[^@\s]+@\S+/i);
+ if ($aRegs && $aRegs[0])
+ {
+ $sEmail = $aRegs[0];
+ }
+ else
+ {
+ $sName = $sEmailAddress;
+ }
+ }
+
+ if ($sEmail.length > 0 && $sName.length === 0 && $sComment.length === 0)
+ {
+ $sName = $sEmailAddress.replace($sEmail, '');
+ }
+
+ $sEmail = Utils.trim($sEmail).replace(/^[<]+/, '').replace(/[>]+$/, '');
+ $sName = Utils.trim($sName).replace(/^["']+/, '').replace(/["']+$/, '');
+ $sComment = Utils.trim($sComment).replace(/^[(]+/, '').replace(/[)]+$/, '');
+
+ // Remove backslash
+ $sName = $sName.replace(/\\\\(.)/g, '$1');
+ $sComment = $sComment.replace(/\\\\(.)/g, '$1');
+
+ this.name = $sName;
+ this.email = $sEmail;
+
+ this.clearDuplicateName();
+ return true;
+ };
+
+ module.exports = EmailModel;
+
+ }());
+
+/***/ },
+/* 31 */
+/*!************************************!*\
+ !*** ./dev/Stores/User/Account.js ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function AccountUserStore()
+ {
+ this.email = ko.observable('');
+ this.parentEmail = ko.observable('');
+ // this.incLogin = ko.observable('');
+ // this.outLogin = ko.observable('');
+
+ this.signature = ko.observable('');
+
+ this.accounts = ko.observableArray([]);
+ this.accounts.loading = ko.observable(false).extend({'throttle': 100});
+
+ this.computers();
+ }
+
+ AccountUserStore.prototype.computers = function ()
+ {
+ this.accountsEmails = ko.computed(function () {
+ return _.compact(_.map(this.accounts(), function (oItem) {
+ return oItem ? oItem.email : null;
+ }));
+ }, this);
+
+ this.accountsUnreadCount = ko.computed(function () {
+
+ var iResult = 0;
+
+ // _.each(this.accounts(), function (oItem) {
+ // if (oItem)
+ // {
+ // iResult += oItem.count();
+ // }
+ // });
+
+ return iResult;
+
+ }, this);
+ };
+
+ AccountUserStore.prototype.populate = function ()
+ {
+ this.email(Settings.settingsGet('Email'));
+ this.parentEmail(Settings.settingsGet('ParentEmail'));
+ };
+
+ /**
+ * @return {boolean}
+ */
+ AccountUserStore.prototype.isRootAccount = function ()
+ {
+ return '' === this.parentEmail();
+ };
+
+ module.exports = new AccountUserStore();
+
+ }());
+
+
+/***/ },
+/* 32 */
+/*!************************************!*\
+ !*** ./dev/Stores/User/Message.js ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+ window = __webpack_require__(/*! window */ 11),
+ $ = __webpack_require__(/*! $ */ 14),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Cache = __webpack_require__(/*! Common/Cache */ 19),
+
+ AppStore = __webpack_require__(/*! Stores/User/App */ 24),
+ FolderStore = __webpack_require__(/*! Stores/User/Folder */ 21),
+ PgpStore = __webpack_require__(/*! Stores/User/Pgp */ 33),
+ SettingsStore = __webpack_require__(/*! Stores/User/Settings */ 28),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15),
+
+ MessageModel = __webpack_require__(/*! Model/Message */ 108),
+ MessageHelper = __webpack_require__(/*! Helper/Message */ 85)
+ ;
+
+ /**
+ * @constructor
+ */
+ function MessageUserStore()
+ {
+ this.staticMessage = new MessageModel();
+
+ this.messageList = ko.observableArray([]).extend({'rateLimit': 0});
+
+ this.messageListCount = ko.observable(0);
+ this.messageListSearch = ko.observable('');
+ this.messageListThreadUid = ko.observable('');
+ this.messageListPage = ko.observable(1);
+ this.messageListPageBeforeThread = ko.observable(1);
+ this.messageListError = ko.observable('');
+
+ this.messageListEndFolder = ko.observable('');
+ this.messageListEndSearch = ko.observable('');
+ this.messageListEndThreadUid = ko.observable('');
+ this.messageListEndPage = ko.observable(1);
+
+ this.messageListLoading = ko.observable(false);
+ this.messageListIsNotCompleted = ko.observable(false);
+ this.messageListCompleteLoadingThrottle = ko.observable(false).extend({'throttle': 200});
+ this.messageListCompleteLoadingThrottleForAnimation = ko.observable(false).extend({'specialThrottle': 700});
+
+ this.messageListDisableAutoSelect = ko.observable(false).extend({'falseTimeout': 500});
+
+ this.selectorMessageSelected = ko.observable(null);
+ this.selectorMessageFocused = ko.observable(null);
+
+ // message viewer
+ this.message = ko.observable(null);
+
+ this.message.viewTrigger = ko.observable(false);
+
+ this.messageError = ko.observable('');
+
+ this.messageCurrentLoading = ko.observable(false);
+
+ this.messageLoading = ko.computed(function () {
+ return this.messageCurrentLoading();
+ }, this);
+
+ this.messageLoadingThrottle = ko.observable(false).extend({'throttle': 50});
+
+ this.messageFullScreenMode = ko.observable(false);
+
+ this.messagesBodiesDom = ko.observable(null);
+ this.messageActiveDom = ko.observable(null);
+
+ this.computers();
+ this.subscribers();
+
+ this.onMessageResponse = _.bind(this.onMessageResponse, this);
+
+ this.purgeMessageBodyCacheThrottle = _.throttle(this.purgeMessageBodyCache, 1000 * 30);
+ }
+
+ MessageUserStore.prototype.computers = function ()
+ {
+ var self = this;
+
+ this.messageListEndHash = ko.computed(function () {
+ return this.messageListEndFolder() + '|' + this.messageListEndSearch() +
+ '|' + this.messageListEndThreadUid() +
+ '|' + this.messageListEndPage();
+ }, this);
+
+ this.messageListPageCount = ko.computed(function () {
+ var iPage = window.Math.ceil(this.messageListCount() /
+ SettingsStore.messagesPerPage());
+ return 0 >= iPage ? 1 : iPage;
+ }, this);
+
+ this.mainMessageListSearch = ko.computed({
+ 'read': this.messageListSearch,
+ 'write': function (sValue) {
+ kn.setHash(Links.mailBox(
+ FolderStore.currentFolderFullNameHash(), 1,
+ Utils.trim(sValue.toString()), self.messageListThreadUid()
+ ));
+ },
+ 'owner': this
+ });
+
+ this.messageListCompleteLoading = ko.computed(function () {
+ var
+ bOne = this.messageListLoading(),
+ bTwo = this.messageListIsNotCompleted()
+ ;
+ return bOne || bTwo;
+ }, this);
+
+ this.isMessageSelected = ko.computed(function () {
+ return null !== this.message();
+ }, this);
+
+ this.messageListChecked = ko.computed(function () {
+ return _.filter(this.messageList(), function (oItem) {
+ return oItem.checked();
+ });
+ }, this).extend({'rateLimit': 0});
+
+ this.hasCheckedMessages = ko.computed(function () {
+ return 0 < this.messageListChecked().length;
+ }, this).extend({'rateLimit': 0});
+
+ this.messageListCheckedOrSelected = ko.computed(function () {
+
+ var
+ aChecked = this.messageListChecked(),
+ oSelectedMessage = this.selectorMessageSelected()
+ ;
+
+ return _.union(aChecked, oSelectedMessage ? [oSelectedMessage] : []);
+
+ }, this);
+
+ this.messageListCheckedOrSelectedUidsWithSubMails = ko.computed(function () {
+ var aList = [];
+ _.each(this.messageListCheckedOrSelected(), function (oMessage) {
+ if (oMessage)
+ {
+ aList.push(oMessage.uid);
+ if (1 < oMessage.threadsLen())
+ {
+ aList = _.union(aList, oMessage.threads());
+ }
+ }
+ });
+ return aList;
+ }, this);
+ };
+
+ MessageUserStore.prototype.subscribers = function ()
+ {
+ this.messageListCompleteLoading.subscribe(function (bValue) {
+ bValue = !!bValue;
+ this.messageListCompleteLoadingThrottle(bValue);
+ this.messageListCompleteLoadingThrottleForAnimation(bValue);
+ }, this);
+
+ this.messageList.subscribe(_.debounce(function (aList) {
+ _.each(aList, function (oItem) {
+ if (oItem && oItem.newForAnimation())
+ {
+ oItem.newForAnimation(false);
+ }
+ });
+ }, 500));
+
+ this.message.subscribe(function (oMessage) {
+
+ if (oMessage)
+ {
+ if (Enums.Layout.NoPreview === SettingsStore.layout())
+ {
+ AppStore.focusedState(Enums.Focused.MessageView);
+ }
+ }
+ else
+ {
+ AppStore.focusedState(Enums.Focused.MessageList);
+
+ this.messageFullScreenMode(false);
+ this.hideMessageBodies();
+ }
+
+ }, this);
+
+ this.messageLoading.subscribe(function (bValue) {
+ this.messageLoadingThrottle(bValue);
+ }, this);
+
+ this.messagesBodiesDom.subscribe(function (oDom) {
+ if (oDom && !(oDom instanceof $))
+ {
+ this.messagesBodiesDom($(oDom));
+ }
+ }, this);
+
+ this.messageListEndFolder.subscribe(function (sFolder) {
+ var oMessage = this.message();
+ if (oMessage && sFolder && sFolder !== oMessage.folderFullNameRaw)
+ {
+ this.message(null);
+ }
+ }, this);
+ };
+
+ MessageUserStore.prototype.purgeMessageBodyCache = function()
+ {
+ var
+ iCount = 0,
+ oMessagesDom = null,
+ iEnd = Globals.iMessageBodyCacheCount - Consts.MESSAGE_BODY_CACHE_LIMIT
+ ;
+
+ if (0 < iEnd)
+ {
+ oMessagesDom = this.messagesBodiesDom();
+ if (oMessagesDom)
+ {
+ oMessagesDom.find('.rl-cache-class').each(function () {
+ var oItem = $(this);
+ if (iEnd > oItem.data('rl-cache-count'))
+ {
+ oItem.addClass('rl-cache-purge');
+ iCount++;
+ }
+ });
+
+ if (0 < iCount)
+ {
+ _.delay(function () {
+ oMessagesDom.find('.rl-cache-purge').remove();
+ }, 300);
+ }
+ }
+ }
+ };
+
+ MessageUserStore.prototype.initUidNextAndNewMessages = function (sFolder, sUidNext, aNewMessages)
+ {
+ if (Cache.getFolderInboxName() === sFolder && Utils.isNormal(sUidNext) && sUidNext !== '')
+ {
+ if (Utils.isArray(aNewMessages) && 0 < aNewMessages.length)
+ {
+ var
+ iIndex = 0,
+ iLen = aNewMessages.length,
+ NotificationStore = __webpack_require__(/*! Stores/User/Notification */ 60)
+ ;
+
+ _.each(aNewMessages, function (oItem) {
+ Cache.addNewMessageCache(sFolder, oItem.Uid);
+ });
+
+ NotificationStore.playSoundNotification();
+
+ if (3 < iLen)
+ {
+ NotificationStore.displayDesktopNotification(
+ Links.notificationMailIcon(),
+ __webpack_require__(/*! Stores/User/Account */ 31).email(),
+ Translator.i18n('MESSAGE_LIST/NEW_MESSAGE_NOTIFICATION', {
+ 'COUNT': iLen
+ }),
+ {'Folder': '', 'Uid': ''}
+ );
+ }
+ else
+ {
+ for (; iIndex < iLen; iIndex++)
+ {
+ NotificationStore.displayDesktopNotification(
+ Links.notificationMailIcon(),
+ MessageHelper.emailArrayToString(MessageHelper.emailArrayFromJson(aNewMessages[iIndex].From), false),
+ aNewMessages[iIndex].Subject,
+ {'Folder': aNewMessages[iIndex].Folder, 'Uid': aNewMessages[iIndex].Uid}
+ );
+ }
+ }
+ }
+
+ Cache.setFolderUidNext(sFolder, sUidNext);
+ }
+ };
+
+ MessageUserStore.prototype.hideMessageBodies = function ()
+ {
+ var oMessagesDom = this.messagesBodiesDom();
+ if (oMessagesDom)
+ {
+ oMessagesDom.find('.b-text-part').hide();
+ }
+ };
+
+ /**
+ * @param {string} sFromFolderFullNameRaw
+ * @param {Array} aUidForRemove
+ * @param {string=} sToFolderFullNameRaw = ''
+ * @param {bCopy=} bCopy = false
+ */
+ MessageUserStore.prototype.removeMessagesFromList = function (
+ sFromFolderFullNameRaw, aUidForRemove, sToFolderFullNameRaw, bCopy)
+ {
+ sToFolderFullNameRaw = Utils.isNormal(sToFolderFullNameRaw) ? sToFolderFullNameRaw : '';
+ bCopy = Utils.isUnd(bCopy) ? false : !!bCopy;
+
+ aUidForRemove = _.map(aUidForRemove, function (mValue) {
+ return Utils.pInt(mValue);
+ });
+
+ var
+ self = this,
+ iUnseenCount = 0,
+ oMessage = null,
+ sTrashFolder = FolderStore.trashFolder(),
+ sSpamFolder = FolderStore.spamFolder(),
+ aMessageList = this.messageList(),
+ oFromFolder = Cache.getFolderFromCacheList(sFromFolderFullNameRaw),
+ oToFolder = '' === sToFolderFullNameRaw ? null : Cache.getFolderFromCacheList(sToFolderFullNameRaw || ''),
+ sCurrentFolderFullNameRaw = FolderStore.currentFolderFullNameRaw(),
+ oCurrentMessage = this.message(),
+ aMessages = sCurrentFolderFullNameRaw === sFromFolderFullNameRaw ? _.filter(aMessageList, function (oMessage) {
+ return oMessage && -1 < Utils.inArray(Utils.pInt(oMessage.uid), aUidForRemove);
+ }) : []
+ ;
+
+ _.each(aMessages, function (oMessage) {
+ if (oMessage && oMessage.unseen())
+ {
+ iUnseenCount++;
+ }
+ });
+
+ if (oFromFolder && !bCopy)
+ {
+ oFromFolder.messageCountAll(0 <= oFromFolder.messageCountAll() - aUidForRemove.length ?
+ oFromFolder.messageCountAll() - aUidForRemove.length : 0);
+
+ if (0 < iUnseenCount)
+ {
+ oFromFolder.messageCountUnread(0 <= oFromFolder.messageCountUnread() - iUnseenCount ?
+ oFromFolder.messageCountUnread() - iUnseenCount : 0);
+ }
+ }
+
+ if (oToFolder)
+ {
+ if (sTrashFolder === oToFolder.fullNameRaw || sSpamFolder === oToFolder.fullNameRaw)
+ {
+ iUnseenCount = 0;
+ }
+
+ oToFolder.messageCountAll(oToFolder.messageCountAll() + aUidForRemove.length);
+ if (0 < iUnseenCount)
+ {
+ oToFolder.messageCountUnread(oToFolder.messageCountUnread() + iUnseenCount);
+ }
+
+ oToFolder.actionBlink(true);
+ }
+
+ if (0 < aMessages.length)
+ {
+ if (bCopy)
+ {
+ _.each(aMessages, function (oMessage) {
+ oMessage.checked(false);
+ });
+ }
+ else
+ {
+ this.messageListIsNotCompleted(true);
+
+ _.each(aMessages, function (oMessage) {
+ if (oCurrentMessage && oCurrentMessage.hash === oMessage.hash)
+ {
+ oCurrentMessage = null;
+ self.message(null);
+ }
+
+ oMessage.deleted(true);
+ });
+
+ _.delay(function () {
+ _.each(aMessages, function (oMessage) {
+ self.messageList.remove(oMessage);
+ });
+ }, 400);
+ }
+ }
+
+ if ('' !== sFromFolderFullNameRaw)
+ {
+ Cache.setFolderHash(sFromFolderFullNameRaw, '');
+ }
+
+ if ('' !== sToFolderFullNameRaw)
+ {
+ Cache.setFolderHash(sToFolderFullNameRaw, '');
+ }
+
+ if ('' !== this.messageListThreadUid())
+ {
+ aMessageList = this.messageList();
+
+ if (aMessageList && 0 < aMessageList.length && !!_.find(aMessageList, function (oMessage) {
+ return !!(oMessage && oMessage.deleted() && oMessage.uid === self.messageListThreadUid());
+ }))
+ {
+ oMessage = _.find(aMessageList, function (oMessage) {
+ return oMessage && !oMessage.deleted();
+ });
+
+ if (oMessage && this.messageListThreadUid() !== Utils.pString(oMessage.uid))
+ {
+ this.messageListThreadUid(Utils.pString(oMessage.uid));
+
+ kn.setHash(Links.mailBox(
+ FolderStore.currentFolderFullNameHash(),
+ this.messageListPage(),
+ this.messageListSearch(),
+ this.messageListThreadUid()
+ ), true, true);
+ }
+ else if (!oMessage)
+ {
+ if (1 < this.messageListPage())
+ {
+ this.messageListPage(this.messageListPage() - 1);
+
+ kn.setHash(Links.mailBox(
+ FolderStore.currentFolderFullNameHash(),
+ this.messageListPage(),
+ this.messageListSearch(),
+ this.messageListThreadUid()
+ ), true, true);
+ }
+ else
+ {
+ this.messageListThreadUid('');
+
+ kn.setHash(Links.mailBox(
+ FolderStore.currentFolderFullNameHash(),
+ this.messageListPageBeforeThread(),
+ this.messageListSearch()
+ ), true, true);
+ }
+ }
+ }
+ }
+ };
+
+ MessageUserStore.prototype.addBlockquoteSwitcherCallback = function ()
+ {
+ var $self = $(this);
+ if ('' !== Utils.trim(($self.text())))
+ {
+ $self.addClass('rl-bq-switcher hidden-bq');
+ $('
')
+ .insertBefore($self)
+ .on('click.rlBlockquoteSwitcher', function () {
+ $self.toggleClass('hidden-bq');
+ Utils.windowResize();
+ })
+ .after('
')
+ .before('
')
+ ;
+ }
+ };
+
+ /**
+ * @param {Object} oMessageTextBody
+ */
+ MessageUserStore.prototype.initBlockquoteSwitcher = function (oMessageTextBody)
+ {
+ if (oMessageTextBody)
+ {
+ var $oList = $('blockquote:not(.rl-bq-switcher)', oMessageTextBody).filter(function () {
+ return 0 === $(this).parent().closest('blockquote', oMessageTextBody).length;
+ });
+
+ if ($oList && 0 < $oList.length)
+ {
+ $oList.each(this.addBlockquoteSwitcherCallback);
+ }
+ }
+ };
+
+ /**
+ * @param {Object} oMessageTextBody
+ */
+ MessageUserStore.prototype.initOpenPgpControls = function (oMessageTextBody, oMessage)
+ {
+ if (oMessageTextBody && oMessageTextBody.find)
+ {
+ oMessageTextBody.find('.b-plain-openpgp:not(.inited)').each(function () {
+ PgpStore.initMessageBodyControls($(this), oMessage);
+ });
+ }
+ };
+
+ MessageUserStore.prototype.setMessage = function (oData, bCached)
+ {
+ var
+ bNew = false,
+ bIsHtml = false,
+ bHasExternals = false,
+ bHasInternals = false,
+ oBody = null,
+ oTextBody = null,
+ sId = '',
+ sPlain = '',
+ sResultHtml = '',
+ bPgpSigned = false,
+ bPgpEncrypted = false,
+ oMessagesDom = this.messagesBodiesDom(),
+ oSelectedMessage = this.selectorMessageSelected(),
+ oMessage = this.message(),
+ aThreads = []
+ ;
+
+ if (oData && oMessage && oData.Result && 'Object/Message' === oData.Result['@Object'] &&
+ oMessage.folderFullNameRaw === oData.Result.Folder)
+ {
+ aThreads = oMessage.threads();
+ if (oMessage.uid !== oData.Result.Uid && 1 < aThreads.length &&
+ -1 < Utils.inArray(oData.Result.Uid, aThreads))
+ {
+ oMessage = MessageModel.newInstanceFromJson(oData.Result);
+ if (oMessage)
+ {
+ oMessage.threads(aThreads);
+ Cache.initMessageFlagsFromCache(oMessage);
+
+ this.message(this.staticMessage.populateByMessageListItem(oMessage));
+ oMessage = this.message();
+
+ bNew = true;
+ }
+ }
+
+ if (oMessage && oMessage.uid === oData.Result.Uid)
+ {
+ this.messageError('');
+
+ oMessage.initUpdateByMessageJson(oData.Result);
+ Cache.addRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid);
+
+ if (!bCached)
+ {
+ oMessage.initFlagsByJson(oData.Result);
+ }
+
+ oMessagesDom = oMessagesDom && oMessagesDom[0] ? oMessagesDom : null;
+ if (oMessagesDom)
+ {
+ sId = 'rl-mgs-' + oMessage.hash.replace(/[^a-zA-Z0-9]/g, '');
+ oTextBody = oMessagesDom.find('#' + sId);
+
+ if (!oTextBody || !oTextBody[0])
+ {
+ bHasExternals = !!oData.Result.HasExternals;
+ bHasInternals = !!oData.Result.HasInternals;
+
+ if (Utils.isNormal(oData.Result.Html) && '' !== oData.Result.Html)
+ {
+ bIsHtml = true;
+ sResultHtml = oData.Result.Html.toString();
+ }
+ else if (Utils.isNormal(oData.Result.Plain) && '' !== oData.Result.Plain)
+ {
+ bIsHtml = false;
+ sResultHtml = Utils.plainToHtml(oData.Result.Plain.toString(), false);
+
+ if ((oMessage.isPgpSigned() || oMessage.isPgpEncrypted()) && __webpack_require__(/*! Stores/User/Pgp */ 33).capaOpenPGP())
+ {
+ sPlain = Utils.pString(oData.Result.Plain);
+
+ bPgpEncrypted = /---BEGIN PGP MESSAGE---/.test(sPlain);
+ if (!bPgpEncrypted)
+ {
+ bPgpSigned = /-----BEGIN PGP SIGNED MESSAGE-----/.test(sPlain) &&
+ /-----BEGIN PGP SIGNATURE-----/.test(sPlain);
+ }
+
+ Globals.$div.empty();
+ if (bPgpSigned && oMessage.isPgpSigned())
+ {
+ sResultHtml =
+ Globals.$div.append(
+ $('
').text(sPlain)
+ ).html()
+ ;
+ }
+ else if (bPgpEncrypted && oMessage.isPgpEncrypted())
+ {
+ sResultHtml =
+ Globals.$div.append(
+ $('
').text(sPlain)
+ ).html()
+ ;
+ }
+ else
+ {
+ sResultHtml = '
' + sResultHtml + ' ';
+ }
+
+ sPlain = '';
+
+ Globals.$div.empty();
+
+ oMessage.isPgpSigned(bPgpSigned);
+ oMessage.isPgpEncrypted(bPgpEncrypted);
+ }
+ else
+ {
+ sResultHtml = '
' + sResultHtml + ' ';
+ }
+ }
+ else
+ {
+ bIsHtml = false;
+ sResultHtml = '
' + sResultHtml + ' ';
+ }
+
+ oBody = $('
').hide().addClass('rl-cache-class');
+ oBody.data('rl-cache-count', ++Globals.iMessageBodyCacheCount);
+
+ oBody
+ .html(Utils.findEmailAndLinks(sResultHtml))
+ .addClass('b-text-part ' + (bIsHtml ? 'html' : 'plain'))
+ ;
+
+ oMessage.isHtml(!!bIsHtml);
+ oMessage.hasImages(!!bHasExternals);
+
+ oMessage.body = oBody;
+ if (oMessage.body)
+ {
+ oMessagesDom.append(oMessage.body);
+ }
+
+ oMessage.storeDataInDom();
+
+ if (bHasInternals)
+ {
+ oMessage.showInternalImages(true);
+ }
+
+ if (oMessage.hasImages() && SettingsStore.showImages())
+ {
+ oMessage.showExternalImages(true);
+ }
+
+ this.purgeMessageBodyCacheThrottle();
+ }
+ else
+ {
+ oMessage.body = oTextBody;
+ if (oMessage.body)
+ {
+ oMessage.body.data('rl-cache-count', ++Globals.iMessageBodyCacheCount);
+ oMessage.fetchDataFromDom();
+ }
+ }
+
+ this.messageActiveDom(oMessage.body);
+
+ this.hideMessageBodies();
+
+ if (oBody)
+ {
+ this.initOpenPgpControls(oBody, oMessage);
+
+ this.initBlockquoteSwitcher(oBody);
+ }
+
+ oMessage.body.show();
+ }
+
+ Cache.initMessageFlagsFromCache(oMessage);
+ if (oMessage.unseen() || oMessage.hasUnseenSubMessage())
+ {
+ __webpack_require__(/*! App/User */ 7).default.messageListAction(oMessage.folderFullNameRaw,
+ oMessage.uid, Enums.MessageSetAction.SetSeen, [oMessage]);
+ }
+
+ if (bNew)
+ {
+ oMessage = this.message();
+
+ if (oSelectedMessage && oMessage && (
+ oMessage.folderFullNameRaw !== oSelectedMessage.folderFullNameRaw ||
+ oMessage.uid !== oSelectedMessage.uid
+ ))
+ {
+ this.selectorMessageSelected(null);
+ if (1 === this.messageList().length)
+ {
+ this.selectorMessageFocused(null);
+ }
+ }
+ else if (!oSelectedMessage && oMessage)
+ {
+ oSelectedMessage = _.find(this.messageList(), function (oSubMessage) {
+ return oSubMessage &&
+ oSubMessage.folderFullNameRaw === oMessage.folderFullNameRaw &&
+ oSubMessage.uid === oMessage.uid;
+ });
+
+ if (oSelectedMessage)
+ {
+ this.selectorMessageSelected(oSelectedMessage);
+ this.selectorMessageFocused(oSelectedMessage);
+ }
+ }
+
+ }
+
+ Utils.windowResize();
+ }
+ }
+ };
+
+ MessageUserStore.prototype.selectMessage = function (oMessage)
+ {
+ if (oMessage)
+ {
+ this.message(this.staticMessage.populateByMessageListItem(oMessage));
+
+ this.populateMessageBody(this.message());
+ }
+ else
+ {
+ this.message(null);
+ }
+ };
+
+ MessageUserStore.prototype.selectMessageByFolderAndUid = function (sFolder, sUid)
+ {
+ if (sFolder && sUid)
+ {
+ this.message(this.staticMessage.populateByMessageListItem(null));
+ this.message().folderFullNameRaw = sFolder;
+ this.message().uid = sUid;
+
+ this.populateMessageBody(this.message());
+ }
+ else
+ {
+ this.message(null);
+ }
+ };
+
+ MessageUserStore.prototype.populateMessageBody = function (oMessage)
+ {
+ if (oMessage)
+ {
+ if (Remote.message(this.onMessageResponse, oMessage.folderFullNameRaw, oMessage.uid))
+ {
+ this.messageCurrentLoading(true);
+ }
+ }
+ };
+
+ /**
+ * @param {string} sResult
+ * @param {AjaxJsonDefaultResponse} oData
+ * @param {boolean} bCached
+ */
+ MessageUserStore.prototype.onMessageResponse = function (sResult, oData, bCached)
+ {
+ this.hideMessageBodies();
+
+ this.messageCurrentLoading(false);
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ this.setMessage(oData, bCached);
+ }
+ else if (Enums.StorageResultType.Unload === sResult)
+ {
+ this.message(null);
+ this.messageError('');
+ }
+ else if (Enums.StorageResultType.Abort !== sResult)
+ {
+ this.message(null);
+ this.messageError((oData && oData.ErrorCode ?
+ Translator.getNotification(oData.ErrorCode) :
+ Translator.getNotification(Enums.Notification.UnknownError)));
+ }
+ };
+
+ /**
+ * @param {Array} aList
+ * @return {string}
+ */
+ MessageUserStore.prototype.calculateMessageListHash = function (aList)
+ {
+ return _.map(aList, function (oMessage) {
+ return '' + oMessage.hash + '_' + oMessage.threadsLen() + '_' + oMessage.flagHash();
+ }).join('|');
+ };
+
+ MessageUserStore.prototype.setMessageList = function (oData, bCached)
+ {
+ if (oData && oData.Result && 'Collection/MessageCollection' === oData.Result['@Object'] &&
+ oData.Result['@Collection'] && Utils.isArray(oData.Result['@Collection']))
+ {
+ var
+ iIndex = 0,
+ iLen = 0,
+ iCount = 0,
+ iOffset = 0,
+ aList = [],
+ oJsonMessage = null,
+ oMessage = null,
+ oFolder = null,
+ iNewCount = 0,
+ iUtc = __webpack_require__(/*! Common/Momentor */ 26).momentNowUnix(),
+ bUnreadCountChange = false
+ ;
+
+ iCount = Utils.pInt(oData.Result.MessageResultCount);
+ iOffset = Utils.pInt(oData.Result.Offset);
+
+ oFolder = Cache.getFolderFromCacheList(
+ Utils.isNormal(oData.Result.Folder) ? oData.Result.Folder : '');
+
+ if (oFolder && !bCached)
+ {
+ oFolder.interval = iUtc;
+
+ Cache.setFolderHash(oData.Result.Folder, oData.Result.FolderHash);
+
+ if (Utils.isNormal(oData.Result.MessageCount))
+ {
+ oFolder.messageCountAll(oData.Result.MessageCount);
+ }
+
+ if (Utils.isNormal(oData.Result.MessageUnseenCount))
+ {
+ if (Utils.pInt(oFolder.messageCountUnread()) !== Utils.pInt(oData.Result.MessageUnseenCount))
+ {
+ bUnreadCountChange = true;
+ }
+
+ oFolder.messageCountUnread(oData.Result.MessageUnseenCount);
+ }
+
+ this.initUidNextAndNewMessages(oFolder.fullNameRaw, oData.Result.UidNext, oData.Result.NewMessages);
+ }
+
+ if (bUnreadCountChange && oFolder)
+ {
+ Cache.clearMessageFlagsFromCacheByFolder(oFolder.fullNameRaw);
+ }
+
+ for (iIndex = 0, iLen = oData.Result['@Collection'].length; iIndex < iLen; iIndex++)
+ {
+ oJsonMessage = oData.Result['@Collection'][iIndex];
+ if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object'])
+ {
+ oMessage = MessageModel.newInstanceFromJson(oJsonMessage);
+ if (oMessage)
+ {
+ if (Cache.hasNewMessageAndRemoveFromCache(oMessage.folderFullNameRaw, oMessage.uid) && 5 >= iNewCount)
+ {
+ iNewCount++;
+ oMessage.newForAnimation(true);
+ }
+
+ oMessage.deleted(false);
+
+ if (bCached)
+ {
+ Cache.initMessageFlagsFromCache(oMessage);
+ }
+ else
+ {
+ Cache.storeMessageFlagsToCache(oMessage);
+ }
+
+ aList.push(oMessage);
+ }
+ }
+ }
+
+ this.messageListCount(iCount);
+ this.messageListSearch(Utils.isNormal(oData.Result.Search) ? oData.Result.Search : '');
+ this.messageListPage(window.Math.ceil((iOffset / SettingsStore.messagesPerPage()) + 1));
+ this.messageListThreadUid(Utils.isNormal(oData.Result.ThreadUid) ? Utils.pString(oData.Result.ThreadUid) : '');
+
+ this.messageListEndFolder(Utils.isNormal(oData.Result.Folder) ? oData.Result.Folder : '');
+ this.messageListEndSearch(this.messageListSearch());
+ this.messageListEndThreadUid(this.messageListThreadUid());
+ this.messageListEndPage(this.messageListPage());
+
+ this.messageListDisableAutoSelect(true);
+
+ this.messageList(aList);
+ this.messageListIsNotCompleted(false);
+
+ Cache.clearNewMessageCache();
+
+ if (oFolder && (bCached || bUnreadCountChange || SettingsStore.useThreads()))
+ {
+ __webpack_require__(/*! App/User */ 7).default.folderInformation(oFolder.fullNameRaw, aList);
+ }
+ }
+ else
+ {
+ this.messageListCount(0);
+ this.messageList([]);
+ this.messageListError(Translator.getNotification(
+ oData && oData.ErrorCode ? oData.ErrorCode : Enums.Notification.CantGetMessageList
+ ));
+ }
+ };
+
+ module.exports = new MessageUserStore();
+
+ }());
+
+
+
+/***/ },
+/* 33 */
+/*!********************************!*\
+ !*** ./dev/Stores/User/Pgp.js ***!
+ \********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+ $ = __webpack_require__(/*! $ */ 14),
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1)
+ ;
+
+ /**
+ * @constructor
+ */
+ function PgpUserStore()
+ {
+ this.capaOpenPGP = ko.observable(false);
+
+ this.openpgp = null;
+
+ this.openpgpkeys = ko.observableArray([]);
+ this.openpgpKeyring = null;
+
+ this.openpgpkeysPublic = this.openpgpkeys.filter(function (oItem) {
+ return !!(oItem && !oItem.isPrivate);
+ });
+
+ this.openpgpkeysPrivate = this.openpgpkeys.filter(function (oItem) {
+ return !!(oItem && oItem.isPrivate);
+ });
+ }
+
+ /**
+ * @return {boolean}
+ */
+ PgpUserStore.prototype.isSupported = function ()
+ {
+ return !!this.openpgp;
+ };
+
+ PgpUserStore.prototype.findKeyByHex = function (aKeys,sHash)
+ {
+ return _.find(aKeys, function (oItem) {
+ return sHash && oItem && (sHash === oItem.id || -1 < oItem.ids.indexOf(sHash));
+ });
+ };
+
+ PgpUserStore.prototype.findPublicKeyByHex = function (sHash)
+ {
+ return this.findKeyByHex(this.openpgpkeysPublic(), sHash);
+ };
+
+ PgpUserStore.prototype.findPrivateKeyByHex = function (sHash)
+ {
+ return this.findKeyByHex(this.openpgpkeysPrivate(), sHash);
+ };
+
+ PgpUserStore.prototype.findPublicKeysByEmail = function (sEmail)
+ {
+ return _.compact(_.flatten(_.map(this.openpgpkeysPublic(), function (oItem) {
+ var oKey = oItem && -1 < oItem.emails.indexOf(sEmail) ? oItem : null;
+ return oKey ? oKey.getNativeKeys() : [null];
+ }), true));
+ };
+
+ PgpUserStore.prototype.findPublicKeysBySigningKeyIds = function (aSigningKeyIds)
+ {
+ var self = this;
+ return _.compact(_.flatten(_.map(aSigningKeyIds, function (oId) {
+ var oKey = oId && oId.toHex ? self.findPublicKeyByHex(oId.toHex()) : null;
+ return oKey ? oKey.getNativeKeys() : [null];
+ }), true));
+ };
+
+ PgpUserStore.prototype.findPrivateKeysByEncryptionKeyIds = function (aEncryptionKeyIds, aRecipients, bReturnWrapKeys)
+ {
+ var self = this, aResult = [];
+ aResult = Utils.isArray(aEncryptionKeyIds) ? _.compact(_.flatten(_.map(aEncryptionKeyIds, function (oId) {
+ var oKey = oId && oId.toHex ? self.findPrivateKeyByHex(oId.toHex()) : null;
+ return oKey ? (bReturnWrapKeys ? [oKey] : oKey.getNativeKeys()) : [null];
+ }), true)) : [];
+
+ if (0 === aResult.length && Utils.isNonEmptyArray(aRecipients))
+ {
+ aResult = _.uniq(_.compact(_.flatten(_.map(aRecipients, function (sEmail) {
+ var aKeys = sEmail ? self.findAllPrivateKeysByEmailNotNative(sEmail) : null;
+ return aKeys ? (bReturnWrapKeys ? aKeys : _.flatten(_.map(aKeys, function (oKey) { return oKey.getNativeKeys(); }), true)) : [null];
+ }), true)), function (oKey) { return oKey.id; });
+ }
+
+ return aResult;
+ };
+
+ /**
+ * @param {string} sEmail
+ * @return {?}
+ */
+ PgpUserStore.prototype.findPublicKeyByEmailNotNative = function (sEmail)
+ {
+ return _.find(this.openpgpkeysPublic(), function (oItem) {
+ return oItem && -1 < oItem.emails.indexOf(sEmail);
+ }) || null;
+ };
+
+ /**
+ * @param {string} sEmail
+ * @return {?}
+ */
+ PgpUserStore.prototype.findPrivateKeyByEmailNotNative = function (sEmail)
+ {
+ return _.find(this.openpgpkeysPrivate(), function (oItem) {
+ return oItem && -1 < oItem.emails.indexOf(sEmail);
+ }) || null;
+ };
+
+ /**
+ * @param {string} sEmail
+ * @return {?}
+ */
+ PgpUserStore.prototype.findAllPublicKeysByEmailNotNative = function (sEmail)
+ {
+ return _.filter(this.openpgpkeysPublic(), function (oItem) {
+ return oItem && -1 < oItem.emails.indexOf(sEmail);
+ }) || null;
+ };
+
+ /**
+ * @param {string} sEmail
+ * @return {?}
+ */
+ PgpUserStore.prototype.findAllPrivateKeysByEmailNotNative = function (sEmail)
+ {
+ return _.filter(this.openpgpkeysPrivate(), function (oItem) {
+ return oItem && -1 < oItem.emails.indexOf(sEmail);
+ }) || null;
+ };
+
+ /**
+ * @param {string} sEmail
+ * @param {string=} sPassword
+ * @return {?}
+ */
+ PgpUserStore.prototype.findPrivateKeyByEmail = function (sEmail, sPassword)
+ {
+ var
+ oPrivateKeys = [],
+ oPrivateKey = null,
+ oKey = _.find(this.openpgpkeysPrivate(), function (oItem) {
+ return oItem && -1 < oItem.emails.indexOf(sEmail);
+ })
+ ;
+
+ if (oKey)
+ {
+ oPrivateKeys = oKey.getNativeKeys();
+ oPrivateKey = oPrivateKeys[0] || null;
+
+ try
+ {
+ if (oPrivateKey)
+ {
+ oPrivateKey.decrypt(Utils.pString(sPassword));
+ }
+ }
+ catch (e)
+ {
+ oPrivateKey = null;
+ }
+ }
+
+ return oPrivateKey;
+ };
+
+ /**
+ * @param {string=} sPassword
+ * @return {?}
+ */
+ PgpUserStore.prototype.findSelfPrivateKey = function (sPassword)
+ {
+ return this.findPrivateKeyByEmail(__webpack_require__(/*! Stores/User/Account */ 31).email(), sPassword);
+ };
+
+ PgpUserStore.prototype.decryptMessage = function (oMessage, aRecipients, fCallback)
+ {
+ var self = this, aPrivateKeys = [];
+ if (oMessage && oMessage.getEncryptionKeyIds)
+ {
+ aPrivateKeys = this.findPrivateKeysByEncryptionKeyIds(oMessage.getEncryptionKeyIds(), aRecipients, true);
+ if (aPrivateKeys && 0 < aPrivateKeys.length)
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/MessageOpenPgp */ 147), [function (oDecryptedKey) {
+
+ if (oDecryptedKey)
+ {
+ oMessage.decrypt(oDecryptedKey).then(function(oDecryptedMessage){
+ var oPrivateKey = null;
+ if (oDecryptedMessage)
+ {
+ oPrivateKey = self.findPrivateKeyByHex(oDecryptedKey.primaryKey.keyid.toHex());
+ if (oPrivateKey)
+ {
+ self.verifyMessage(oDecryptedMessage, function (oValidKey, aSigningKeyIds) {
+ fCallback(oPrivateKey, oDecryptedMessage, oValidKey || null, aSigningKeyIds || null);
+ });
+ }
+ else
+ {
+ fCallback(oPrivateKey, oDecryptedMessage);
+ }
+ }
+ else
+ {
+ fCallback(oPrivateKey, oDecryptedMessage);
+ }
+
+ }, function() {
+ fCallback(null, null);
+ });
+ }
+ else
+ {
+ fCallback(null, null);
+ }
+
+ }, aPrivateKeys]);
+
+ return false;
+ }
+ }
+
+ fCallback(null, null);
+
+ return false;
+ };
+
+ PgpUserStore.prototype.verifyMessage = function (oMessage, fCallback)
+ {
+ var oValid = null, aResult = [], aPublicKeys = [], aSigningKeyIds = [];
+ if (oMessage && oMessage.getSigningKeyIds)
+ {
+ aSigningKeyIds = oMessage.getSigningKeyIds();
+ if (aSigningKeyIds && 0 < aSigningKeyIds.length)
+ {
+ aPublicKeys = this.findPublicKeysBySigningKeyIds(aSigningKeyIds);
+ if (aPublicKeys && 0 < aPublicKeys.length)
+ {
+ try
+ {
+ aResult = oMessage.verify(aPublicKeys);
+ oValid = _.find(_.isArray(aResult) ? aResult : [], function (oItem) {
+ return oItem && oItem.valid && oItem.keyid;
+ });
+
+ if (oValid && oValid.keyid && oValid.keyid && oValid.keyid.toHex)
+ {
+ fCallback(this.findPublicKeyByHex(oValid.keyid.toHex()));
+ return true;
+ }
+ }
+ catch (e)
+ {
+ Utils.log(e);
+ }
+ }
+
+ fCallback(null, aSigningKeyIds);
+ return false;
+ }
+ }
+
+ fCallback(null);
+ return false;
+ };
+
+ /**
+ * @param {*} mDom
+ */
+ PgpUserStore.prototype.controlsHelper = function (mDom, oVerControl, bSuccess, sTitle, sText)
+ {
+ if (bSuccess)
+ {
+ mDom.removeClass('error').addClass('success').attr('title', sTitle);
+ oVerControl.removeClass('error').addClass('success').attr('title', sTitle);
+ }
+ else
+ {
+ mDom.removeClass('success').addClass('error').attr('title', sTitle);
+ oVerControl.removeClass('success').addClass('error').attr('title', sTitle);
+ }
+
+ if (!Utils.isUnd(sText))
+ {
+ mDom.text(Utils.trim(sText.replace(/(\u200C|\u0002)/g, '')));
+ }
+ };
+
+ /**
+ * @static
+ */
+ PgpUserStore.domControlEncryptedClickHelper = function (self, mDom, sArmoredMessage, aRecipients)
+ {
+ return function () {
+
+ var oMessage = null, $this = $(this);
+ if ($this.hasClass('success'))
+ {
+ return false;
+ }
+
+ try
+ {
+ oMessage = self.openpgp.message.readArmored(sArmoredMessage);
+ }
+ catch (e)
+ {
+ Utils.log(e);
+ }
+
+ if (oMessage && oMessage.getText && oMessage.verify && oMessage.decrypt)
+ {
+ self.decryptMessage(oMessage, aRecipients, function (oValidPrivateKey, oDecryptedMessage, oValidPublicKey, aSigningKeyIds) {
+
+ if (oDecryptedMessage)
+ {
+ if (oValidPublicKey)
+ {
+ self.controlsHelper(mDom, $this, true, Translator.i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', {
+ 'USER': oValidPublicKey.user + ' (' + oValidPublicKey.id + ')'
+ }), oDecryptedMessage.getText());
+ }
+ else if (oValidPrivateKey)
+ {
+ var
+ aKeyIds = Utils.isNonEmptyArray(aSigningKeyIds) ? aSigningKeyIds : null,
+ sAdditional = aKeyIds ? _.compact(_.map(aKeyIds, function (oItem) {
+ return oItem && oItem.toHex ? oItem.toHex() : null;
+ })).join(', ') : ''
+ ;
+
+ self.controlsHelper(mDom, $this, false,
+ Translator.i18n('PGP_NOTIFICATIONS/UNVERIFIRED_SIGNATURE') +
+ (sAdditional ? ' (' + sAdditional + ')' : ''),
+ oDecryptedMessage.getText());
+ }
+ else
+ {
+ self.controlsHelper(mDom, $this, false,
+ Translator.i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
+ }
+ }
+ else
+ {
+ self.controlsHelper(mDom, $this, false,
+ Translator.i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
+ }
+ });
+
+ return false;
+ }
+
+ self.controlsHelper(mDom, $this, false, Translator.i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
+ return false;
+ };
+ };
+
+ /**
+ * @static
+ */
+ PgpUserStore.domControlSignedClickHelper = function (self, mDom, sArmoredMessage)
+ {
+ return function () {
+
+ var oMessage = null, $this = $(this);
+ if ($this.hasClass('success') || $this.hasClass('error'))
+ {
+ return false;
+ }
+
+ try
+ {
+ oMessage = self.openpgp.cleartext.readArmored(sArmoredMessage);
+ }
+ catch (e)
+ {
+ Utils.log(e);
+ }
+
+ if (oMessage && oMessage.getText && oMessage.verify)
+ {
+ self.verifyMessage(oMessage, function (oValidKey, aSigningKeyIds) {
+ if (oValidKey)
+ {
+ self.controlsHelper(mDom, $this, true, Translator.i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', {
+ 'USER': oValidKey.user + ' (' + oValidKey.id + ')'
+ }), oMessage.getText());
+ }
+ else
+ {
+ var
+ aKeyIds = Utils.isNonEmptyArray(aSigningKeyIds) ? aSigningKeyIds : null,
+ sAdditional = aKeyIds ? _.compact(_.map(aKeyIds, function (oItem) {
+ return oItem && oItem.toHex ? oItem.toHex() : null;
+ })).join(', ') : ''
+ ;
+
+ self.controlsHelper(mDom, $this, false,
+ Translator.i18n('PGP_NOTIFICATIONS/UNVERIFIRED_SIGNATURE') +
+ (sAdditional ? ' (' + sAdditional + ')' : ''));
+ }
+ });
+
+ return false;
+ }
+
+ self.controlsHelper(mDom, $this, false, Translator.i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
+ return false;
+ };
+ };
+
+ /**
+ * @param {*} mDom
+ * @param {MessageModel} oRainLoopMessage
+ */
+ PgpUserStore.prototype.initMessageBodyControls = function (mDom, oRainLoopMessage)
+ {
+ if (mDom && !mDom.hasClass('inited'))
+ {
+ mDom.addClass('inited');
+
+ var
+ bEncrypted = mDom.hasClass('encrypted'),
+ bSigned = mDom.hasClass('signed'),
+ oVerControl = null,
+ aRecipients = oRainLoopMessage ? oRainLoopMessage.getEmails(['from', 'to', 'cc']) : [],
+ sData = ''
+ ;
+
+ if (bEncrypted || bSigned)
+ {
+ sData = mDom.text();
+ mDom.data('openpgp-original', sData);
+
+ if (bEncrypted)
+ {
+ oVerControl = $('
')
+ .attr('title', Translator.i18n('MESSAGE/PGP_ENCRYPTED_MESSAGE_DESC'))
+ .on('click', PgpUserStore.domControlEncryptedClickHelper(this, mDom, sData, aRecipients))
+ ;
+ }
+ else if (bSigned)
+ {
+ oVerControl = $('
')
+ .attr('title', Translator.i18n('MESSAGE/PGP_SIGNED_MESSAGE_DESC'))
+ .on('click', PgpUserStore.domControlSignedClickHelper(this, mDom, sData))
+ ;
+ }
+
+ if (oVerControl)
+ {
+ mDom.before(oVerControl).before('
');
+ }
+ }
+ }
+ };
+
+ module.exports = new PgpUserStore();
+
+ }());
+
+
+
+/***/ },
+/* 34 */
+/*!******************************!*\
+ !*** ./dev/Stores/Social.js ***!
+ \******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2)
+ ;
+
+ /**
+ * @constructor
+ */
+ function SocialStore()
+ {
+ this.google = {};
+ this.twitter = {};
+ this.facebook = {};
+ this.dropbox = {};
+
+ // Google
+ this.google.enabled = ko.observable(false);
+
+ this.google.clientID = ko.observable('');
+ this.google.clientSecret = ko.observable('');
+ this.google.apiKey = ko.observable('');
+
+ this.google.loading = ko.observable(false);
+ this.google.userName = ko.observable('');
+
+ this.google.loggined = ko.computed(function () {
+ return '' !== this.google.userName();
+ }, this);
+
+ this.google.capa = {};
+ this.google.capa.auth = ko.observable(false);
+ this.google.capa.authFast = ko.observable(false);
+ this.google.capa.drive = ko.observable(false);
+ this.google.capa.preview = ko.observable(false);
+
+ this.google.require = {};
+ this.google.require.clientSettings = ko.computed(function () {
+ return this.google.enabled() && (this.google.capa.auth() || this.google.capa.drive());
+ }, this);
+
+ this.google.require.apiKeySettings = ko.computed(function () {
+ return this.google.enabled() && this.google.capa.drive();
+ }, this);
+
+ // Facebook
+ this.facebook.enabled = ko.observable(false);
+ this.facebook.appID = ko.observable('');
+ this.facebook.appSecret = ko.observable('');
+ this.facebook.loading = ko.observable(false);
+ this.facebook.userName = ko.observable('');
+ this.facebook.supported = ko.observable(false);
+
+ this.facebook.loggined = ko.computed(function () {
+ return '' !== this.facebook.userName();
+ }, this);
+
+ // Twitter
+ this.twitter.enabled = ko.observable(false);
+ this.twitter.consumerKey = ko.observable('');
+ this.twitter.consumerSecret = ko.observable('');
+ this.twitter.loading = ko.observable(false);
+ this.twitter.userName = ko.observable('');
+
+ this.twitter.loggined = ko.computed(function () {
+ return '' !== this.twitter.userName();
+ }, this);
+
+ // Dropbox
+ this.dropbox.enabled = ko.observable(false);
+ this.dropbox.apiKey = ko.observable('');
+ }
+
+ SocialStore.prototype.google = {};
+ SocialStore.prototype.twitter = {};
+ SocialStore.prototype.facebook = {};
+ SocialStore.prototype.dropbox = {};
+
+ SocialStore.prototype.populate = function ()
+ {
+ var Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ this.google.enabled(!!Settings.settingsGet('AllowGoogleSocial'));
+ this.google.clientID(Settings.settingsGet('GoogleClientID'));
+ this.google.clientSecret(Settings.settingsGet('GoogleClientSecret'));
+ this.google.apiKey(Settings.settingsGet('GoogleApiKey'));
+
+ this.google.capa.auth(!!Settings.settingsGet('AllowGoogleSocialAuth'));
+ this.google.capa.authFast(!!Settings.settingsGet('AllowGoogleSocialAuthFast'));
+ this.google.capa.drive(!!Settings.settingsGet('AllowGoogleSocialDrive'));
+ this.google.capa.preview(!!Settings.settingsGet('AllowGoogleSocialPreview'));
+
+ this.facebook.enabled(!!Settings.settingsGet('AllowFacebookSocial'));
+ this.facebook.appID(Settings.settingsGet('FacebookAppID'));
+ this.facebook.appSecret(Settings.settingsGet('FacebookAppSecret'));
+ this.facebook.supported(!!Settings.settingsGet('SupportedFacebookSocial'));
+
+ this.twitter.enabled = ko.observable(!!Settings.settingsGet('AllowTwitterSocial'));
+ this.twitter.consumerKey = ko.observable(Settings.settingsGet('TwitterConsumerKey'));
+ this.twitter.consumerSecret = ko.observable(Settings.settingsGet('TwitterConsumerSecret'));
+
+ this.dropbox.enabled(!!Settings.settingsGet('AllowDropboxSocial'));
+ this.dropbox.apiKey(Settings.settingsGet('DropboxApiKey'));
+ };
+
+ module.exports = new SocialStore();
+
+ }());
+
+
+/***/ },
+/* 35 */,
+/* 36 */
+/*!******************************!*\
+ !*** external "window.JSON" ***!
+ \******************************/
+/***/ function(module, exports) {
+
+ module.exports = window.JSON;
+
+/***/ },
+/* 37 */
+/*!*****************************************!*\
+ !*** ./dev/Component/AbstractInput.jsx ***!
+ \*****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.AbstractInput = undefined;
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Enums = __webpack_require__(/*! Common/Enums */ 4);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var AbstractInput = function (_AbstractComponent) {
+ _inherits(AbstractInput, _AbstractComponent);
+
+ /**
+ * @param {Object} params
+ */
+
+ function AbstractInput(params) {
+ _classCallCheck(this, AbstractInput);
+
+ var _this = _possibleConstructorReturn(this, _AbstractComponent.call(this));
+
+ _this.value = params.value || '';
+ _this.size = params.size || 0;
+ _this.label = params.label || '';
+ _this.preLabel = params.preLabel || '';
+ _this.enable = _Utils2.default.isUnd(params.enable) ? true : params.enable;
+ _this.trigger = params.trigger && params.trigger.subscribe ? params.trigger : null;
+ _this.placeholder = params.placeholder || '';
+
+ _this.labeled = !_Utils2.default.isUnd(params.label);
+ _this.preLabeled = !_Utils2.default.isUnd(params.preLabel);
+ _this.triggered = !_Utils2.default.isUnd(params.trigger) && !!_this.trigger;
+
+ _this.classForTrigger = _ko2.default.observable('');
+
+ _this.className = _ko2.default.computed(function () {
+
+ var size = _ko2.default.unwrap(_this.size),
+ suffixValue = _this.trigger ? ' ' + _Utils2.default.trim('settings-saved-trigger-input ' + _this.classForTrigger()) : '';
+
+ return (size > 0 ? 'span' + size : '') + suffixValue;
+ }, _this);
+
+ if (!_Utils2.default.isUnd(params.width) && params.element) {
+ params.element.find('input,select,textarea').css('width', params.width);
+ }
+
+ _this.disposable.push(_this.className);
+
+ if (_this.trigger) {
+ _this.setTriggerState(_this.trigger());
+
+ _this.disposable.push(_this.trigger.subscribe(_this.setTriggerState, _this));
+ }
+ return _this;
+ }
+
+ AbstractInput.prototype.setTriggerState = function setTriggerState(value) {
+ switch (_Utils2.default.pInt(value)) {
+ case _Enums.SaveSettingsStep.TrueResult:
+ this.classForTrigger('success');
+ break;
+ case _Enums.SaveSettingsStep.FalseResult:
+ this.classForTrigger('error');
+ break;
+ default:
+ this.classForTrigger('');
+ break;
+ }
+ };
+
+ return AbstractInput;
+ }(_Abstract.AbstractComponent);
+
+ exports.AbstractInput = AbstractInput;
+ exports.default = AbstractInput;
+
+/***/ },
+/* 38 */
+/*!************************************!*\
+ !*** ./dev/Component/Checkbox.jsx ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ var _AbstracCheckbox2 = __webpack_require__(/*! Component/AbstracCheckbox */ 46);
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var CheckboxComponent = function (_AbstracCheckbox) {
+ _inherits(CheckboxComponent, _AbstracCheckbox);
+
+ function CheckboxComponent() {
+ _classCallCheck(this, CheckboxComponent);
+
+ return _possibleConstructorReturn(this, _AbstracCheckbox.apply(this, arguments));
+ }
+
+ return CheckboxComponent;
+ }(_AbstracCheckbox2.AbstracCheckbox);
+
+ module.exports = (0, _Abstract.componentExportHelper)(CheckboxComponent, 'CheckboxComponent');
+
+/***/ },
+/* 39 */
+/*!*************************************!*\
+ !*** ./dev/Knoin/AbstractScreen.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ crossroads = __webpack_require__(/*! crossroads */ 49),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1)
+ ;
+
+ /**
+ * @param {string} sScreenName
+ * @param {?=} aViewModels = []
+ * @constructor
+ */
+ function AbstractScreen(sScreenName, aViewModels)
+ {
+ this.sScreenName = sScreenName;
+ this.aViewModels = Utils.isArray(aViewModels) ? aViewModels : [];
+ }
+
+ /**
+ * @type {Array}
+ */
+ AbstractScreen.prototype.oCross = null;
+
+ /**
+ * @type {string}
+ */
+ AbstractScreen.prototype.sScreenName = '';
+
+ /**
+ * @type {Array}
+ */
+ AbstractScreen.prototype.aViewModels = [];
+
+ /**
+ * @return {Array}
+ */
+ AbstractScreen.prototype.viewModels = function ()
+ {
+ return this.aViewModels;
+ };
+
+ /**
+ * @return {string}
+ */
+ AbstractScreen.prototype.screenName = function ()
+ {
+ return this.sScreenName;
+ };
+
+ AbstractScreen.prototype.routes = function ()
+ {
+ return null;
+ };
+
+ /**
+ * @return {?Object}
+ */
+ AbstractScreen.prototype.__cross = function ()
+ {
+ return this.oCross;
+ };
+
+ AbstractScreen.prototype.__start = function ()
+ {
+ var
+ aRoutes = this.routes(),
+ oRoute = null,
+ fMatcher = null
+ ;
+
+ if (Utils.isNonEmptyArray(aRoutes))
+ {
+ fMatcher = _.bind(this.onRoute || Utils.emptyFunction, this);
+ oRoute = crossroads.create();
+
+ _.each(aRoutes, function (aItem) {
+ oRoute.addRoute(aItem[0], fMatcher).rules = aItem[1];
+ });
+
+ this.oCross = oRoute;
+ }
+ };
+
+ module.exports = AbstractScreen;
+
+ }());
+
+/***/ },
+/* 40 */
+/*!********************************!*\
+ !*** ./dev/Stores/Language.js ***!
+ \********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function LanguageStore()
+ {
+ this.languages = ko.observableArray([]);
+ this.languagesAdmin = ko.observableArray([]);
+
+ this.language = ko.observable('')
+ .extend({'limitedList': this.languages});
+
+ this.languageAdmin = ko.observable('')
+ .extend({'limitedList': this.languagesAdmin});
+
+ this.userLanguage = ko.observable('');
+ this.userLanguageAdmin = ko.observable('');
+ }
+
+ LanguageStore.prototype.populate = function ()
+ {
+ var
+ aLanguages = Settings.appSettingsGet('languages'),
+ aLanguagesAdmin = Settings.appSettingsGet('languagesAdmin')
+ ;
+
+ this.languages(Utils.isArray(aLanguages) ? aLanguages : []);
+ this.languagesAdmin(Utils.isArray(aLanguagesAdmin) ? aLanguagesAdmin : []);
+
+ this.language(Settings.settingsGet('Language'));
+ this.languageAdmin(Settings.settingsGet('LanguageAdmin'));
+
+ this.userLanguage(Settings.settingsGet('UserLanguage'));
+ this.userLanguageAdmin(Settings.settingsGet('UserLanguageAdmin'));
+ };
+
+ module.exports = new LanguageStore();
+
+ }());
+
+
+/***/ },
+/* 41 */
+/*!***********************************!*\
+ !*** ./dev/Promises/User/Ajax.js ***!
+ \***********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+
+ // Enums = require('Common/Enums'),
+ // Utils = require('Common/Utils'),
+ // Base64 = require('Common/Base64'),
+ // Cache = require('Common/Cache'),
+ // Links = require('Common/Links'),
+ //
+ // AppStore = require('Stores/User/App'),
+ // SettingsStore = require('Stores/User/Settings'),
+
+ PromisesPopulator = __webpack_require__(/*! Promises/User/Populator */ 112),
+ AbstractAjaxPromises = __webpack_require__(/*! Promises/AbstractAjax */ 111)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractAjaxPromises
+ */
+ function UserAjaxUserPromises()
+ {
+ AbstractAjaxPromises.call(this);
+ }
+
+ _.extend(UserAjaxUserPromises.prototype, AbstractAjaxPromises.prototype);
+
+ UserAjaxUserPromises.prototype.foldersReload = function (fTrigger)
+ {
+ return this.abort('Folders')
+ .postRequest('Folders', fTrigger).then(function (oData) {
+ PromisesPopulator.foldersList(oData.Result);
+ PromisesPopulator.foldersAdditionalParameters(oData.Result);
+ return true;
+ });
+ };
+
+ UserAjaxUserPromises.prototype._folders_timeout_ = 0;
+ UserAjaxUserPromises.prototype.foldersReloadWithTimeout = function (fTrigger)
+ {
+ this.setTrigger(fTrigger, true);
+
+ var self = this;
+ window.clearTimeout(this._folders_timeout_);
+ this._folders_timeout_ = window.setTimeout(function () {
+ self.foldersReload(fTrigger);
+ }, 500);
+ };
+
+ UserAjaxUserPromises.prototype.folderDelete = function (sFolderFullNameRaw, fTrigger)
+ {
+ return this.postRequest('FolderDelete', fTrigger, {
+ 'Folder': sFolderFullNameRaw
+ });
+ };
+
+ UserAjaxUserPromises.prototype.folderCreate = function (sNewFolderName, sParentName, fTrigger)
+ {
+ return this.postRequest('FolderCreate', fTrigger, {
+ 'Folder': sNewFolderName,
+ 'Parent': sParentName
+ });
+ };
+
+ UserAjaxUserPromises.prototype.folderRename = function (sPrevFolderFullNameRaw, sNewFolderName, fTrigger)
+ {
+ return this.postRequest('FolderRename', fTrigger, {
+ 'Folder': sPrevFolderFullNameRaw,
+ 'NewFolderName': sNewFolderName
+ });
+ };
+
+ UserAjaxUserPromises.prototype.attachmentsActions = function (sAction, aHashes, fTrigger)
+ {
+ return this.postRequest('AttachmentsActions', fTrigger, {
+ 'Do': sAction,
+ 'Hashes': aHashes
+ });
+ };
+
+ UserAjaxUserPromises.prototype.welcomeClose = function ()
+ {
+ return this.postRequest('WelcomeClose');
+ };
+
+ module.exports = new UserAjaxUserPromises();
+
+ }());
+
+/***/ },
+/* 42 */
+/*!*****************************!*\
+ !*** ./dev/Stores/Theme.js ***!
+ \*****************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function ThemeStore()
+ {
+ this.themes = ko.observableArray([]);
+ this.themeBackgroundName = ko.observable('');
+ this.themeBackgroundHash = ko.observable('');
+
+ this.theme = ko.observable('')
+ .extend({'limitedList': this.themes});
+ }
+
+ ThemeStore.prototype.populate = function ()
+ {
+ var aThemes = Settings.appSettingsGet('themes');
+
+ this.themes(Utils.isArray(aThemes) ? aThemes : []);
+ this.theme(Settings.settingsGet('Theme'));
+ this.themeBackgroundName(Settings.settingsGet('UserBackgroundName'));
+ this.themeBackgroundHash(Settings.settingsGet('UserBackgroundHash'));
+ };
+
+ module.exports = new ThemeStore();
+
+ }());
+
+
+/***/ },
+/* 43 */
+/*!*******************************!*\
+ !*** ./dev/View/Popup/Ask.js ***!
+ \*******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+ key = __webpack_require__(/*! key */ 18),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function AskPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsAsk');
+
+ this.askDesc = ko.observable('');
+ this.yesButton = ko.observable('');
+ this.noButton = ko.observable('');
+
+ this.yesFocus = ko.observable(false);
+ this.noFocus = ko.observable(false);
+
+ this.fYesAction = null;
+ this.fNoAction = null;
+
+ this.bFocusYesOnShow = true;
+ this.bDisabeCloseOnEsc = true;
+ this.sDefaultKeyScope = Enums.KeyState.PopupAsk;
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/Ask', 'PopupsAskViewModel'], AskPopupView);
+ _.extend(AskPopupView.prototype, AbstractView.prototype);
+
+ AskPopupView.prototype.clearPopup = function ()
+ {
+ this.askDesc('');
+ this.yesButton(Translator.i18n('POPUPS_ASK/BUTTON_YES'));
+ this.noButton(Translator.i18n('POPUPS_ASK/BUTTON_NO'));
+
+ this.yesFocus(false);
+ this.noFocus(false);
+
+ this.fYesAction = null;
+ this.fNoAction = null;
+ };
+
+ AskPopupView.prototype.yesClick = function ()
+ {
+ this.cancelCommand();
+
+ if (Utils.isFunc(this.fYesAction))
+ {
+ this.fYesAction.call(null);
+ }
+ };
+
+ AskPopupView.prototype.noClick = function ()
+ {
+ this.cancelCommand();
+
+ if (Utils.isFunc(this.fNoAction))
+ {
+ this.fNoAction.call(null);
+ }
+ };
+
+ /**
+ * @param {string} sAskDesc
+ * @param {Function=} fYesFunc
+ * @param {Function=} fNoFunc
+ * @param {string=} sYesButton
+ * @param {string=} sNoButton
+ * @param {boolean=} bFocusYesOnShow
+ */
+ AskPopupView.prototype.onShow = function (sAskDesc, fYesFunc, fNoFunc, sYesButton, sNoButton, bFocusYesOnShow)
+ {
+ this.clearPopup();
+
+ this.fYesAction = fYesFunc || null;
+ this.fNoAction = fNoFunc || null;
+
+ this.askDesc(sAskDesc || '');
+ if (sYesButton)
+ {
+ this.yesButton(sYesButton);
+ }
+
+ if (sYesButton)
+ {
+ this.yesButton(sNoButton);
+ }
+
+ this.bFocusYesOnShow = Utils.isUnd(bFocusYesOnShow) ? true : !!bFocusYesOnShow;
+ };
+
+ AskPopupView.prototype.onShowWithDelay = function ()
+ {
+ if (this.bFocusYesOnShow)
+ {
+ this.yesFocus(true);
+ }
+ };
+
+ AskPopupView.prototype.onBuild = function ()
+ {
+ key('tab, shift+tab, right, left', Enums.KeyState.PopupAsk, _.bind(function () {
+ if (this.yesFocus())
+ {
+ this.noFocus(true);
+ }
+ else
+ {
+ this.yesFocus(true);
+ }
+ return false;
+ }, this));
+
+ key('esc', Enums.KeyState.PopupAsk, _.bind(function () {
+ this.noClick();
+ return false;
+ }, this));
+ };
+
+ module.exports = AskPopupView;
+
+ }());
+
+/***/ },
+/* 44 */
+/*!*************************************!*\
+ !*** ./dev/View/Popup/Languages.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function LanguagesPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsLanguages');
+
+ var self = this;
+
+ this.fLang = null;
+ this.userLanguage = ko.observable('');
+
+ this.langs = ko.observableArray([]);
+
+ this.languages = ko.computed(function () {
+ var sUserLanguage = self.userLanguage();
+ return _.map(self.langs(), function (sLanguage) {
+ return {
+ 'key': sLanguage,
+ 'user': sLanguage === sUserLanguage,
+ 'selected': ko.observable(false),
+ 'fullName': Utils.convertLangName(sLanguage)
+ };
+ });
+ });
+
+ this.langs.subscribe(function () {
+ this.setLanguageSelection();
+ }, this);
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/Languages', 'PopupsLanguagesViewModel'], LanguagesPopupView);
+ _.extend(LanguagesPopupView.prototype, AbstractView.prototype);
+
+ LanguagesPopupView.prototype.languageTooltipName = function (sLanguage)
+ {
+ var sResult = Utils.convertLangName(sLanguage, true);
+ return Utils.convertLangName(sLanguage, false) === sResult ? '' : sResult;
+ };
+
+ LanguagesPopupView.prototype.setLanguageSelection = function ()
+ {
+ var sCurrent = this.fLang ? ko.unwrap(this.fLang) : '';
+ _.each(this.languages(), function (oItem) {
+ oItem['selected'](oItem['key'] === sCurrent);
+ });
+ };
+
+ LanguagesPopupView.prototype.onBeforeShow = function ()
+ {
+ this.fLang = null;
+ this.userLanguage('');
+
+ this.langs([]);
+ };
+
+ LanguagesPopupView.prototype.onShow = function (fLanguage, aLangs, sUserLanguage)
+ {
+ this.fLang = fLanguage;
+ this.userLanguage(sUserLanguage || '');
+
+ this.langs(aLangs);
+ };
+
+ LanguagesPopupView.prototype.changeLanguage = function (sLang)
+ {
+ if (this.fLang)
+ {
+ this.fLang(sLang);
+ }
+
+ this.cancelCommand();
+ };
+
+ module.exports = LanguagesPopupView;
+
+ }());
+
+/***/ },
+/* 45 */
+/*!***********************************!*\
+ !*** ./dev/Common/HtmlEditor.jsx ***!
+ \***********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.HtmlEditor = undefined;
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ var _Globals2 = _interopRequireDefault(_Globals);
+
+ var _Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var HtmlEditor = function () {
+
+ /**
+ * @param {Object} element
+ * @param {Function=} onBlur
+ * @param {Function=} onReady
+ * @param {Function=} onModeChange
+ */
+
+ function HtmlEditor(element) {
+ var onBlur = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1];
+ var onReady = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2];
+ var onModeChange = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3];
+
+ _classCallCheck(this, HtmlEditor);
+
+ this.editor = null;
+ this.$element = null;
+ this.blurTimer = 0;
+ this.onBlur = null;
+ this.onReady = null;
+ this.onModeChange = null;
+ this.__inited = null;
+
+ this.onBlur = onBlur;
+ this.onReady = onReady;
+ this.onModeChange = onModeChange;
+
+ this.$element = (0, _common.$)(element);
+
+ this.resize = _common._.throttle(_common._.bind(this.resize, this), 100);
+
+ this.__inited = false;
+
+ this.init();
+ }
+
+ HtmlEditor.prototype.blurTrigger = function blurTrigger() {
+ var _this = this;
+
+ if (this.onBlur) {
+ _common.window.clearTimeout(this.blurTimer);
+ this.blurTimer = _common.window.setTimeout(function () {
+ _this.onBlur();
+ }, 200);
+ }
+ };
+
+ HtmlEditor.prototype.focusTrigger = function focusTrigger() {
+ if (this.onBlur) {
+ _common.window.clearTimeout(this.blurTimer);
+ }
+ };
+
+ /**
+ * @return {boolean}
+ */
+
+
+ HtmlEditor.prototype.isHtml = function isHtml() {
+ return this.editor ? 'wysiwyg' === this.editor.mode : false;
+ };
+
+ /**
+ * @param {string} signature
+ * @param {bool} html
+ * @param {bool} insertBefore
+ */
+
+
+ HtmlEditor.prototype.setSignature = function setSignature(signature, html, insertBefore) {
+ if (this.editor) {
+ this.editor.execCommand('insertSignature', {
+ isHtml: html,
+ insertBefore: insertBefore,
+ signature: signature
+ });
+ }
+ };
+
+ /**
+ * @return {boolean}
+ */
+
+
+ HtmlEditor.prototype.checkDirty = function checkDirty() {
+ return this.editor ? this.editor.checkDirty() : false;
+ };
+
+ HtmlEditor.prototype.resetDirty = function resetDirty() {
+ if (this.editor) {
+ this.editor.resetDirty();
+ }
+ };
+
+ /**
+ * @param {string} text
+ * @return {string}
+ */
+
+
+ HtmlEditor.prototype.clearSignatureSigns = function clearSignatureSigns(text) {
+ return text.replace(/(\u200C|\u0002)/g, '');
+ };
+
+ /**
+ * @param {boolean=} wrapIsHtml = false
+ * @param {boolean=} clearSignatureSigns = false
+ * @return {string}
+ */
+
+
+ HtmlEditor.prototype.getData = function getData() {
+ var wrapIsHtml = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
+ var clearSignatureSigns = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
+
+
+ var result = '';
+ if (this.editor) {
+ try {
+ if ('plain' === this.editor.mode && this.editor.plugins.plain && this.editor.__plain) {
+ result = this.editor.__plain.getRawData();
+ } else {
+ result = wrapIsHtml ? '
' + this.editor.getData() + '
' : this.editor.getData();
+ }
+ } catch (e) {/* eslint-disable-line no-empty */}
+
+ if (clearSignatureSigns) {
+ result = this.clearSignatureSigns(result);
+ }
+ }
+
+ return result;
+ };
+
+ /**
+ * @param {boolean=} wrapIsHtml = false
+ * @param {boolean=} clearSignatureSigns = false
+ * @return {string}
+ */
+
+
+ HtmlEditor.prototype.getDataWithHtmlMark = function getDataWithHtmlMark() {
+ var wrapIsHtml = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
+ var clearSignatureSigns = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
+
+ return (this.isHtml() ? ':HTML:' : '') + this.getData(wrapIsHtml, clearSignatureSigns);
+ };
+
+ HtmlEditor.prototype.modeToggle = function modeToggle(plain, resize) {
+ if (this.editor) {
+ try {
+ if (plain) {
+ if ('plain' === this.editor.mode) {
+ this.editor.setMode('wysiwyg');
+ }
+ } else {
+ if ('wysiwyg' === this.editor.mode) {
+ this.editor.setMode('plain');
+ }
+ }
+ } catch (e) {/* eslint-disable-line no-empty */}
+
+ if (resize) {
+ this.resize();
+ }
+ }
+ };
+
+ HtmlEditor.prototype.setHtmlOrPlain = function setHtmlOrPlain(text, focus) {
+ if (':HTML:' === text.substr(0, 6)) {
+ this.setHtml(text.substr(6), focus);
+ } else {
+ this.setPlain(text, focus);
+ }
+ };
+
+ HtmlEditor.prototype.setHtml = function setHtml(html, focus) {
+ if (this.editor && this.__inited) {
+ this.modeToggle(true);
+
+ html = html.replace(/
]*><\/p>/ig, '');
+
+ try {
+ this.editor.setData(html);
+ } catch (e) {/* eslint-disable-line no-empty */}
+
+ if (focus) {
+ this.focus();
+ }
+ }
+ };
+
+ HtmlEditor.prototype.replaceHtml = function replaceHtml(find, _replaceHtml) {
+ if (this.editor && this.__inited && 'wysiwyg' === this.editor.mode) {
+ try {
+ this.editor.setData(this.editor.getData().replace(find, _replaceHtml));
+ } catch (e) {/* eslint-disable-line no-empty */}
+ }
+ };
+
+ HtmlEditor.prototype.setPlain = function setPlain(plain, focus) {
+ if (this.editor && this.__inited) {
+ this.modeToggle(false);
+ if ('plain' === this.editor.mode && this.editor.plugins.plain && this.editor.__plain) {
+ this.editor.__plain.setRawData(plain);
+ } else {
+ try {
+ this.editor.setData(plain);
+ } catch (e) {/* eslint-disable-line no-empty */}
+ }
+
+ if (focus) {
+ this.focus();
+ }
+ }
+ };
+
+ HtmlEditor.prototype.init = function init() {
+ var _this2 = this;
+
+ if (this.$element && this.$element[0] && !this.editor) {
+ var initFunc = function initFunc() {
+
+ var config = _Globals2.default.oHtmlEditorDefaultConfig,
+ language = _Settings2.default.settingsGet('Language'),
+ allowSource = !!_Settings2.default.appSettingsGet('allowHtmlEditorSourceButton'),
+ biti = !!_Settings2.default.appSettingsGet('allowHtmlEditorBitiButtons');
+
+ if ((allowSource || !biti) && !config.toolbarGroups.__cfgInited) {
+ config.toolbarGroups.__cfgInited = true;
+
+ if (allowSource) {
+ config.removeButtons = config.removeButtons.replace(',Source', '');
+ }
+
+ if (!biti) {
+ config.removePlugins += (config.removePlugins ? ',' : '') + 'bidi';
+ }
+ }
+
+ config.enterMode = _common.window.CKEDITOR.ENTER_BR;
+ config.shiftEnterMode = _common.window.CKEDITOR.ENTER_P;
+
+ config.language = _Globals2.default.oHtmlEditorLangsMap[language] || 'en';
+ if (_common.window.CKEDITOR.env) {
+ _common.window.CKEDITOR.env.isCompatible = true;
+ }
+
+ _this2.editor = _common.window.CKEDITOR.appendTo(_this2.$element[0], config);
+
+ _this2.editor.on('key', function (event) {
+ if (event && event.data && 9 /* Tab */ === event.data.keyCode) {
+ return false;
+ }
+ });
+
+ _this2.editor.on('blur', function () {
+ _this2.blurTrigger();
+ });
+
+ _this2.editor.on('mode', function () {
+ _this2.blurTrigger();
+ if (_this2.onModeChange) {
+ _this2.onModeChange('plain' !== _this2.editor.mode);
+ }
+ });
+
+ _this2.editor.on('focus', function () {
+ _this2.focusTrigger();
+ });
+
+ if (_common.window.FileReader) {
+ _this2.editor.on('drop', function (event) {
+ if (0 < event.data.dataTransfer.getFilesCount()) {
+ var file = event.data.dataTransfer.getFile(0);
+ if (file && _common.window.FileReader && event.data.dataTransfer.id && file.type && file.type.match(/^image/i)) {
+ var id = event.data.dataTransfer.id,
+ imageId = '[img=' + id + ']',
+ reader = new _common.window.FileReader();
+
+ reader.onloadend = function () {
+ if (reader.result) {
+ _this2.replaceHtml(imageId, ' ');
+ }
+ };
+
+ reader.readAsDataURL(file);
+
+ event.data.dataTransfer.setData('text/html', imageId);
+ }
+ }
+ });
+ }
+
+ _this2.editor.on('instanceReady', function () {
+
+ if (_this2.editor.removeMenuItem) {
+ _this2.editor.removeMenuItem('cut');
+ _this2.editor.removeMenuItem('copy');
+ _this2.editor.removeMenuItem('paste');
+ }
+
+ _this2.__resizable = true;
+ _this2.__inited = true;
+
+ _this2.resize();
+
+ if (_this2.onReady) {
+ _this2.onReady();
+ }
+ });
+ };
+
+ if (_common.window.CKEDITOR) {
+ initFunc();
+ } else {
+ _common.window.__initEditor = initFunc;
+ }
+ }
+ };
+
+ HtmlEditor.prototype.focus = function focus() {
+ if (this.editor) {
+ try {
+ this.editor.focus();
+ } catch (e) {/* eslint-disable-line no-empty */}
+ }
+ };
+
+ HtmlEditor.prototype.hasFocus = function hasFocus() {
+ if (this.editor) {
+ try {
+ return !!this.editor.focusManager.hasFocus;
+ } catch (e) {/* eslint-disable-line no-empty */}
+ }
+
+ return false;
+ };
+
+ HtmlEditor.prototype.blur = function blur() {
+ if (this.editor) {
+ try {
+ this.editor.focusManager.blur(true);
+ } catch (e) {/* eslint-disable-line no-empty */}
+ }
+ };
+
+ HtmlEditor.prototype.resize = function resize() {
+ if (this.editor && this.__resizable) {
+ try {
+ this.editor.resize(this.$element.width(), this.$element.innerHeight());
+ } catch (e) {/* eslint-disable-line no-empty */}
+ }
+ };
+
+ HtmlEditor.prototype.setReadOnly = function setReadOnly(value) {
+ if (this.editor) {
+ try {
+ this.editor.setReadOnly(!!value);
+ } catch (e) {/* eslint-disable-line no-empty */}
+ }
+ };
+
+ HtmlEditor.prototype.clear = function clear(focus) {
+ this.setHtml('', focus);
+ };
+
+ return HtmlEditor;
+ }();
+
+ exports.HtmlEditor = HtmlEditor;
+ exports.default = HtmlEditor;
+
+ module.exports = HtmlEditor;
+
+/***/ },
+/* 46 */
+/*!*******************************************!*\
+ !*** ./dev/Component/AbstracCheckbox.jsx ***!
+ \*******************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.AbstracCheckbox = undefined;
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var AbstracCheckbox = function (_AbstractComponent) {
+ _inherits(AbstracCheckbox, _AbstractComponent);
+
+ /**
+ * @param {Object} params = {}
+ */
+
+ function AbstracCheckbox() {
+ var params = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
+
+ _classCallCheck(this, AbstracCheckbox);
+
+ var _this = _possibleConstructorReturn(this, _AbstractComponent.call(this));
+
+ _this.value = params.value;
+ if (_Utils2.default.isUnd(_this.value) || !_this.value.subscribe) {
+ _this.value = _ko2.default.observable(_Utils2.default.isUnd(_this.value) ? false : !!_this.value);
+ }
+
+ _this.enable = params.enable;
+ if (_Utils2.default.isUnd(_this.enable) || !_this.enable.subscribe) {
+ _this.enable = _ko2.default.observable(_Utils2.default.isUnd(_this.enable) ? true : !!_this.enable);
+ }
+
+ _this.disable = params.disable;
+ if (_Utils2.default.isUnd(_this.disable) || !_this.disable.subscribe) {
+ _this.disable = _ko2.default.observable(_Utils2.default.isUnd(_this.disable) ? false : !!_this.disable);
+ }
+
+ _this.label = params.label || '';
+ _this.inline = _Utils2.default.isUnd(params.inline) ? false : params.inline;
+
+ _this.readOnly = _Utils2.default.isUnd(params.readOnly) ? false : !!params.readOnly;
+ _this.inverted = _Utils2.default.isUnd(params.inverted) ? false : !!params.inverted;
+
+ _this.labeled = !_Utils2.default.isUnd(params.label);
+ _this.labelAnimated = !!params.labelAnimated;
+ return _this;
+ }
+
+ AbstracCheckbox.prototype.click = function click() {
+ if (!this.readOnly && this.enable() && !this.disable()) {
+ this.value(!this.value());
+ }
+ };
+
+ return AbstracCheckbox;
+ }(_Abstract.AbstractComponent);
+
+ exports.AbstracCheckbox = AbstracCheckbox;
+ exports.default = AbstracCheckbox;
+
+/***/ },
+/* 47 */
+/*!********************************!*\
+ !*** ./dev/Storage/Client.jsx ***!
+ \********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Cookie = __webpack_require__(/*! Common/ClientStorageDriver/Cookie */ 163);
+
+ var _LocalStorage = __webpack_require__(/*! Common/ClientStorageDriver/LocalStorage */ 164);
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var ClientStorage = function () {
+ function ClientStorage() {
+ _classCallCheck(this, ClientStorage);
+
+ var SupportedStorageDriver = _common._.find([_LocalStorage.LocalStorageDriver, _Cookie.CookieDriver], function (StorageDriver) {
+ return StorageDriver && StorageDriver.supported();
+ });
+ this.driver = SupportedStorageDriver ? new SupportedStorageDriver() : null;
+ }
+
+ /**
+ * @param {number} key
+ * @param {*} data
+ * @return {boolean}
+ */
+
+
+ ClientStorage.prototype.set = function set(key, data) {
+ return this.driver ? this.driver.set('p' + key, data) : false;
+ };
+
+ /**
+ * @param {number} key
+ * @return {*}
+ */
+
+
+ ClientStorage.prototype.get = function get(key) {
+ return this.driver ? this.driver.get('p' + key) : null;
+ };
+
+ return ClientStorage;
+ }();
+
+ module.exports = new ClientStorage();
+
+/***/ },
+/* 48 */
+/*!***************************!*\
+ !*** external "window.Q" ***!
+ \***************************/
+/***/ function(module, exports) {
+
+ module.exports = window.Q;
+
+/***/ },
+/* 49 */
+/*!************************************!*\
+ !*** external "window.crossroads" ***!
+ \************************************/
+/***/ function(module, exports) {
+
+ module.exports = window.crossroads;
+
+/***/ },
+/* 50 */,
+/* 51 */
+/*!************************************!*\
+ !*** ./dev/Stores/User/Contact.js ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function ContactUserStore()
+ {
+ this.contacts = ko.observableArray([]);
+ this.contacts.loading = ko.observable(false).extend({'throttle': 200});
+ this.contacts.importing = ko.observable(false).extend({'throttle': 200});
+ this.contacts.syncing = ko.observable(false).extend({'throttle': 200});
+ this.contacts.exportingVcf = ko.observable(false).extend({'throttle': 200});
+ this.contacts.exportingCsv = ko.observable(false).extend({'throttle': 200});
+
+ this.allowContactsSync = ko.observable(false);
+ this.enableContactsSync = ko.observable(false);
+ this.contactsSyncUrl = ko.observable('');
+ this.contactsSyncUser = ko.observable('');
+ this.contactsSyncPass = ko.observable('');
+ }
+
+ ContactUserStore.prototype.populate = function ()
+ {
+ this.allowContactsSync(!!Settings.settingsGet('ContactsSyncIsAllowed'));
+ this.enableContactsSync(!!Settings.settingsGet('EnableContactsSync'));
+
+ this.contactsSyncUrl(Settings.settingsGet('ContactsSyncUrl'));
+ this.contactsSyncUser(Settings.settingsGet('ContactsSyncUser'));
+ this.contactsSyncPass(Settings.settingsGet('ContactsSyncPassword'));
+ };
+
+ module.exports = new ContactUserStore();
+
+ }());
+
+/***/ },
+/* 52 */
+/*!****************************************!*\
+ !*** ./dev/View/Popup/FolderSystem.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ FolderStore = __webpack_require__(/*! Stores/User/Folder */ 21),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function FolderSystemPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsFolderSystem');
+
+ Translator.initOnStartOrLangChange(function () {
+ this.sChooseOnText = Translator.i18n('POPUPS_SYSTEM_FOLDERS/SELECT_CHOOSE_ONE');
+ this.sUnuseText = Translator.i18n('POPUPS_SYSTEM_FOLDERS/SELECT_UNUSE_NAME');
+ }, this);
+
+ this.notification = ko.observable('');
+
+ this.folderSelectList = ko.computed(function () {
+ return Utils.folderListOptionsBuilder([], FolderStore.folderList(), FolderStore.folderListSystemNames(), [
+ ['', this.sChooseOnText],
+ [Consts.UNUSED_OPTION_VALUE, this.sUnuseText]
+ ], null, null, null, null, null, true);
+ }, this);
+
+ var
+ fSaveSystemFolders = null,
+ fCallback = null
+ ;
+
+ this.sentFolder = FolderStore.sentFolder;
+ this.draftFolder = FolderStore.draftFolder;
+ this.spamFolder = FolderStore.spamFolder;
+ this.trashFolder = FolderStore.trashFolder;
+ this.archiveFolder = FolderStore.archiveFolder;
+
+ fSaveSystemFolders = _.debounce(function () {
+
+ Settings.settingsSet('SentFolder', FolderStore.sentFolder());
+ Settings.settingsSet('DraftFolder', FolderStore.draftFolder());
+ Settings.settingsSet('SpamFolder', FolderStore.spamFolder());
+ Settings.settingsSet('TrashFolder', FolderStore.trashFolder());
+ Settings.settingsSet('ArchiveFolder', FolderStore.archiveFolder());
+
+ Remote.saveSystemFolders(Utils.emptyFunction, {
+ 'SentFolder': FolderStore.sentFolder(),
+ 'DraftFolder': FolderStore.draftFolder(),
+ 'SpamFolder': FolderStore.spamFolder(),
+ 'TrashFolder': FolderStore.trashFolder(),
+ 'ArchiveFolder': FolderStore.archiveFolder(),
+ 'NullFolder': 'NullFolder'
+ });
+
+ }, 1000);
+
+ fCallback = function () {
+
+ Settings.settingsSet('SentFolder', FolderStore.sentFolder());
+ Settings.settingsSet('DraftFolder', FolderStore.draftFolder());
+ Settings.settingsSet('SpamFolder', FolderStore.spamFolder());
+ Settings.settingsSet('TrashFolder', FolderStore.trashFolder());
+ Settings.settingsSet('ArchiveFolder', FolderStore.archiveFolder());
+
+ fSaveSystemFolders();
+ };
+
+ FolderStore.sentFolder.subscribe(fCallback);
+ FolderStore.draftFolder.subscribe(fCallback);
+ FolderStore.spamFolder.subscribe(fCallback);
+ FolderStore.trashFolder.subscribe(fCallback);
+ FolderStore.archiveFolder.subscribe(fCallback);
+
+ this.defautOptionsAfterRender = Utils.defautOptionsAfterRender;
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/FolderSystem', 'PopupsFolderSystemViewModel'], FolderSystemPopupView);
+ _.extend(FolderSystemPopupView.prototype, AbstractView.prototype);
+
+ FolderSystemPopupView.prototype.sChooseOnText = '';
+ FolderSystemPopupView.prototype.sUnuseText = '';
+
+ /**
+ * @param {number=} iNotificationType = Enums.SetSystemFoldersNotification.None
+ */
+ FolderSystemPopupView.prototype.onShow = function (iNotificationType)
+ {
+ var sNotification = '';
+
+ iNotificationType = Utils.isUnd(iNotificationType) ? Enums.SetSystemFoldersNotification.None : iNotificationType;
+
+ switch (iNotificationType)
+ {
+ case Enums.SetSystemFoldersNotification.Sent:
+ sNotification = Translator.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_SENT');
+ break;
+ case Enums.SetSystemFoldersNotification.Draft:
+ sNotification = Translator.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_DRAFTS');
+ break;
+ case Enums.SetSystemFoldersNotification.Spam:
+ sNotification = Translator.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_SPAM');
+ break;
+ case Enums.SetSystemFoldersNotification.Trash:
+ sNotification = Translator.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_TRASH');
+ break;
+ case Enums.SetSystemFoldersNotification.Archive:
+ sNotification = Translator.i18n('POPUPS_SYSTEM_FOLDERS/NOTIFICATION_ARCHIVE');
+ break;
+ }
+
+ this.notification(sNotification);
+ };
+
+ module.exports = FolderSystemPopupView;
+
+ }());
+
+/***/ },
+/* 53 */
+/*!**************************************!*\
+ !*** ./dev/Stores/User/Identity.jsx ***!
+ \**************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var IdentityUserStore = function IdentityUserStore() {
+ var _this = this;
+
+ _classCallCheck(this, IdentityUserStore);
+
+ this.identities = _ko2.default.observableArray([]);
+ this.identities.loading = _ko2.default.observable(false).extend({ throttle: 100 });
+
+ this.identitiesIDS = _ko2.default.computed(function () {
+ return _common._.compact(_common._.map(_this.identities(), function (item) {
+ return item ? item.id : null;
+ }));
+ }, this);
+ };
+
+ module.exports = new IdentityUserStore();
+
+/***/ },
+/* 54 */
+/*!*********************************!*\
+ !*** ./dev/External/Opentip.js ***!
+ \*********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ Opentip = window.Opentip
+ ;
+
+ Opentip.styles.rainloop = {
+
+ 'extends': 'standard',
+
+ 'fixed': true,
+ 'target': true,
+
+ 'delay': 0.2,
+ 'hideDelay': 0,
+
+ 'hideEffect': 'fade',
+ 'hideEffectDuration': 0.2,
+
+ 'showEffect': 'fade',
+ 'showEffectDuration': 0.2,
+
+ 'showOn': 'mouseover click',
+ 'removeElementsOnHide': true,
+
+ 'background': '#fff',
+ 'shadow': false,
+
+ 'borderColor': '#999',
+ 'borderRadius': 2,
+ 'borderWidth': 1
+ };
+
+ Opentip.styles.rainloopTip = {
+ 'extends': 'rainloop',
+ 'delay': 0.4,
+ 'group': 'rainloopTips'
+ };
+
+ Opentip.styles.rainloopErrorTip = {
+ 'extends': 'rainloop',
+ 'className': 'rainloopErrorTip'
+ };
+
+ module.exports = Opentip;
+
+ }());
+
+
+/***/ },
+/* 55 */
+/*!************************************!*\
+ !*** ./dev/Remote/AbstractAjax.js ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Plugins = __webpack_require__(/*! Common/Plugins */ 23),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function AbstractAjaxRemote()
+ {
+ this.oRequests = {};
+ }
+
+ AbstractAjaxRemote.prototype.oRequests = {};
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sRequestAction
+ * @param {string} sType
+ * @param {?AjaxJsonDefaultResponse} oData
+ * @param {boolean} bCached
+ * @param {*=} oRequestParameters
+ */
+ AbstractAjaxRemote.prototype.defaultResponse = function (fCallback, sRequestAction, sType, oData, bCached, oRequestParameters)
+ {
+ var
+ fCall = function () {
+ if (Enums.StorageResultType.Success !== sType && Globals.bUnload)
+ {
+ sType = Enums.StorageResultType.Unload;
+ }
+
+ if (Enums.StorageResultType.Success === sType && oData && !oData.Result)
+ {
+ if (oData && -1 < Utils.inArray(oData.ErrorCode, [
+ Enums.Notification.AuthError, Enums.Notification.AccessError,
+ Enums.Notification.ConnectionError, Enums.Notification.DomainNotAllowed, Enums.Notification.AccountNotAllowed,
+ Enums.Notification.MailServerError, Enums.Notification.UnknownNotification, Enums.Notification.UnknownError
+ ]))
+ {
+ Globals.iAjaxErrorCount++;
+ }
+
+ if (oData && Enums.Notification.InvalidToken === oData.ErrorCode)
+ {
+ Globals.iTokenErrorCount++;
+ }
+
+ if (Consts.TOKEN_ERROR_LIMIT < Globals.iTokenErrorCount)
+ {
+ if (Globals.__APP__ && Globals.__APP__.loginAndLogoutReload)
+ {
+ Globals.__APP__.loginAndLogoutReload(false, true);
+ }
+ }
+
+ if (oData.ClearAuth || oData.Logout || Consts.AJAX_ERROR_LIMIT < Globals.iAjaxErrorCount)
+ {
+ if (Globals.__APP__ && Globals.__APP__.clearClientSideToken)
+ {
+ Globals.__APP__.clearClientSideToken();
+
+ if (!oData.ClearAuth && Globals.__APP__.loginAndLogoutReload)
+ {
+ Globals.__APP__.loginAndLogoutReload(false, true);
+ }
+ }
+ }
+ }
+ else if (Enums.StorageResultType.Success === sType && oData && oData.Result)
+ {
+ Globals.iAjaxErrorCount = 0;
+ Globals.iTokenErrorCount = 0;
+ }
+
+ if (fCallback)
+ {
+ Plugins.runHook('ajax-default-response', [sRequestAction, Enums.StorageResultType.Success === sType ? oData : null, sType, bCached, oRequestParameters]);
+
+ fCallback(
+ sType,
+ Enums.StorageResultType.Success === sType ? oData : null,
+ bCached,
+ sRequestAction,
+ oRequestParameters
+ );
+ }
+ }
+ ;
+
+ switch (sType)
+ {
+ case 'success':
+ sType = Enums.StorageResultType.Success;
+ break;
+ case 'abort':
+ sType = Enums.StorageResultType.Abort;
+ break;
+ default:
+ sType = Enums.StorageResultType.Error;
+ break;
+ }
+
+ if (Enums.StorageResultType.Error === sType)
+ {
+ _.delay(fCall, 300);
+ }
+ else
+ {
+ fCall();
+ }
+ };
+
+ /**
+ * @param {?Function} fResultCallback
+ * @param {Object} oParameters
+ * @param {?number=} iTimeOut = 20000
+ * @param {string=} sGetAdd = ''
+ * @param {Array=} aAbortActions = []
+ * @return {jQuery.jqXHR}
+ */
+ AbstractAjaxRemote.prototype.ajaxRequest = function (fResultCallback, oParameters, iTimeOut, sGetAdd, aAbortActions)
+ {
+ var
+ self = this,
+ bPost = '' === sGetAdd,
+ oHeaders = {},
+ iStart = (new window.Date()).getTime(),
+ oDefAjax = null,
+ sAction = ''
+ ;
+
+ oParameters = oParameters || {};
+ iTimeOut = Utils.isNormal(iTimeOut) ? iTimeOut : 20000;
+ sGetAdd = Utils.isUnd(sGetAdd) ? '' : Utils.pString(sGetAdd);
+ aAbortActions = Utils.isArray(aAbortActions) ? aAbortActions : [];
+
+ sAction = oParameters.Action || '';
+
+ if (sAction && 0 < aAbortActions.length)
+ {
+ _.each(aAbortActions, function (sActionToAbort) {
+ if (self.oRequests[sActionToAbort])
+ {
+ self.oRequests[sActionToAbort].__aborted = true;
+ if (self.oRequests[sActionToAbort].abort)
+ {
+ self.oRequests[sActionToAbort].abort();
+ }
+ self.oRequests[sActionToAbort] = null;
+ }
+ });
+ }
+
+ if (bPost)
+ {
+ oParameters['XToken'] = Settings.appSettingsGet('token');
+ }
+
+ oDefAjax = $.ajax({
+ 'type': bPost ? 'POST' : 'GET',
+ 'url': Links.ajax(sGetAdd),
+ 'async': true,
+ 'dataType': 'json',
+ 'data': bPost ? oParameters : {},
+ 'headers': oHeaders,
+ 'timeout': iTimeOut,
+ 'global': true
+ });
+
+ oDefAjax.always(function (oData, sType) {
+
+ var bCached = false;
+ if (oData && oData['Time'])
+ {
+ bCached = Utils.pInt(oData['Time']) > (new window.Date()).getTime() - iStart;
+ }
+
+ if (sAction && self.oRequests[sAction])
+ {
+ if (self.oRequests[sAction].__aborted)
+ {
+ sType = 'abort';
+ }
+
+ self.oRequests[sAction] = null;
+ }
+
+ self.defaultResponse(fResultCallback, sAction, sType, oData, bCached, oParameters);
+ });
+
+ if (sAction && 0 < aAbortActions.length && -1 < Utils.inArray(sAction, aAbortActions))
+ {
+ if (this.oRequests[sAction])
+ {
+ this.oRequests[sAction].__aborted = true;
+ if (this.oRequests[sAction].abort)
+ {
+ this.oRequests[sAction].abort();
+ }
+ this.oRequests[sAction] = null;
+ }
+
+ this.oRequests[sAction] = oDefAjax;
+ }
+
+ return oDefAjax;
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sAction
+ * @param {Object=} oParameters
+ * @param {?number=} iTimeout
+ * @param {string=} sGetAdd = ''
+ * @param {Array=} aAbortActions = []
+ */
+ AbstractAjaxRemote.prototype.defaultRequest = function (fCallback, sAction, oParameters, iTimeout, sGetAdd, aAbortActions)
+ {
+ oParameters = oParameters || {};
+ oParameters.Action = sAction;
+
+ sGetAdd = Utils.pString(sGetAdd);
+
+ Plugins.runHook('ajax-default-request', [sAction, oParameters, sGetAdd]);
+
+ return this.ajaxRequest(fCallback, oParameters,
+ Utils.isUnd(iTimeout) ? Consts.DEFAULT_AJAX_TIMEOUT : Utils.pInt(iTimeout), sGetAdd, aAbortActions);
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ AbstractAjaxRemote.prototype.noop = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'Noop');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sMessage
+ * @param {string} sFileName
+ * @param {number} iLineNo
+ * @param {string} sLocation
+ * @param {string} sHtmlCapa
+ * @param {number} iTime
+ */
+ AbstractAjaxRemote.prototype.jsError = function (fCallback, sMessage, sFileName, iLineNo, sLocation, sHtmlCapa, iTime)
+ {
+ this.defaultRequest(fCallback, 'JsError', {
+ 'Message': sMessage,
+ 'FileName': sFileName,
+ 'LineNo': iLineNo,
+ 'Location': sLocation,
+ 'HtmlCapa': sHtmlCapa,
+ 'TimeOnPage': iTime
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sType
+ * @param {Array=} mData = null
+ * @param {boolean=} bIsError = false
+ */
+ AbstractAjaxRemote.prototype.jsInfo = function (fCallback, sType, mData, bIsError)
+ {
+ this.defaultRequest(fCallback, 'JsInfo', {
+ 'Type': sType,
+ 'Data': mData,
+ 'IsError': (Utils.isUnd(bIsError) ? false : !!bIsError) ? '1' : '0'
+ });
+ };
+
+ /**
+ * @param {?Function} fCallback
+ */
+ AbstractAjaxRemote.prototype.getPublicKey = function (fCallback)
+ {
+ this.defaultRequest(fCallback, 'GetPublicKey');
+ };
+
+ /**
+ * @param {?Function} fCallback
+ * @param {string} sVersion
+ */
+ AbstractAjaxRemote.prototype.jsVersion = function (fCallback, sVersion)
+ {
+ this.defaultRequest(fCallback, 'Version', {
+ 'Version': sVersion
+ });
+ };
+
+ module.exports = AbstractAjaxRemote;
+
+ }());
+
+/***/ },
+/* 56 */
+/*!****************************************!*\
+ !*** ./dev/Screen/AbstractSettings.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractScreen = __webpack_require__(/*! Knoin/AbstractScreen */ 39)
+ ;
+
+ /**
+ * @constructor
+ * @param {Array} aViewModels
+ * @extends AbstractScreen
+ */
+ function AbstractSettingsScreen(aViewModels)
+ {
+ AbstractScreen.call(this, 'settings', aViewModels);
+
+ this.menu = ko.observableArray([]);
+
+ this.oCurrentSubScreen = null;
+ this.oViewModelPlace = null;
+
+ this.setupSettings();
+ }
+
+ _.extend(AbstractSettingsScreen.prototype, AbstractScreen.prototype);
+
+ /**
+ * @param {Function=} fCallback
+ */
+ AbstractSettingsScreen.prototype.setupSettings = function (fCallback)
+ {
+ if (fCallback)
+ {
+ fCallback();
+ }
+ };
+
+ AbstractSettingsScreen.prototype.onRoute = function (sSubName)
+ {
+ var
+ self = this,
+ oSettingsScreen = null,
+ RoutedSettingsViewModel = null,
+ oViewModelPlace = null,
+ oViewModelDom = null
+ ;
+
+ RoutedSettingsViewModel = _.find(Globals.aViewModels['settings'], function (SettingsViewModel) {
+ return SettingsViewModel && SettingsViewModel.__rlSettingsData &&
+ sSubName === SettingsViewModel.__rlSettingsData.Route;
+ });
+
+ if (RoutedSettingsViewModel)
+ {
+ if (_.find(Globals.aViewModels['settings-removed'], function (DisabledSettingsViewModel) {
+ return DisabledSettingsViewModel && DisabledSettingsViewModel === RoutedSettingsViewModel;
+ }))
+ {
+ RoutedSettingsViewModel = null;
+ }
+
+ if (RoutedSettingsViewModel && _.find(Globals.aViewModels['settings-disabled'], function (DisabledSettingsViewModel) {
+ return DisabledSettingsViewModel && DisabledSettingsViewModel === RoutedSettingsViewModel;
+ }))
+ {
+ RoutedSettingsViewModel = null;
+ }
+ }
+
+ if (RoutedSettingsViewModel)
+ {
+ if (RoutedSettingsViewModel.__builded && RoutedSettingsViewModel.__vm)
+ {
+ oSettingsScreen = RoutedSettingsViewModel.__vm;
+ }
+ else
+ {
+ oViewModelPlace = this.oViewModelPlace;
+ if (oViewModelPlace && 1 === oViewModelPlace.length)
+ {
+ oSettingsScreen = new RoutedSettingsViewModel();
+
+ oViewModelDom = $('
').addClass('rl-settings-view-model').hide();
+ oViewModelDom.appendTo(oViewModelPlace);
+
+ oSettingsScreen.viewModelDom = oViewModelDom;
+
+ oSettingsScreen.__rlSettingsData = RoutedSettingsViewModel.__rlSettingsData;
+
+ RoutedSettingsViewModel.__dom = oViewModelDom;
+ RoutedSettingsViewModel.__builded = true;
+ RoutedSettingsViewModel.__vm = oSettingsScreen;
+
+ ko.applyBindingAccessorsToNode(oViewModelDom[0], {
+ 'translatorInit': true,
+ 'template': function () { return {'name': RoutedSettingsViewModel.__rlSettingsData.Template}; }
+ }, oSettingsScreen);
+
+ Utils.delegateRun(oSettingsScreen, 'onBuild', [oViewModelDom]);
+ }
+ else
+ {
+ Utils.log('Cannot find sub settings view model position: SettingsSubScreen');
+ }
+ }
+
+ if (oSettingsScreen)
+ {
+ _.defer(function () {
+ // hide
+ if (self.oCurrentSubScreen)
+ {
+ Utils.delegateRun(self.oCurrentSubScreen, 'onHide');
+ self.oCurrentSubScreen.viewModelDom.hide();
+ }
+ // --
+
+ self.oCurrentSubScreen = oSettingsScreen;
+
+ // show
+ if (self.oCurrentSubScreen)
+ {
+ Utils.delegateRun(self.oCurrentSubScreen, 'onBeforeShow');
+ self.oCurrentSubScreen.viewModelDom.show();
+ Utils.delegateRun(self.oCurrentSubScreen, 'onShow');
+ Utils.delegateRun(self.oCurrentSubScreen, 'onShowWithDelay', [], 200);
+
+ _.each(self.menu(), function (oItem) {
+ oItem.selected(oSettingsScreen && oSettingsScreen.__rlSettingsData && oItem.route === oSettingsScreen.__rlSettingsData.Route);
+ });
+
+ $('#rl-content .b-settings .b-content .content').scrollTop(0);
+ }
+ // --
+
+ Utils.windowResize();
+ });
+ }
+ }
+ else
+ {
+ kn.setHash(Links.settings(), false, true);
+ }
+ };
+
+ AbstractSettingsScreen.prototype.onHide = function ()
+ {
+ if (this.oCurrentSubScreen && this.oCurrentSubScreen.viewModelDom)
+ {
+ Utils.delegateRun(this.oCurrentSubScreen, 'onHide');
+ this.oCurrentSubScreen.viewModelDom.hide();
+ }
+ };
+
+ AbstractSettingsScreen.prototype.onBuild = function ()
+ {
+ _.each(Globals.aViewModels['settings'], function (SettingsViewModel) {
+ if (SettingsViewModel && SettingsViewModel.__rlSettingsData &&
+ !_.find(Globals.aViewModels['settings-removed'], function (RemoveSettingsViewModel) {
+ return RemoveSettingsViewModel && RemoveSettingsViewModel === SettingsViewModel;
+ }))
+ {
+ this.menu.push({
+ 'route': SettingsViewModel.__rlSettingsData.Route,
+ 'label': SettingsViewModel.__rlSettingsData.Label,
+ 'selected': ko.observable(false),
+ 'disabled': !!_.find(Globals.aViewModels['settings-disabled'], function (DisabledSettingsViewModel) {
+ return DisabledSettingsViewModel && DisabledSettingsViewModel === SettingsViewModel;
+ })
+ });
+ }
+ }, this);
+
+ this.oViewModelPlace = $('#rl-content #rl-settings-subscreen');
+ };
+
+ AbstractSettingsScreen.prototype.routes = function ()
+ {
+ var
+ DefaultViewModel = _.find(Globals.aViewModels['settings'], function (SettingsViewModel) {
+ return SettingsViewModel && SettingsViewModel.__rlSettingsData && SettingsViewModel.__rlSettingsData['IsDefault'];
+ }),
+ sDefaultRoute = DefaultViewModel ? DefaultViewModel.__rlSettingsData['Route'] : 'general',
+ oRules = {
+ 'subname': /^(.*)$/,
+ 'normalize_': function (oRequest, oVals) {
+ oVals.subname = Utils.isUnd(oVals.subname) ? sDefaultRoute : Utils.pString(oVals.subname);
+ return [oVals.subname];
+ }
+ }
+ ;
+
+ return [
+ ['{subname}/', oRules],
+ ['{subname}', oRules],
+ ['', oRules]
+ ];
+ };
+
+ module.exports = AbstractSettingsScreen;
+
+ }());
+
+/***/ },
+/* 57 */,
+/* 58 */,
+/* 59 */,
+/* 60 */
+/*!*****************************************!*\
+ !*** ./dev/Stores/User/Notification.js ***!
+ \*****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Events = __webpack_require__(/*! Common/Events */ 25),
+ Audio = __webpack_require__(/*! Common/Audio */ 65),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9)
+ ;
+
+ /**
+ * @constructor
+ */
+ function NotificationUserStore()
+ {
+ var self = this;
+
+ this.enableSoundNotification = ko.observable(false);
+ this.soundNotificationIsSupported = ko.observable(false);
+
+ this.allowDesktopNotification = ko.observable(false);
+
+ this.desktopNotificationPermissions = ko.computed(function () {
+
+ this.allowDesktopNotification();
+
+ var
+ NotificationClass = this.notificationClass(),
+ iResult = Enums.DesktopNotification.NotSupported
+ ;
+
+ if (NotificationClass && NotificationClass.permission)
+ {
+ switch (NotificationClass.permission.toLowerCase())
+ {
+ case 'granted':
+ iResult = Enums.DesktopNotification.Allowed;
+ break;
+ case 'denied':
+ iResult = Enums.DesktopNotification.Denied;
+ break;
+ case 'default':
+ iResult = Enums.DesktopNotification.NotAllowed;
+ break;
+ }
+ }
+ else if (window.webkitNotifications && window.webkitNotifications.checkPermission)
+ {
+ iResult = window.webkitNotifications.checkPermission();
+ }
+
+ return iResult;
+
+ }, this).extend({'notify': 'always'});
+
+ this.enableDesktopNotification = ko.computed({
+ 'owner': this,
+ 'read': function () {
+ return this.allowDesktopNotification() &&
+ Enums.DesktopNotification.Allowed === this.desktopNotificationPermissions();
+ },
+ 'write': function (bValue) {
+ if (bValue)
+ {
+ var
+ NotificationClass = this.notificationClass(),
+ iPermission = this.desktopNotificationPermissions()
+ ;
+
+ if (NotificationClass && Enums.DesktopNotification.Allowed === iPermission)
+ {
+ this.allowDesktopNotification(true);
+ }
+ else if (NotificationClass && Enums.DesktopNotification.NotAllowed === iPermission)
+ {
+ NotificationClass.requestPermission(function () {
+ self.allowDesktopNotification.valueHasMutated();
+ if (Enums.DesktopNotification.Allowed === self.desktopNotificationPermissions())
+ {
+ if (self.allowDesktopNotification())
+ {
+ self.allowDesktopNotification.valueHasMutated();
+ }
+ else
+ {
+ self.allowDesktopNotification(true);
+ }
+ }
+ else
+ {
+ if (self.allowDesktopNotification())
+ {
+ self.allowDesktopNotification(false);
+ }
+ else
+ {
+ self.allowDesktopNotification.valueHasMutated();
+ }
+ }
+ });
+ }
+ else
+ {
+ this.allowDesktopNotification(false);
+ }
+ }
+ else
+ {
+ this.allowDesktopNotification(false);
+ }
+ }
+ }).extend({'notify': 'always'});
+
+ if (!this.enableDesktopNotification.valueHasMutated)
+ {
+ this.enableDesktopNotification.valueHasMutated = function () {
+ self.allowDesktopNotification.valueHasMutated();
+ };
+ }
+
+ this.computers();
+
+ this.initNotificationPlayer();
+ }
+
+ NotificationUserStore.prototype.computers = function ()
+ {
+ this.isDesktopNotificationSupported = ko.computed(function () {
+ return Enums.DesktopNotification.NotSupported !== this.desktopNotificationPermissions();
+ }, this);
+
+ this.isDesktopNotificationDenied = ko.computed(function () {
+ return Enums.DesktopNotification.NotSupported === this.desktopNotificationPermissions() ||
+ Enums.DesktopNotification.Denied === this.desktopNotificationPermissions();
+ }, this);
+ };
+
+ NotificationUserStore.prototype.initNotificationPlayer = function ()
+ {
+ if (Audio && Audio.supportedNotification)
+ {
+ this.soundNotificationIsSupported(true);
+ }
+ else
+ {
+ this.enableSoundNotification(false);
+ this.soundNotificationIsSupported(false);
+ }
+ };
+
+ NotificationUserStore.prototype.playSoundNotification = function (bSkipSetting)
+ {
+ if (Audio && Audio.supportedNotification && (bSkipSetting ? true : this.enableSoundNotification()))
+ {
+ Audio.playNotification();
+ }
+ };
+
+ NotificationUserStore.prototype.displayDesktopNotification = function (sImageSrc, sTitle, sText, oMessageData)
+ {
+ if (this.enableDesktopNotification())
+ {
+ var
+ NotificationClass = this.notificationClass(),
+ oNotification = NotificationClass ? new NotificationClass(sTitle, {
+ 'body': sText,
+ 'icon': sImageSrc
+ }) : null
+ ;
+
+ if (oNotification)
+ {
+ if (oNotification.show)
+ {
+ oNotification.show();
+ }
+
+ if (oMessageData)
+ {
+ oNotification.onclick = function () {
+
+ window.focus();
+
+ if (oMessageData.Folder && oMessageData.Uid)
+ {
+ Events.pub('mailbox.message.show', [oMessageData.Folder, oMessageData.Uid]);
+ }
+ };
+ }
+
+ window.setTimeout((function (oLocalNotifications) {
+ return function () {
+ if (oLocalNotifications.cancel)
+ {
+ oLocalNotifications.cancel();
+ }
+ else if (oLocalNotifications.close)
+ {
+ oLocalNotifications.close();
+ }
+ };
+ }(oNotification)), 7000);
+ }
+ }
+ };
+
+ NotificationUserStore.prototype.populate = function ()
+ {
+ this.enableSoundNotification(!!Settings.settingsGet('SoundNotification'));
+ this.enableDesktopNotification(!!Settings.settingsGet('DesktopNotifications'));
+ };
+
+ /**
+ * @return {*|null}
+ */
+ NotificationUserStore.prototype.notificationClass = function ()
+ {
+ return window.Notification && window.Notification.requestPermission ? window.Notification : null;
+ };
+
+ module.exports = new NotificationUserStore();
+
+ }());
+
+
+/***/ },
+/* 61 */
+/*!***********************************!*\
+ !*** ./dev/View/Popup/Account.js ***!
+ \***********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function AccountPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsAccount');
+
+ this.isNew = ko.observable(true);
+
+ this.email = ko.observable('');
+ this.password = ko.observable('');
+
+ this.emailError = ko.observable(false);
+ this.passwordError = ko.observable(false);
+
+ this.email.subscribe(function () {
+ this.emailError(false);
+ }, this);
+
+ this.password.subscribe(function () {
+ this.passwordError(false);
+ }, this);
+
+ this.submitRequest = ko.observable(false);
+ this.submitError = ko.observable('');
+ this.submitErrorAdditional = ko.observable('');
+
+ this.emailFocus = ko.observable(false);
+
+ this.addAccountCommand = Utils.createCommand(this, function () {
+
+ this.emailError('' === Utils.trim(this.email()));
+ this.passwordError('' === Utils.trim(this.password()));
+
+ if (this.emailError() || this.passwordError())
+ {
+ return false;
+ }
+
+ this.submitRequest(true);
+
+ Remote.accountSetup(_.bind(function (sResult, oData) {
+
+ this.submitRequest(false);
+ if (Enums.StorageResultType.Success === sResult && oData)
+ {
+ if (oData.Result)
+ {
+ __webpack_require__(/*! App/User */ 7).default.accountsAndIdentities();
+ this.cancelCommand();
+ }
+ else
+ {
+ this.submitError(oData.ErrorCode ? Translator.getNotification(oData.ErrorCode) :
+ Translator.getNotification(Enums.Notification.UnknownError));
+
+ if (oData.ErrorMessageAdditional)
+ {
+ this.submitErrorAdditional(oData.ErrorMessageAdditional);
+ }
+ }
+ }
+ else
+ {
+ this.submitError(Translator.getNotification(Enums.Notification.UnknownError));
+ this.submitErrorAdditional('');
+ }
+
+ }, this), this.email(), this.password(), this.isNew());
+
+ return true;
+
+ }, function () {
+ return !this.submitRequest();
+ });
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/Account', 'View/Popup/AddAccount', 'PopupsAddAccountViewModel'], AccountPopupView);
+ _.extend(AccountPopupView.prototype, AbstractView.prototype);
+
+ AccountPopupView.prototype.clearPopup = function ()
+ {
+ this.isNew(true);
+
+ this.email('');
+ this.password('');
+
+ this.emailError(false);
+ this.passwordError(false);
+
+ this.submitRequest(false);
+ this.submitError('');
+ this.submitErrorAdditional('');
+ };
+
+ AccountPopupView.prototype.onShow = function (oAccount)
+ {
+ this.clearPopup();
+ if (oAccount && oAccount.canBeEdit())
+ {
+ this.isNew(false);
+ this.email(oAccount.email);
+ }
+ };
+
+ AccountPopupView.prototype.onShowWithDelay = function ()
+ {
+ this.emailFocus(true);
+ };
+
+ module.exports = AccountPopupView;
+
+ }());
+
+/***/ },
+/* 62 */
+/*!************************************!*\
+ !*** ./dev/View/Popup/Contacts.js ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+ key = __webpack_require__(/*! key */ 18),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Selector = __webpack_require__(/*! Common/Selector */ 100),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ SettingsStore = __webpack_require__(/*! Stores/User/Settings */ 28),
+ ContactStore = __webpack_require__(/*! Stores/User/Contact */ 51),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15),
+
+ EmailModel = __webpack_require__(/*! Model/Email */ 30),
+ ContactModel = __webpack_require__(/*! Model/Contact */ 103),
+ ContactPropertyModel = __webpack_require__(/*! Model/ContactProperty */ 104),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function ContactsPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsContacts');
+
+ var
+ self = this,
+ fFastClearEmptyListHelper = function (aList) {
+ if (aList && 0 < aList.length) {
+ self.viewProperties.removeAll(aList);
+ Utils.delegateRunOnDestroy(aList);
+ }
+ }
+ ;
+
+ this.bBackToCompose = false;
+ this.sLastComposeFocusedField = '';
+
+ this.allowContactsSync = ContactStore.allowContactsSync;
+ this.enableContactsSync = ContactStore.enableContactsSync;
+ this.allowExport = !Globals.bMobileDevice;
+
+ this.search = ko.observable('');
+ this.contactsCount = ko.observable(0);
+ this.contacts = ContactStore.contacts;
+
+ this.currentContact = ko.observable(null);
+
+ this.importUploaderButton = ko.observable(null);
+
+ this.contactsPage = ko.observable(1);
+ this.contactsPageCount = ko.computed(function () {
+ var iPage = window.Math.ceil(this.contactsCount() / Consts.CONTACTS_PER_PAGE);
+ return 0 >= iPage ? 1 : iPage;
+ }, this);
+
+ this.contactsPagenator = ko.computed(Utils.computedPagenatorHelper(this.contactsPage, this.contactsPageCount));
+
+ this.emptySelection = ko.observable(true);
+ this.viewClearSearch = ko.observable(false);
+
+ this.viewID = ko.observable('');
+ this.viewReadOnly = ko.observable(false);
+ this.viewProperties = ko.observableArray([]);
+
+ this.viewSaveTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.viewPropertiesNames = this.viewProperties.filter(function(oProperty) {
+ return -1 < Utils.inArray(oProperty.type(), [
+ Enums.ContactPropertyType.FirstName, Enums.ContactPropertyType.LastName
+ ]);
+ });
+
+ this.viewPropertiesOther = this.viewProperties.filter(function(oProperty) {
+ return -1 < Utils.inArray(oProperty.type(), [
+ Enums.ContactPropertyType.Note
+ ]);
+ });
+
+ this.viewPropertiesOther = ko.computed(function () {
+
+ var aList = _.filter(this.viewProperties(), function (oProperty) {
+ return -1 < Utils.inArray(oProperty.type(), [
+ Enums.ContactPropertyType.Nick
+ ]);
+ });
+
+ return _.sortBy(aList, function (oProperty) {
+ return oProperty.type();
+ });
+
+ }, this);
+
+ this.viewPropertiesEmails = this.viewProperties.filter(function(oProperty) {
+ return Enums.ContactPropertyType.Email === oProperty.type();
+ });
+
+ this.viewPropertiesWeb = this.viewProperties.filter(function(oProperty) {
+ return Enums.ContactPropertyType.Web === oProperty.type();
+ });
+
+ this.viewHasNonEmptyRequaredProperties = ko.computed(function() {
+
+ var
+ aNames = this.viewPropertiesNames(),
+ aEmail = this.viewPropertiesEmails(),
+ fHelper = function (oProperty) {
+ return '' !== Utils.trim(oProperty.value());
+ }
+ ;
+
+ return !!(_.find(aNames, fHelper) || _.find(aEmail, fHelper));
+ }, this);
+
+ this.viewPropertiesPhones = this.viewProperties.filter(function(oProperty) {
+ return Enums.ContactPropertyType.Phone === oProperty.type();
+ });
+
+ this.viewPropertiesEmailsNonEmpty = this.viewPropertiesNames.filter(function(oProperty) {
+ return '' !== Utils.trim(oProperty.value());
+ });
+
+ this.viewPropertiesEmailsEmptyAndOnFocused = this.viewPropertiesEmails.filter(function(oProperty) {
+ var bF = oProperty.focused();
+ return '' === Utils.trim(oProperty.value()) && !bF;
+ });
+
+ this.viewPropertiesPhonesEmptyAndOnFocused = this.viewPropertiesPhones.filter(function(oProperty) {
+ var bF = oProperty.focused();
+ return '' === Utils.trim(oProperty.value()) && !bF;
+ });
+
+ this.viewPropertiesWebEmptyAndOnFocused = this.viewPropertiesWeb.filter(function(oProperty) {
+ var bF = oProperty.focused();
+ return '' === Utils.trim(oProperty.value()) && !bF;
+ });
+
+ this.viewPropertiesOtherEmptyAndOnFocused = ko.computed(function () {
+ return _.filter(this.viewPropertiesOther(), function (oProperty) {
+ var bF = oProperty.focused();
+ return '' === Utils.trim(oProperty.value()) && !bF;
+ });
+ }, this);
+
+ this.viewPropertiesEmailsEmptyAndOnFocused.subscribe(function(aList) {
+ fFastClearEmptyListHelper(aList);
+ });
+
+ this.viewPropertiesPhonesEmptyAndOnFocused.subscribe(function(aList) {
+ fFastClearEmptyListHelper(aList);
+ });
+
+ this.viewPropertiesWebEmptyAndOnFocused.subscribe(function(aList) {
+ fFastClearEmptyListHelper(aList);
+ });
+
+ this.viewPropertiesOtherEmptyAndOnFocused.subscribe(function(aList) {
+ fFastClearEmptyListHelper(aList);
+ });
+
+ this.viewSaving = ko.observable(false);
+
+ this.useCheckboxesInList = SettingsStore.useCheckboxesInList;
+
+ this.search.subscribe(function () {
+ this.reloadContactList();
+ }, this);
+
+ this.contacts.subscribe(Utils.windowResizeCallback);
+ this.viewProperties.subscribe(Utils.windowResizeCallback);
+
+ this.contactsChecked = ko.computed(function () {
+ return _.filter(this.contacts(), function (oItem) {
+ return oItem.checked();
+ });
+ }, this);
+
+ this.contactsCheckedOrSelected = ko.computed(function () {
+
+ var
+ aChecked = this.contactsChecked(),
+ oSelected = this.currentContact()
+ ;
+
+ return _.union(aChecked, oSelected ? [oSelected] : []);
+
+ }, this);
+
+ this.contactsCheckedOrSelectedUids = ko.computed(function () {
+ return _.map(this.contactsCheckedOrSelected(), function (oContact) {
+ return oContact.idContact;
+ });
+ }, this);
+
+ this.selector = new Selector(this.contacts, this.currentContact, null,
+ '.e-contact-item .actionHandle', '.e-contact-item.selected', '.e-contact-item .checkboxItem',
+ '.e-contact-item.focused');
+
+ this.selector.on('onItemSelect', _.bind(function (oContact) {
+ this.populateViewContact(oContact ? oContact : null);
+ if (!oContact)
+ {
+ this.emptySelection(true);
+ }
+ }, this));
+
+ this.selector.on('onItemGetUid', function (oContact) {
+ return oContact ? oContact.generateUid() : '';
+ });
+
+ this.newCommand = Utils.createCommand(this, function () {
+ this.populateViewContact(null);
+ this.currentContact(null);
+ });
+
+ this.deleteCommand = Utils.createCommand(this, function () {
+ this.deleteSelectedContacts();
+ this.emptySelection(true);
+ }, function () {
+ return 0 < this.contactsCheckedOrSelected().length;
+ });
+
+ this.newMessageCommand = Utils.createCommand(this, function () {
+
+ if (!Settings.capa(Enums.Capa.Composer))
+ {
+ return false;
+ }
+
+ var
+ aE = [],
+ aC = this.contactsCheckedOrSelected(),
+ aToEmails = null,
+ aCcEmails = null,
+ aBccEmails = null
+ ;
+
+ if (Utils.isNonEmptyArray(aC))
+ {
+ aE = _.map(aC, function (oItem) {
+ if (oItem)
+ {
+ var
+ aData = oItem.getNameAndEmailHelper(),
+ oEmail = aData ? new EmailModel(aData[0], aData[1]) : null
+ ;
+
+ if (oEmail && oEmail.validate())
+ {
+ return oEmail;
+ }
+ }
+
+ return null;
+ });
+
+ aE = _.compact(aE);
+ }
+
+ if (Utils.isNonEmptyArray(aE))
+ {
+ self.bBackToCompose = false;
+
+ kn.hideScreenPopup(__webpack_require__(/*! View/Popup/Contacts */ 62));
+
+ switch (self.sLastComposeFocusedField)
+ {
+ default:
+ case 'to':
+ aToEmails = aE;
+ break;
+ case 'cc':
+ aCcEmails = aE;
+ break;
+ case 'bcc':
+ aBccEmails = aE;
+ break;
+ }
+
+ self.sLastComposeFocusedField = '';
+
+ _.delay(function () {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/Compose */ 29),
+ [Enums.ComposeType.Empty, null, aToEmails, aCcEmails, aBccEmails]);
+ }, 200);
+ }
+
+ }, function () {
+ return 0 < this.contactsCheckedOrSelected().length;
+ });
+
+ this.clearCommand = Utils.createCommand(this, function () {
+ this.search('');
+ });
+
+ this.saveCommand = Utils.createCommand(this, function () {
+
+ this.viewSaving(true);
+ this.viewSaveTrigger(Enums.SaveSettingsStep.Animate);
+
+ var
+ sRequestUid = Utils.fakeMd5(),
+ aProperties = []
+ ;
+
+ _.each(this.viewProperties(), function (oItem) {
+ if (oItem.type() && '' !== Utils.trim(oItem.value()))
+ {
+ aProperties.push([oItem.type(), oItem.value(), oItem.typeStr()]);
+ }
+ });
+
+ Remote.contactSave(function (sResult, oData) {
+
+ var bRes = false;
+ self.viewSaving(false);
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result &&
+ oData.Result.RequestUid === sRequestUid && 0 < Utils.pInt(oData.Result.ResultID))
+ {
+ if ('' === self.viewID())
+ {
+ self.viewID(Utils.pInt(oData.Result.ResultID));
+ }
+
+ self.reloadContactList();
+ bRes = true;
+ }
+
+ _.delay(function () {
+ self.viewSaveTrigger(bRes ? Enums.SaveSettingsStep.TrueResult : Enums.SaveSettingsStep.FalseResult);
+ }, 300);
+
+ if (bRes)
+ {
+ self.watchDirty(false);
+
+ _.delay(function () {
+ self.viewSaveTrigger(Enums.SaveSettingsStep.Idle);
+ }, 1000);
+ }
+
+ }, sRequestUid, this.viewID(), aProperties);
+
+ }, function () {
+ var
+ bV = this.viewHasNonEmptyRequaredProperties(),
+ bReadOnly = this.viewReadOnly()
+ ;
+ return !this.viewSaving() && bV && !bReadOnly;
+ });
+
+ this.syncCommand = Utils.createCommand(this, function () {
+
+ var self = this;
+ __webpack_require__(/*! App/User */ 7).default.contactsSync(function (sResult, oData) {
+ if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result)
+ {
+ window.alert(Translator.getNotification(
+ oData && oData.ErrorCode ? oData.ErrorCode : Enums.Notification.ContactsSyncError));
+ }
+
+ self.reloadContactList(true);
+ });
+
+ }, function () {
+ return !this.contacts.syncing() && !this.contacts.importing();
+ });
+
+ this.bDropPageAfterDelete = false;
+
+ this.watchDirty = ko.observable(false);
+ this.watchHash = ko.observable(false);
+
+ this.viewHash = ko.computed(function () {
+ return '' + _.map(self.viewProperties(), function (oItem) {
+ return oItem.value();
+ }).join('');
+ });
+
+ // this.saveCommandDebounce = _.debounce(_.bind(this.saveCommand, this), 1000);
+
+ this.viewHash.subscribe(function () {
+ if (this.watchHash() && !this.viewReadOnly() && !this.watchDirty())
+ {
+ this.watchDirty(true);
+ }
+ }, this);
+
+ this.sDefaultKeyScope = Enums.KeyState.ContactList;
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/Contacts', 'PopupsContactsViewModel'], ContactsPopupView);
+ _.extend(ContactsPopupView.prototype, AbstractView.prototype);
+
+ ContactsPopupView.prototype.getPropertyPlaceholder = function (sType)
+ {
+ var sResult = '';
+ switch (sType)
+ {
+ case Enums.ContactPropertyType.LastName:
+ sResult = 'CONTACTS/PLACEHOLDER_ENTER_LAST_NAME';
+ break;
+ case Enums.ContactPropertyType.FirstName:
+ sResult = 'CONTACTS/PLACEHOLDER_ENTER_FIRST_NAME';
+ break;
+ case Enums.ContactPropertyType.Nick:
+ sResult = 'CONTACTS/PLACEHOLDER_ENTER_NICK_NAME';
+ break;
+ }
+
+ return sResult;
+ };
+
+ ContactsPopupView.prototype.addNewProperty = function (sType, sTypeStr)
+ {
+ this.viewProperties.push(new ContactPropertyModel(sType, sTypeStr || '', '', true, this.getPropertyPlaceholder(sType)));
+ };
+
+ ContactsPopupView.prototype.addNewOrFocusProperty = function (sType, sTypeStr)
+ {
+ var oItem = _.find(this.viewProperties(), function (oItem) {
+ return sType === oItem.type();
+ });
+
+ if (oItem)
+ {
+ oItem.focused(true);
+ }
+ else
+ {
+ this.addNewProperty(sType, sTypeStr);
+ }
+ };
+
+ ContactsPopupView.prototype.addNewEmail = function ()
+ {
+ this.addNewProperty(Enums.ContactPropertyType.Email, 'Home');
+ };
+
+ ContactsPopupView.prototype.addNewPhone = function ()
+ {
+ this.addNewProperty(Enums.ContactPropertyType.Phone, 'Mobile');
+ };
+
+ ContactsPopupView.prototype.addNewWeb = function ()
+ {
+ this.addNewProperty(Enums.ContactPropertyType.Web);
+ };
+
+ ContactsPopupView.prototype.addNewNickname = function ()
+ {
+ this.addNewOrFocusProperty(Enums.ContactPropertyType.Nick);
+ };
+
+ ContactsPopupView.prototype.addNewNotes = function ()
+ {
+ this.addNewOrFocusProperty(Enums.ContactPropertyType.Note);
+ };
+
+ ContactsPopupView.prototype.addNewBirthday = function ()
+ {
+ this.addNewOrFocusProperty(Enums.ContactPropertyType.Birthday);
+ };
+
+ ContactsPopupView.prototype.exportVcf = function ()
+ {
+ __webpack_require__(/*! App/User */ 7).default.download(Links.exportContactsVcf());
+ };
+
+ ContactsPopupView.prototype.exportCsv = function ()
+ {
+ __webpack_require__(/*! App/User */ 7).default.download(Links.exportContactsCsv());
+ };
+
+ ContactsPopupView.prototype.initUploader = function ()
+ {
+ if (this.importUploaderButton())
+ {
+ var
+ oJua = new Jua({
+ 'action': Links.uploadContacts(),
+ 'name': 'uploader',
+ 'queueSize': 1,
+ 'multipleSizeLimit': 1,
+ 'disableDragAndDrop': true,
+ 'disableMultiple': true,
+ 'disableDocumentDropPrevent': true,
+ 'clickElement': this.importUploaderButton()
+ })
+ ;
+
+ if (oJua)
+ {
+ oJua
+ .on('onStart', _.bind(function () {
+ this.contacts.importing(true);
+ }, this))
+ .on('onComplete', _.bind(function (sId, bResult, oData) {
+
+ this.contacts.importing(false);
+ this.reloadContactList();
+
+ if (!sId || !bResult || !oData || !oData.Result)
+ {
+ window.alert(Translator.i18n('CONTACTS/ERROR_IMPORT_FILE'));
+ }
+
+ }, this))
+ ;
+ }
+ }
+ };
+
+ ContactsPopupView.prototype.removeCheckedOrSelectedContactsFromList = function ()
+ {
+ var
+ self = this,
+ oKoContacts = this.contacts,
+ oCurrentContact = this.currentContact(),
+ iCount = this.contacts().length,
+ aContacts = this.contactsCheckedOrSelected()
+ ;
+
+ if (0 < aContacts.length)
+ {
+ _.each(aContacts, function (oContact) {
+
+ if (oCurrentContact && oCurrentContact.idContact === oContact.idContact)
+ {
+ oCurrentContact = null;
+ self.currentContact(null);
+ }
+
+ oContact.deleted(true);
+ iCount--;
+ });
+
+ if (iCount <= 0)
+ {
+ this.bDropPageAfterDelete = true;
+ }
+
+ _.delay(function () {
+
+ _.each(aContacts, function (oContact) {
+ oKoContacts.remove(oContact);
+ Utils.delegateRunOnDestroy(oContact);
+ });
+
+ }, 500);
+ }
+ };
+
+ ContactsPopupView.prototype.deleteSelectedContacts = function ()
+ {
+ if (0 < this.contactsCheckedOrSelected().length)
+ {
+ Remote.contactsDelete(
+ _.bind(this.deleteResponse, this),
+ this.contactsCheckedOrSelectedUids()
+ );
+
+ this.removeCheckedOrSelectedContactsFromList();
+ }
+ };
+
+ /**
+ * @param {string} sResult
+ * @param {AjaxJsonDefaultResponse} oData
+ */
+ ContactsPopupView.prototype.deleteResponse = function (sResult, oData)
+ {
+ if (500 < (Enums.StorageResultType.Success === sResult && oData && oData.Time ? Utils.pInt(oData.Time) : 0))
+ {
+ this.reloadContactList(this.bDropPageAfterDelete);
+ }
+ else
+ {
+ _.delay((function (self) {
+ return function () {
+ self.reloadContactList(self.bDropPageAfterDelete);
+ };
+ }(this)), 500);
+ }
+ };
+
+ ContactsPopupView.prototype.removeProperty = function (oProp)
+ {
+ this.viewProperties.remove(oProp);
+ Utils.delegateRunOnDestroy(oProp);
+ };
+
+ /**
+ * @param {?ContactModel} oContact
+ */
+ ContactsPopupView.prototype.populateViewContact = function (oContact)
+ {
+ var
+ sId = '',
+ sLastName = '',
+ sFirstName = '',
+ aList = []
+ ;
+
+ this.watchHash(false);
+
+ this.emptySelection(false);
+ this.viewReadOnly(false);
+
+ if (oContact)
+ {
+ sId = oContact.idContact;
+ if (Utils.isNonEmptyArray(oContact.properties))
+ {
+ _.each(oContact.properties, function (aProperty) {
+ if (aProperty && aProperty[0])
+ {
+ if (Enums.ContactPropertyType.LastName === aProperty[0])
+ {
+ sLastName = aProperty[1];
+ }
+ else if (Enums.ContactPropertyType.FirstName === aProperty[0])
+ {
+ sFirstName = aProperty[1];
+ }
+ else
+ {
+ aList.push(new ContactPropertyModel(aProperty[0], aProperty[2] || '', aProperty[1]));
+ }
+ }
+ });
+ }
+
+ this.viewReadOnly(!!oContact.readOnly);
+ }
+
+ aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.LastName, '', sLastName, false,
+ this.getPropertyPlaceholder(Enums.ContactPropertyType.LastName)));
+
+ aList.unshift(new ContactPropertyModel(Enums.ContactPropertyType.FirstName, '', sFirstName, !oContact,
+ this.getPropertyPlaceholder(Enums.ContactPropertyType.FirstName)));
+
+ this.viewID(sId);
+
+ Utils.delegateRunOnDestroy(this.viewProperties());
+
+ this.viewProperties([]);
+ this.viewProperties(aList);
+
+ this.watchDirty(false);
+ this.watchHash(true);
+ };
+
+ /**
+ * @param {boolean=} bDropPagePosition = false
+ */
+ ContactsPopupView.prototype.reloadContactList = function (bDropPagePosition)
+ {
+ var
+ self = this,
+ iOffset = (this.contactsPage() - 1) * Consts.CONTACTS_PER_PAGE
+ ;
+
+ this.bDropPageAfterDelete = false;
+
+ if (Utils.isUnd(bDropPagePosition) ? false : !!bDropPagePosition)
+ {
+ this.contactsPage(1);
+ iOffset = 0;
+ }
+
+ this.contacts.loading(true);
+ Remote.contacts(function (sResult, oData) {
+
+ var
+ iCount = 0,
+ aList = []
+ ;
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result && oData.Result.List)
+ {
+ if (Utils.isNonEmptyArray(oData.Result.List))
+ {
+ aList = _.map(oData.Result.List, function (oItem) {
+ var oContact = new ContactModel();
+ return oContact.parse(oItem) ? oContact : null;
+ });
+
+ aList = _.compact(aList);
+
+ iCount = Utils.pInt(oData.Result.Count);
+ iCount = 0 < iCount ? iCount : 0;
+ }
+ }
+
+ self.contactsCount(iCount);
+
+ Utils.delegateRunOnDestroy(self.contacts());
+ self.contacts(aList);
+
+ self.contacts.loading(false);
+ self.viewClearSearch('' !== self.search());
+
+ }, iOffset, Consts.CONTACTS_PER_PAGE, this.search());
+ };
+
+ ContactsPopupView.prototype.onBuild = function (oDom)
+ {
+ this.oContentVisible = $('.b-list-content', oDom);
+ this.oContentScrollable = $('.content', this.oContentVisible);
+
+ this.selector.init(this.oContentVisible, this.oContentScrollable, Enums.KeyState.ContactList);
+
+ var self = this;
+
+ key('delete', Enums.KeyState.ContactList, function () {
+ self.deleteCommand();
+ return false;
+ });
+
+ key('c, w', Enums.KeyState.ContactList, function () {
+ self.newMessageCommand();
+ return false;
+ });
+
+ oDom
+ .on('click', '.e-pagenator .e-page', function () {
+ var oPage = ko.dataFor(this);
+ if (oPage)
+ {
+ self.contactsPage(Utils.pInt(oPage.value));
+ self.reloadContactList();
+ }
+ })
+ ;
+
+ this.initUploader();
+ };
+
+ ContactsPopupView.prototype.onShow = function (bBackToCompose, sLastComposeFocusedField)
+ {
+ this.bBackToCompose = Utils.isUnd(bBackToCompose) ? false : !!bBackToCompose;
+ this.sLastComposeFocusedField = Utils.isUnd(sLastComposeFocusedField) ? '' : sLastComposeFocusedField;
+
+ kn.routeOff();
+ this.reloadContactList(true);
+ };
+
+ ContactsPopupView.prototype.onHide = function ()
+ {
+ kn.routeOn();
+
+ this.currentContact(null);
+ this.emptySelection(true);
+ this.search('');
+ this.contactsCount(0);
+
+ Utils.delegateRunOnDestroy(this.contacts());
+ this.contacts([]);
+
+ this.sLastComposeFocusedField = '';
+
+ if (this.bBackToCompose)
+ {
+ this.bBackToCompose = false;
+
+ if (Settings.capa(Enums.Capa.Composer))
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/Compose */ 29));
+ }
+ }
+ };
+
+ module.exports = ContactsPopupView;
+
+ }());
+
+/***/ },
+/* 63 */
+/*!************************************!*\
+ !*** ./dev/View/Popup/Identity.js ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function IdentityPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsIdentity');
+
+ var self = this;
+
+ this.id = '';
+ this.edit = ko.observable(false);
+ this.owner = ko.observable(false);
+
+ this.email = ko.observable('').validateEmail();
+ this.email.focused = ko.observable(false);
+ this.name = ko.observable('');
+ this.name.focused = ko.observable(false);
+ this.replyTo = ko.observable('').validateSimpleEmail();
+ this.replyTo.focused = ko.observable(false);
+ this.bcc = ko.observable('').validateSimpleEmail();
+ this.bcc.focused = ko.observable(false);
+
+ this.signature = ko.observable('');
+ this.signatureInsertBefore = ko.observable(false);
+
+ this.showBcc = ko.observable(false);
+ this.showReplyTo = ko.observable(false);
+
+ this.submitRequest = ko.observable(false);
+ this.submitError = ko.observable('');
+
+ this.bcc.subscribe(function (aValue) {
+ if (false === self.showBcc() && 0 < aValue.length)
+ {
+ self.showBcc(true);
+ }
+ }, this);
+
+ this.replyTo.subscribe(function (aValue) {
+ if (false === self.showReplyTo() && 0 < aValue.length)
+ {
+ self.showReplyTo(true);
+ }
+ }, this);
+
+ this.addOrEditIdentityCommand = Utils.createCommand(this, function () {
+
+ if (this.signature && this.signature.__fetchEditorValue)
+ {
+ this.signature.__fetchEditorValue();
+ }
+
+ if (!this.email.hasError())
+ {
+ this.email.hasError('' === Utils.trim(this.email()));
+ }
+
+ if (this.email.hasError())
+ {
+ if (!this.owner())
+ {
+ this.email.focused(true);
+ }
+
+ return false;
+ }
+
+ if (this.replyTo.hasError())
+ {
+ this.replyTo.focused(true);
+ return false;
+ }
+
+ if (this.bcc.hasError())
+ {
+ this.bcc.focused(true);
+ return false;
+ }
+
+ this.submitRequest(true);
+
+ Remote.identityUpdate(_.bind(function (sResult, oData) {
+
+ this.submitRequest(false);
+ if (Enums.StorageResultType.Success === sResult && oData)
+ {
+ if (oData.Result)
+ {
+ __webpack_require__(/*! App/User */ 7).default.accountsAndIdentities();
+ this.cancelCommand();
+ }
+ else if (oData.ErrorCode)
+ {
+ this.submitError(Translator.getNotification(oData.ErrorCode));
+ }
+ }
+ else
+ {
+ this.submitError(Translator.getNotification(Enums.Notification.UnknownError));
+ }
+
+ }, this), this.id, this.email(), this.name(), this.replyTo(), this.bcc(),
+ this.signature(), this.signatureInsertBefore());
+
+ return true;
+
+ }, function () {
+ return !this.submitRequest();
+ });
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/Identity', 'PopupsIdentityViewModel'], IdentityPopupView);
+ _.extend(IdentityPopupView.prototype, AbstractView.prototype);
+
+ IdentityPopupView.prototype.clearPopup = function ()
+ {
+ this.id = '';
+ this.edit(false);
+ this.owner(false);
+
+ this.name('');
+ this.email('');
+ this.replyTo('');
+ this.bcc('');
+ this.signature('');
+ this.signatureInsertBefore(false);
+
+ this.email.hasError(false);
+ this.replyTo.hasError(false);
+ this.bcc.hasError(false);
+
+ this.showBcc(false);
+ this.showReplyTo(false);
+
+ this.submitRequest(false);
+ this.submitError('');
+ };
+
+ /**
+ * @param {?IdentityModel} oIdentity
+ */
+ IdentityPopupView.prototype.onShow = function (oIdentity)
+ {
+ this.clearPopup();
+
+ if (oIdentity)
+ {
+ this.edit(true);
+
+ this.id = oIdentity.id() || '';
+ this.name(oIdentity.name());
+ this.email(oIdentity.email());
+ this.replyTo(oIdentity.replyTo());
+ this.bcc(oIdentity.bcc());
+ this.signature(oIdentity.signature());
+ this.signatureInsertBefore(oIdentity.signatureInsertBefore());
+
+ this.owner(this.id === '');
+ }
+ else
+ {
+ this.id = Utils.fakeMd5();
+ }
+ };
+
+ IdentityPopupView.prototype.onShowWithDelay = function ()
+ {
+ if (!this.owner() && !Globals.bMobile)
+ {
+ this.email.focused(true);
+ }
+ };
+
+ IdentityPopupView.prototype.onHideWithDelay = function ()
+ {
+ this.clearPopup();
+ };
+
+ module.exports = IdentityPopupView;
+
+ }());
+
+/***/ },
+/* 64 */
+/*!******************************!*\
+ !*** ./dev/App/Abstract.jsx ***!
+ \******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.AbstractApp = undefined;
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ var _Globals2 = _interopRequireDefault(_Globals);
+
+ var _Enums = __webpack_require__(/*! Common/Enums */ 4);
+
+ var Enums = _interopRequireWildcard(_Enums);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Links = __webpack_require__(/*! Common/Links */ 12);
+
+ var _Links2 = _interopRequireDefault(_Links);
+
+ var _Events = __webpack_require__(/*! Common/Events */ 25);
+
+ var _Events2 = _interopRequireDefault(_Events);
+
+ var _Translator = __webpack_require__(/*! Common/Translator */ 6);
+
+ var _Translator2 = _interopRequireDefault(_Translator);
+
+ var _Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ var _AbstractBoot2 = __webpack_require__(/*! Knoin/AbstractBoot */ 75);
+
+ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var AbstractApp = function (_AbstractBoot) {
+ _inherits(AbstractApp, _AbstractBoot);
+
+ /**
+ * @param {RemoteStorage|AdminRemoteStorage} Remote
+ */
+
+ function AbstractApp(Remote) {
+ _classCallCheck(this, AbstractApp);
+
+ var _this = _possibleConstructorReturn(this, _AbstractBoot.call(this));
+
+ _this.googlePreviewSupportedCache = null;
+ _this.isLocalAutocomplete = true;
+ _this.iframe = null;
+
+
+ _this.iframe = (0, _common.$)('
').appendTo('body');
+
+ _Globals2.default.$win.on('error', function (oEvent) {
+ if (oEvent && oEvent.originalEvent && oEvent.originalEvent.message && -1 === _Utils2.default.inArray(oEvent.originalEvent.message, ['Script error.', 'Uncaught Error: Error calling method on NPObject.'])) {
+ Remote.jsError(_Utils2.default.emptyFunction, oEvent.originalEvent.message, oEvent.originalEvent.filename, oEvent.originalEvent.lineno, _common.window.location && _common.window.location.toString ? _common.window.location.toString() : '', _Globals2.default.$html.attr('class'), _Utils2.default.microtime() - _Globals2.default.startMicrotime);
+ }
+ });
+
+ _Globals2.default.$win.on('resize', function () {
+ _Events2.default.pub('window.resize');
+ });
+
+ _Events2.default.sub('window.resize', _common._.throttle(function () {
+
+ var iH = _Globals2.default.$win.height(),
+ iW = _Globals2.default.$win.height();
+
+ if (_Globals2.default.$win.__sizes[0] !== iH || _Globals2.default.$win.__sizes[1] !== iW) {
+ _Globals2.default.$win.__sizes[0] = iH;
+ _Globals2.default.$win.__sizes[1] = iW;
+
+ _Events2.default.pub('window.resize.real');
+ }
+ }, 50));
+
+ // DEBUG
+ // Events.sub({
+ // 'window.resize': function () {
+ // window.console.log('window.resize');
+ // },
+ // 'window.resize.real': function () {
+ // window.console.log('window.resize.real');
+ // }
+ // });
+
+ _Globals2.default.$doc.on('keydown', function (oEvent) {
+ if (oEvent && oEvent.ctrlKey) {
+ _Globals2.default.$html.addClass('rl-ctrl-key-pressed');
+ }
+ }).on('keyup', function (oEvent) {
+ if (oEvent && !oEvent.ctrlKey) {
+ _Globals2.default.$html.removeClass('rl-ctrl-key-pressed');
+ }
+ });
+
+ _Globals2.default.$doc.on('mousemove keypress click', _common._.debounce(function () {
+ _Events2.default.pub('rl.auto-logout-refresh');
+ }, 5000));
+
+ (0, _common.key)('esc, enter', Enums.KeyState.All, _common._.bind(function () {
+ _Utils2.default.detectDropdownVisibility();
+ }, _this));
+ return _this;
+ }
+
+ AbstractApp.prototype.remote = function remote() {
+ return null;
+ };
+
+ AbstractApp.prototype.data = function data() {
+ return null;
+ };
+
+ AbstractApp.prototype.getApplicationConfiguration = function getApplicationConfiguration(name, default_) {
+ return this.applicationConfiguration[name] || default_;
+ };
+
+ /**
+ * @param {string} link
+ * @return {boolean}
+ */
+
+
+ AbstractApp.prototype.download = function download(link) {
+
+ if (_Globals2.default.sUserAgent && (_Globals2.default.sUserAgent.indexOf('chrome') > -1 || _Globals2.default.sUserAgent.indexOf('chrome') > -1)) {
+ var oLink = _common.window.document.createElement('a');
+ oLink.href = link;
+
+ if (_common.window.document && _common.window.document.createEvent) {
+ var oE = _common.window.document.createEvent.MouseEvents;
+ if (oE && oE.initEvent && oLink.dispatchEvent) {
+ oE.initEvent('click', true, true);
+ oLink.dispatchEvent(oE);
+ return true;
+ }
+ }
+ }
+
+ if (_Globals2.default.bMobileDevice) {
+ _common.window.open(link, '_self');
+ _common.window.focus();
+ } else {
+ this.iframe.attr('src', link);
+ // window.document.location.href = link;
+ }
+
+ return true;
+ };
+
+ /**
+ * @return {boolean}
+ */
+
+
+ AbstractApp.prototype.googlePreviewSupported = function googlePreviewSupported() {
+ if (null === this.googlePreviewSupportedCache) {
+ this.googlePreviewSupportedCache = !!_Settings2.default.settingsGet('AllowGoogleSocial') && !!_Settings2.default.settingsGet('AllowGoogleSocialPreview');
+ }
+
+ return this.googlePreviewSupportedCache;
+ };
+
+ /**
+ * @param {string} title
+ */
+
+
+ AbstractApp.prototype.setWindowTitle = function setWindowTitle(title) {
+ title = _Utils2.default.isNormal(title) && 0 < title.length ? '' + title : '';
+ if (_Settings2.default.settingsGet('Title')) {
+ title += (title ? ' - ' : '') + _Settings2.default.settingsGet('Title');
+ }
+
+ _common.window.document.title = title + ' ...';
+ _common.window.document.title = title;
+ };
+
+ AbstractApp.prototype.redirectToAdminPanel = function redirectToAdminPanel() {
+ _common._.delay(function () {
+ return _common.window.location.href = _Links2.default.rootAdmin();
+ }, 100);
+ };
+
+ AbstractApp.prototype.clearClientSideToken = function clearClientSideToken() {
+ if (_common.window.__rlah_clear) {
+ _common.window.__rlah_clear();
+ }
+ };
+
+ /**
+ * @param {string} token
+ */
+
+
+ AbstractApp.prototype.setClientSideToken = function setClientSideToken(token) {
+ if (_common.window.__rlah_set) {
+ _common.window.__rlah_set(token);
+
+ __webpack_require__(/*! Storage/Settings */ 9).settingsSet('AuthAccountHash', token);
+ __webpack_require__(/*! Common/Links */ 12).populateAuthSuffix();
+ }
+ };
+
+ /**
+ * @param {boolean=} admin = false
+ * @param {boolean=} logout = false
+ * @param {boolean=} close = false
+ */
+
+
+ AbstractApp.prototype.loginAndLogoutReload = function loginAndLogoutReload() {
+ var admin = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
+ var logout = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
+ var close = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2];
+
+
+ var kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ mobile = _Settings2.default.appSettingsGet('mobile'),
+ inIframe = !!_Settings2.default.appSettingsGet('inIframe');
+
+ var customLogoutLink = _Utils2.default.pString(_Settings2.default.appSettingsGet('customLogoutLink'));
+
+ if (logout) {
+ this.clearClientSideToken();
+ }
+
+ if (logout && close && _common.window.close) {
+ _common.window.close();
+ }
+
+ customLogoutLink = customLogoutLink || (admin ? _Links2.default.rootAdmin(mobile) : _Links2.default.rootUser(mobile));
+
+ if (logout && _common.window.location.href !== customLogoutLink) {
+ _common._.delay(function () {
+ if (inIframe && _common.window.parent) {
+ _common.window.parent.location.href = customLogoutLink;
+ } else {
+ _common.window.location.href = customLogoutLink;
+ }
+ }, 100);
+ } else {
+ kn.routeOff();
+ kn.setHash(_Links2.default.root(), true);
+ kn.routeOff();
+
+ _common._.delay(function () {
+ if (inIframe && _common.window.parent) {
+ _common.window.parent.location.reload();
+ } else {
+ _common.window.location.reload();
+ }
+ }, 100);
+ }
+ };
+
+ AbstractApp.prototype.historyBack = function historyBack() {
+ _common.window.history.back();
+ };
+
+ AbstractApp.prototype.bootstart = function bootstart() {
+
+ // Utils.log('Ps' + 'ss, hac' + 'kers! The' + 're\'s not' + 'hing inte' + 'resting :' + ')');
+
+ _Events2.default.pub('rl.bootstart');
+
+ var mobile = _Settings2.default.appSettingsGet('mobile'),
+ ssm = __webpack_require__(/*! ssm */ 84),
+ ko = __webpack_require__(/*! ko */ 2);
+
+ ko.components.register('SaveTrigger', __webpack_require__(/*! Component/SaveTrigger */ 71));
+ ko.components.register('Input', __webpack_require__(/*! Component/Input */ 68));
+ ko.components.register('Select', __webpack_require__(/*! Component/Select */ 73));
+ ko.components.register('Radio', __webpack_require__(/*! Component/Radio */ 70));
+ ko.components.register('TextArea', __webpack_require__(/*! Component/TextArea */ 74));
+
+ ko.components.register('x-script', __webpack_require__(/*! Component/Script */ 72));
+ // ko.components.register('svg-icon', require('Component/SvgIcon'));
+
+ if (_Settings2.default.appSettingsGet('materialDesign') && _Globals2.default.bAnimationSupported) {
+ ko.components.register('Checkbox', __webpack_require__(/*! Component/MaterialDesign/Checkbox */ 69));
+ ko.components.register('CheckboxSimple', __webpack_require__(/*! Component/Checkbox */ 38));
+ } else {
+ // ko.components.register('Checkbox', require('Component/Classic/Checkbox'));
+ // ko.components.register('CheckboxSimple', require('Component/Classic/Checkbox'));
+ ko.components.register('Checkbox', __webpack_require__(/*! Component/Checkbox */ 38));
+ ko.components.register('CheckboxSimple', __webpack_require__(/*! Component/Checkbox */ 38));
+ }
+
+ _Translator2.default.initOnStartOrLangChange(_Translator2.default.initNotificationLanguage, _Translator2.default);
+
+ _common._.delay(_Utils2.default.windowResizeCallback, 1000);
+
+ _Events2.default.sub('ssm.mobile-enter', function () {
+ _Globals2.default.leftPanelDisabled(true);
+ });
+
+ _Events2.default.sub('ssm.mobile-leave', function () {
+ _Globals2.default.leftPanelDisabled(false);
+ });
+
+ if (!mobile) {
+ ssm.addState({
+ id: 'mobile',
+ maxWidth: 767,
+ onEnter: function onEnter() {
+ _Globals2.default.$html.addClass('ssm-state-mobile');
+ _Events2.default.pub('ssm.mobile-enter');
+ },
+ onLeave: function onLeave() {
+ _Globals2.default.$html.removeClass('ssm-state-mobile');
+ _Events2.default.pub('ssm.mobile-leave');
+ }
+ });
+
+ ssm.addState({
+ id: 'tablet',
+ minWidth: 768,
+ maxWidth: 999,
+ onEnter: function onEnter() {
+ _Globals2.default.$html.addClass('ssm-state-tablet');
+ },
+ onLeave: function onLeave() {
+ _Globals2.default.$html.removeClass('ssm-state-tablet');
+ }
+ });
+
+ ssm.addState({
+ id: 'desktop',
+ minWidth: 1000,
+ maxWidth: 1400,
+ onEnter: function onEnter() {
+ _Globals2.default.$html.addClass('ssm-state-desktop');
+ },
+ onLeave: function onLeave() {
+ _Globals2.default.$html.removeClass('ssm-state-desktop');
+ }
+ });
+
+ ssm.addState({
+ id: 'desktop-large',
+ minWidth: 1400,
+ onEnter: function onEnter() {
+ _Globals2.default.$html.addClass('ssm-state-desktop-large');
+ },
+ onLeave: function onLeave() {
+ _Globals2.default.$html.removeClass('ssm-state-desktop-large');
+ }
+ });
+ } else {
+ _Globals2.default.$html.addClass('ssm-state-mobile').addClass('rl-mobile');
+ _Events2.default.pub('ssm.mobile-enter');
+ }
+
+ _Globals2.default.leftPanelDisabled.subscribe(function (bValue) {
+ _Globals2.default.$html.toggleClass('rl-left-panel-disabled', bValue);
+ _Globals2.default.$html.toggleClass('rl-left-panel-enabled', !bValue);
+ });
+
+ _Globals2.default.leftPanelType.subscribe(function (sValue) {
+ _Globals2.default.$html.toggleClass('rl-left-panel-none', 'none' === sValue);
+ _Globals2.default.$html.toggleClass('rl-left-panel-short', 'short' === sValue);
+ });
+
+ _Globals2.default.leftPanelDisabled.valueHasMutated();
+
+ ssm.ready();
+
+ __webpack_require__(/*! Stores/Language */ 40).populate();
+ __webpack_require__(/*! Stores/Theme */ 42).populate();
+ __webpack_require__(/*! Stores/Social */ 34).populate();
+ };
+
+ return AbstractApp;
+ }(_AbstractBoot2.AbstractBoot);
+
+ exports.AbstractApp = AbstractApp;
+ exports.default = AbstractApp;
+
+/***/ },
+/* 65 */
+/*!******************************!*\
+ !*** ./dev/Common/Audio.jsx ***!
+ \******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ var _Globals2 = _interopRequireDefault(_Globals);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Links = __webpack_require__(/*! Common/Links */ 12);
+
+ var _Links2 = _interopRequireDefault(_Links);
+
+ var _Events = __webpack_require__(/*! Common/Events */ 25);
+
+ var _Events2 = _interopRequireDefault(_Events);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var Audio = function () {
+ function Audio() {
+ var _this = this;
+
+ _classCallCheck(this, Audio);
+
+ this.player = null;
+ this.notificator = null;
+ this.supported = false;
+ this.supportedMp3 = false;
+ this.supportedOgg = false;
+ this.supportedWav = false;
+ this.supportedNotification = false;
+
+ this.player = this.createNewObject();
+
+ this.supported = !_Globals2.default.bMobileDevice && !_Globals2.default.bSafari && !!this.player && !!this.player.play;
+ if (this.supported && this.player.canPlayType) {
+ this.supportedMp3 = '' !== this.player.canPlayType('audio/mpeg;').replace(/no/, '');
+ this.supportedWav = '' !== this.player.canPlayType('audio/wav; codecs="1"').replace(/no/, '');
+ this.supportedOgg = '' !== this.player.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, '');
+ this.supportedNotification = this.supported && this.supportedMp3;
+ }
+
+ if (!this.player || !this.supportedMp3 && !this.supportedOgg && !this.supportedWav) {
+ this.supported = false;
+ this.supportedMp3 = false;
+ this.supportedOgg = false;
+ this.supportedWav = false;
+ this.supportedNotification = false;
+ }
+
+ if (this.supported) {
+ (0, _common.$)(this.player).on('ended error', function () {
+ return _this.stop();
+ });
+
+ _Events2.default.sub('audio.api.stop', function () {
+ return _this.stop();
+ });
+ }
+ }
+
+ Audio.prototype.createNewObject = function createNewObject() {
+ var player = _common.window.Audio ? new _common.window.Audio() : null;
+ if (player && player.canPlayType && player.pause && player.play) {
+ player.preload = 'none';
+ player.loop = false;
+ player.autoplay = false;
+ player.muted = false;
+ }
+
+ return player;
+ };
+
+ Audio.prototype.paused = function paused() {
+ return this.supported ? !!this.player.paused : true;
+ };
+
+ Audio.prototype.stop = function stop() {
+ if (this.supported && this.player.pause) {
+ this.player.pause();
+ }
+
+ _Events2.default.pub('audio.stop');
+ };
+
+ Audio.prototype.pause = function pause() {
+ this.stop();
+ };
+
+ Audio.prototype.clearName = function clearName() {
+ var name = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
+ var ext = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1];
+
+
+ name = _Utils2.default.trim(name);
+ if (ext && '.' + ext === name.toLowerCase().substr((ext.length + 1) * -1)) {
+ name = _Utils2.default.trim(name.substr(0, name.length - 4));
+ }
+
+ return '' === name ? 'audio' : name;
+ };
+
+ Audio.prototype.playMp3 = function playMp3(url, name) {
+ if (this.supported && this.supportedMp3) {
+ this.player.src = url;
+ this.player.play();
+
+ _Events2.default.pub('audio.start', [this.clearName(name, 'mp3'), 'mp3']);
+ }
+ };
+
+ Audio.prototype.playOgg = function playOgg(url, name) {
+ if (this.supported && this.supportedOgg) {
+ this.player.src = url;
+ this.player.play();
+
+ name = this.clearName(name, 'oga');
+ name = this.clearName(name, 'ogg');
+
+ _Events2.default.pub('audio.start', [name, 'ogg']);
+ }
+ };
+
+ Audio.prototype.playWav = function playWav(url, name) {
+ if (this.supported && this.supportedWav) {
+ this.player.src = url;
+ this.player.play();
+
+ _Events2.default.pub('audio.start', [this.clearName(name, 'wav'), 'wav']);
+ }
+ };
+
+ Audio.prototype.playNotification = function playNotification() {
+ if (this.supported && this.supportedMp3) {
+ if (!this.notificator) {
+ this.notificator = this.createNewObject();
+ this.notificator.src = _Links2.default.sound('new-mail.mp3');
+ }
+
+ if (this.notificator && this.notificator.play) {
+ this.notificator.play();
+ }
+ }
+ };
+
+ return Audio;
+ }();
+
+ module.exports = new Audio();
+
+/***/ },
+/* 66 */
+/*!*****************************!*\
+ !*** ./dev/Common/Mime.jsx ***!
+ \*****************************/
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ /* eslint key-spacing: 0 */
+ /* eslint quote-props: 0 */
+
+ module.exports = {
+ 'eml': 'message/rfc822',
+ 'mime': 'message/rfc822',
+ 'txt': 'text/plain',
+ 'text': 'text/plain',
+ 'def': 'text/plain',
+ 'list': 'text/plain',
+ 'in': 'text/plain',
+ 'ini': 'text/plain',
+ 'log': 'text/plain',
+ 'sql': 'text/plain',
+ 'cfg': 'text/plain',
+ 'conf': 'text/plain',
+ 'asc': 'text/plain',
+ 'rtx': 'text/richtext',
+ 'vcard': 'text/vcard',
+ 'vcf': 'text/vcard',
+ 'htm': 'text/html',
+ 'html': 'text/html',
+ 'csv': 'text/csv',
+ 'ics': 'text/calendar',
+ 'ifb': 'text/calendar',
+ 'xml': 'text/xml',
+ 'json': 'application/json',
+ 'swf': 'application/x-shockwave-flash',
+ 'hlp': 'application/winhlp',
+ 'wgt': 'application/widget',
+ 'chm': 'application/vnd.ms-htmlhelp',
+ 'p10': 'application/pkcs10',
+ 'p7c': 'application/pkcs7-mime',
+ 'p7m': 'application/pkcs7-mime',
+ 'p7s': 'application/pkcs7-signature',
+ 'torrent': 'application/x-bittorrent',
+
+ // scripts
+ 'js': 'application/javascript',
+ 'pl': 'text/perl',
+ 'css': 'text/css',
+ 'asp': 'text/asp',
+ 'php': 'application/x-httpd-php',
+ 'php3': 'application/x-httpd-php',
+ 'php4': 'application/x-httpd-php',
+ 'php5': 'application/x-httpd-php',
+ 'phtml': 'application/x-httpd-php',
+
+ // images
+ 'png': 'image/png',
+ 'jpg': 'image/jpeg',
+ 'jpeg': 'image/jpeg',
+ 'jpe': 'image/jpeg',
+ 'jfif': 'image/jpeg',
+ 'gif': 'image/gif',
+ 'bmp': 'image/bmp',
+ 'cgm': 'image/cgm',
+ 'ief': 'image/ief',
+ 'ico': 'image/x-icon',
+ 'tif': 'image/tiff',
+ 'tiff': 'image/tiff',
+ 'svg': 'image/svg+xml',
+ 'svgz': 'image/svg+xml',
+ 'djv': 'image/vnd.djvu',
+ 'djvu': 'image/vnd.djvu',
+ 'webp': 'image/webp',
+
+ // archives
+ 'zip': 'application/zip',
+ '7z': 'application/x-7z-compressed',
+ 'rar': 'application/x-rar-compressed',
+ 'exe': 'application/x-msdownload',
+ 'dll': 'application/x-msdownload',
+ 'scr': 'application/x-msdownload',
+ 'com': 'application/x-msdownload',
+ 'bat': 'application/x-msdownload',
+ 'msi': 'application/x-msdownload',
+ 'cab': 'application/vnd.ms-cab-compressed',
+ 'gz': 'application/x-gzip',
+ 'tgz': 'application/x-gzip',
+ 'bz': 'application/x-bzip',
+ 'bz2': 'application/x-bzip2',
+ 'deb': 'application/x-debian-package',
+
+ // fonts
+ 'psf': 'application/x-font-linux-psf',
+ 'otf': 'application/x-font-otf',
+ 'pcf': 'application/x-font-pcf',
+ 'snf': 'application/x-font-snf',
+ 'ttf': 'application/x-font-ttf',
+ 'ttc': 'application/x-font-ttf',
+
+ // audio
+ 'mp3': 'audio/mpeg',
+ 'amr': 'audio/amr',
+ 'aac': 'audio/x-aac',
+ 'aif': 'audio/x-aiff',
+ 'aifc': 'audio/x-aiff',
+ 'aiff': 'audio/x-aiff',
+ 'wav': 'audio/x-wav',
+ 'wma': 'audio/x-ms-wma',
+ 'wax': 'audio/x-ms-wax',
+ 'midi': 'audio/midi',
+ 'mp4a': 'audio/mp4',
+ 'ogg': 'audio/ogg',
+ 'weba': 'audio/webm',
+ 'ra': 'audio/x-pn-realaudio',
+ 'ram': 'audio/x-pn-realaudio',
+ 'rmp': 'audio/x-pn-realaudio-plugin',
+ 'm3u': 'audio/x-mpegurl',
+
+ // video
+ 'flv': 'video/x-flv',
+ 'qt': 'video/quicktime',
+ 'mov': 'video/quicktime',
+ 'wmv': 'video/windows-media',
+ 'avi': 'video/x-msvideo',
+ 'mpg': 'video/mpeg',
+ 'mpeg': 'video/mpeg',
+ 'mpe': 'video/mpeg',
+ 'm1v': 'video/mpeg',
+ 'm2v': 'video/mpeg',
+ '3gp': 'video/3gpp',
+ '3g2': 'video/3gpp2',
+ 'h261': 'video/h261',
+ 'h263': 'video/h263',
+ 'h264': 'video/h264',
+ 'jpgv': 'video/jpgv',
+ 'mp4': 'video/mp4',
+ 'mp4v': 'video/mp4',
+ 'mpg4': 'video/mp4',
+ 'ogv': 'video/ogg',
+ 'webm': 'video/webm',
+ 'm4v': 'video/x-m4v',
+ 'asf': 'video/x-ms-asf',
+ 'asx': 'video/x-ms-asf',
+ 'wm': 'video/x-ms-wm',
+ 'wmx': 'video/x-ms-wmx',
+ 'wvx': 'video/x-ms-wvx',
+ 'movie': 'video/x-sgi-movie',
+
+ // adobe
+ 'pdf': 'application/pdf',
+ 'psd': 'image/vnd.adobe.photoshop',
+ 'ai': 'application/postscript',
+ 'eps': 'application/postscript',
+ 'ps': 'application/postscript',
+
+ // ms office
+ 'doc': 'application/msword',
+ 'dot': 'application/msword',
+ 'rtf': 'application/rtf',
+ 'xls': 'application/vnd.ms-excel',
+ 'ppt': 'application/vnd.ms-powerpoint',
+ 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'dotx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+ 'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+
+ // open office
+ 'odt': 'application/vnd.oasis.opendocument.text',
+ 'ods': 'application/vnd.oasis.opendocument.spreadsheet'
+ };
+
+/***/ },
+/* 67 */
+/*!****************************************!*\
+ !*** ./dev/Component/AbstracRadio.jsx ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.AbstracRadio = undefined;
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var AbstracRadio = function (_AbstractComponent) {
+ _inherits(AbstracRadio, _AbstractComponent);
+
+ /**
+ * @param {Object} params
+ */
+
+ function AbstracRadio(params) {
+ _classCallCheck(this, AbstracRadio);
+
+ var _this = _possibleConstructorReturn(this, _AbstractComponent.call(this));
+
+ _this.values = _ko2.default.observableArray([]);
+
+ _this.value = params.value;
+ if (_Utils2.default.isUnd(_this.value) || !_this.value.subscribe) {
+ _this.value = _ko2.default.observable('');
+ }
+
+ _this.inline = _Utils2.default.isUnd(params.inline) ? false : params.inline;
+ _this.readOnly = _Utils2.default.isUnd(params.readOnly) ? false : !!params.readOnly;
+
+ if (params.values) {
+ _this.values(_common._.map(params.values, function (label, value) {
+ return { label: label, value: value };
+ }));
+ }
+
+ _this.click = _common._.bind(_this.click, _this);
+ return _this;
+ }
+
+ AbstracRadio.prototype.click = function click(value) {
+ if (!this.readOnly && value) {
+ this.value(value.value);
+ }
+ };
+
+ return AbstracRadio;
+ }(_Abstract.AbstractComponent);
+
+ exports.AbstracRadio = AbstracRadio;
+ exports.default = AbstracRadio;
+
+/***/ },
+/* 68 */
+/*!*********************************!*\
+ !*** ./dev/Component/Input.jsx ***!
+ \*********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ var _AbstractInput2 = __webpack_require__(/*! Component/AbstractInput */ 37);
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var InputComponent = function (_AbstractInput) {
+ _inherits(InputComponent, _AbstractInput);
+
+ function InputComponent() {
+ _classCallCheck(this, InputComponent);
+
+ return _possibleConstructorReturn(this, _AbstractInput.apply(this, arguments));
+ }
+
+ return InputComponent;
+ }(_AbstractInput2.AbstractInput);
+
+ module.exports = (0, _Abstract.componentExportHelper)(InputComponent, 'InputComponent');
+
+/***/ },
+/* 69 */
+/*!***************************************************!*\
+ !*** ./dev/Component/MaterialDesign/Checkbox.jsx ***!
+ \***************************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ var _AbstracCheckbox2 = __webpack_require__(/*! Component/AbstracCheckbox */ 46);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var CheckboxMaterialDesignComponent = function (_AbstracCheckbox) {
+ _inherits(CheckboxMaterialDesignComponent, _AbstracCheckbox);
+
+ /**
+ * @param {Object} params
+ */
+
+ function CheckboxMaterialDesignComponent(params) {
+ _classCallCheck(this, CheckboxMaterialDesignComponent);
+
+ var _this = _possibleConstructorReturn(this, _AbstracCheckbox.call(this, params));
+
+ _this.animationBox = _ko2.default.observable(false).extend({ falseTimeout: 200 });
+ _this.animationCheckmark = _ko2.default.observable(false).extend({ falseTimeout: 200 });
+
+ _this.animationBoxSetTrue = _common._.bind(_this.animationBoxSetTrue, _this);
+ _this.animationCheckmarkSetTrue = _common._.bind(_this.animationCheckmarkSetTrue, _this);
+
+ _this.disposable.push(_this.value.subscribe(function (value) {
+ _this.triggerAnimation(value);
+ }, _this));
+ return _this;
+ }
+
+ CheckboxMaterialDesignComponent.prototype.animationBoxSetTrue = function animationBoxSetTrue() {
+ this.animationBox(true);
+ };
+
+ CheckboxMaterialDesignComponent.prototype.animationCheckmarkSetTrue = function animationCheckmarkSetTrue() {
+ this.animationCheckmark(true);
+ };
+
+ CheckboxMaterialDesignComponent.prototype.triggerAnimation = function triggerAnimation(box) {
+ if (box) {
+ this.animationBoxSetTrue();
+ _common._.delay(this.animationCheckmarkSetTrue, 200);
+ } else {
+ this.animationCheckmarkSetTrue();
+ _common._.delay(this.animationBoxSetTrue, 200);
+ }
+ };
+
+ return CheckboxMaterialDesignComponent;
+ }(_AbstracCheckbox2.AbstracCheckbox);
+
+ module.exports = (0, _Abstract.componentExportHelper)(CheckboxMaterialDesignComponent, 'CheckboxMaterialDesignComponent');
+
+/***/ },
+/* 70 */
+/*!*********************************!*\
+ !*** ./dev/Component/Radio.jsx ***!
+ \*********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ var _AbstracRadio2 = __webpack_require__(/*! Component/AbstracRadio */ 67);
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var RadioComponent = function (_AbstracRadio) {
+ _inherits(RadioComponent, _AbstracRadio);
+
+ function RadioComponent() {
+ _classCallCheck(this, RadioComponent);
+
+ return _possibleConstructorReturn(this, _AbstracRadio.apply(this, arguments));
+ }
+
+ return RadioComponent;
+ }(_AbstracRadio2.AbstracRadio);
+
+ module.exports = (0, _Abstract.componentExportHelper)(RadioComponent, 'RadioComponent');
+
+/***/ },
+/* 71 */
+/*!***************************************!*\
+ !*** ./dev/Component/SaveTrigger.jsx ***!
+ \***************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Enums = __webpack_require__(/*! Common/Enums */ 4);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var SaveTriggerComponent = function (_AbstractComponent) {
+ _inherits(SaveTriggerComponent, _AbstractComponent);
+
+ /**
+ * @param {Object} params
+ */
+
+ function SaveTriggerComponent(params) {
+ _classCallCheck(this, SaveTriggerComponent);
+
+ var _this = _possibleConstructorReturn(this, _AbstractComponent.call(this));
+
+ _this.element = params.element || null;
+ _this.value = params.value && params.value.subscribe ? params.value : null;
+
+ if (_this.element) {
+ if (_this.value) {
+ _this.element.css('display', 'inline-block');
+
+ if (params.verticalAlign) {
+ _this.element.css('vertical-align', params.verticalAlign);
+ }
+
+ _this.setState(_this.value());
+
+ _this.disposable.push(_this.value.subscribe(_this.setState, _this));
+ } else {
+ _this.element.hide();
+ }
+ }
+ return _this;
+ }
+
+ SaveTriggerComponent.prototype.setState = function setState(value) {
+
+ switch (_Utils2.default.pInt(value)) {
+ case _Enums.SaveSettingsStep.TrueResult:
+ this.element.find('.animated,.error').hide().removeClass('visible').end().find('.success').show().addClass('visible');
+ break;
+ case _Enums.SaveSettingsStep.FalseResult:
+ this.element.find('.animated,.success').hide().removeClass('visible').end().find('.error').show().addClass('visible');
+ break;
+ case _Enums.SaveSettingsStep.Animate:
+ this.element.find('.error,.success').hide().removeClass('visible').end().find('.animated').show().addClass('visible');
+ break;
+ default:
+ case _Enums.SaveSettingsStep.Idle:
+ this.element.find('.animated').hide().end().find('.error,.success').removeClass('visible');
+ break;
+ }
+ };
+
+ return SaveTriggerComponent;
+ }(_Abstract.AbstractComponent);
+
+ module.exports = (0, _Abstract.componentExportHelper)(SaveTriggerComponent, 'SaveTriggerComponent');
+
+/***/ },
+/* 72 */
+/*!**********************************!*\
+ !*** ./dev/Component/Script.jsx ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var ScriptComponent = function (_AbstractComponent) {
+ _inherits(ScriptComponent, _AbstractComponent);
+
+ /**
+ * @param {Object} params
+ */
+
+ function ScriptComponent(params) {
+ _classCallCheck(this, ScriptComponent);
+
+ var _this = _possibleConstructorReturn(this, _AbstractComponent.call(this));
+
+ if (params.component && params.component.templateNodes && params.element && params.element[0] && params.element[0].outerHTML) {
+ var script = params.element[0].outerHTML;
+ script = !script ? '' : script.replace(/
<\/b><\/x-script>/i, '');
+
+ if (script) {
+ params.element.text('');
+ params.element.replaceWith((0, _common.$)(script).text(params.component.templateNodes[0] && params.component.templateNodes[0].nodeValue ? params.component.templateNodes[0].nodeValue : ''));
+ } else {
+ params.element.remove();
+ }
+ }
+ return _this;
+ }
+
+ return ScriptComponent;
+ }(_Abstract.AbstractComponent);
+
+ module.exports = (0, _Abstract.componentExportHelper)(ScriptComponent, 'ScriptComponent');
+
+/***/ },
+/* 73 */
+/*!**********************************!*\
+ !*** ./dev/Component/Select.jsx ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Translator = __webpack_require__(/*! Common/Translator */ 6);
+
+ var _Translator2 = _interopRequireDefault(_Translator);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ var _AbstractInput2 = __webpack_require__(/*! Component/AbstractInput */ 37);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var SelectComponent = function (_AbstractInput) {
+ _inherits(SelectComponent, _AbstractInput);
+
+ /**
+ * @param {Object} params
+ */
+
+ function SelectComponent(params) {
+ _classCallCheck(this, SelectComponent);
+
+ var _this = _possibleConstructorReturn(this, _AbstractInput.call(this, params));
+
+ _this.options = params.options || '';
+
+ _this.optionsText = params.optionsText || null;
+ _this.optionsValue = params.optionsValue || null;
+ _this.optionsCaption = params.optionsCaption || null;
+
+ if (_this.optionsCaption) {
+ _this.optionsCaption = _Translator2.default.i18n(_this.optionsCaption);
+ }
+
+ _this.defautOptionsAfterRender = _Utils2.default.defautOptionsAfterRender;
+ return _this;
+ }
+
+ return SelectComponent;
+ }(_AbstractInput2.AbstractInput);
+
+ module.exports = (0, _Abstract.componentExportHelper)(SelectComponent, 'SelectComponent');
+
+/***/ },
+/* 74 */
+/*!************************************!*\
+ !*** ./dev/Component/TextArea.jsx ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Abstract = __webpack_require__(/*! Component/Abstract */ 16);
+
+ var _AbstractInput2 = __webpack_require__(/*! Component/AbstractInput */ 37);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var TextAreaComponent = function (_AbstractInput) {
+ _inherits(TextAreaComponent, _AbstractInput);
+
+ /**
+ * @param {Object} params
+ */
+
+ function TextAreaComponent(params) {
+ _classCallCheck(this, TextAreaComponent);
+
+ var _this = _possibleConstructorReturn(this, _AbstractInput.call(this, params));
+
+ _this.rows = params.rows || 5;
+ _this.spellcheck = _Utils2.default.isUnd(params.spellcheck) ? false : !!params.spellcheck;
+ return _this;
+ }
+
+ return TextAreaComponent;
+ }(_AbstractInput2.AbstractInput);
+
+ module.exports = (0, _Abstract.componentExportHelper)(TextAreaComponent, 'TextAreaComponent');
+
+/***/ },
+/* 75 */
+/*!************************************!*\
+ !*** ./dev/Knoin/AbstractBoot.jsx ***!
+ \************************************/
+/***/ function(module, exports) {
+
+ "use strict";
+
+ exports.__esModule = true;
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var AbstractBoot = function () {
+ function AbstractBoot() {
+ _classCallCheck(this, AbstractBoot);
+ }
+
+ AbstractBoot.prototype.bootstart = function bootstart() {
+ // eslint-disable-line no-empty
+ };
+
+ return AbstractBoot;
+ }();
+
+ exports.AbstractBoot = AbstractBoot;
+ exports.default = AbstractBoot;
+
+/***/ },
+/* 76 */
+/*!************************************!*\
+ !*** ./dev/Stores/AbstractApp.jsx ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.AbstractAppStore = undefined;
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Globals = __webpack_require__(/*! Common/Globals */ 8);
+
+ var _Globals2 = _interopRequireDefault(_Globals);
+
+ var _Settings = __webpack_require__(/*! Storage/Settings */ 9);
+
+ var _Settings2 = _interopRequireDefault(_Settings);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var AbstractAppStore = function () {
+ function AbstractAppStore() {
+ _classCallCheck(this, AbstractAppStore);
+
+ this.allowLanguagesOnSettings = _ko2.default.observable(true);
+ this.allowLanguagesOnLogin = _ko2.default.observable(true);
+
+ this.interfaceAnimation = _ko2.default.observable(true);
+
+ this.interfaceAnimation.subscribe(function (bValue) {
+ var bAnim = _Globals2.default.bMobileDevice || !bValue;
+ _Globals2.default.$html.toggleClass('rl-anim', !bAnim).toggleClass('no-rl-anim', bAnim);
+ });
+
+ this.interfaceAnimation.valueHasMutated();
+
+ this.prem = _ko2.default.observable(false);
+ this.community = _ko2.default.observable(true);
+ }
+
+ AbstractAppStore.prototype.populate = function populate() {
+ this.allowLanguagesOnLogin(!!_Settings2.default.settingsGet('AllowLanguagesOnLogin'));
+ this.allowLanguagesOnSettings(!!_Settings2.default.settingsGet('AllowLanguagesOnSettings'));
+
+ this.interfaceAnimation(!!_Settings2.default.settingsGet('InterfaceAnimation'));
+
+ this.prem(!!_Settings2.default.settingsGet('PremType'));
+ this.community(!!_Settings2.default.settingsGet('Community'));
+ };
+
+ return AbstractAppStore;
+ }();
+
+ exports.AbstractAppStore = AbstractAppStore;
+ exports.default = AbstractAppStore;
+
+/***/ },
+/* 77 */
+/*!***************************!*\
+ !*** ./dev/bootstrap.jsx ***!
+ \***************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+
+ exports.default = function (App) {
+
+ var window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Plugins = __webpack_require__(/*! Common/Plugins */ 23),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+ EmailModel = __webpack_require__(/*! Model/Email */ 30);
+
+ Globals.__APP__ = App;
+
+ Globals.$win.keydown(Utils.kill_CtrlA_CtrlS).unload(function () {
+ Globals.bUnload = true;
+ });
+
+ Globals.$html.addClass(Globals.bMobileDevice ? 'mobile' : 'no-mobile').on('click.dropdown.data-api', function () {
+ Utils.detectDropdownVisibility();
+ });
+
+ // export
+ /* eslint dot-notation: 0 */
+ window['rl'] = window['rl'] || {};
+ window['rl']['i18n'] = _.bind(Translator.i18n, Translator);
+
+ window['rl']['addHook'] = _.bind(Plugins.addHook, Plugins);
+ window['rl']['settingsGet'] = _.bind(Plugins.mainSettingsGet, Plugins);
+ window['rl']['createCommand'] = Utils.createCommand;
+
+ window['rl']['addSettingsViewModel'] = _.bind(Plugins.addSettingsViewModel, Plugins);
+
+ window['rl']['pluginRemoteRequest'] = _.bind(Plugins.remoteRequest, Plugins);
+ window['rl']['pluginSettingsGet'] = _.bind(Plugins.settingsGet, Plugins);
+
+ window['rl']['EmailModel'] = EmailModel;
+ window['rl']['Enums'] = Enums;
+
+ window['__APP_BOOT'] = function (fCall) {
+
+ $(_.delay(function () {
+
+ if (!$('#rl-check').is(':visible')) {
+ Globals.$html.addClass('no-css');
+ }
+
+ $('#rl-check').remove();
+
+ if (window['rainloopTEMPLATES'] && window['rainloopTEMPLATES'][0]) {
+ $('#rl-templates').html(window['rainloopTEMPLATES'][0]);
+
+ _.delay(function () {
+
+ App.bootstart();
+
+ Globals.$html.removeClass('no-js rl-booted-trigger').addClass('rl-booted');
+ }, 10);
+ } else {
+ fCall(false);
+ }
+
+ window['__APP_BOOT'] = null;
+ }, 10));
+ };
+ };
+
+/***/ },
+/* 78 */
+/*!************************************!*\
+ !*** external "window.Autolinker" ***!
+ \************************************/
+/***/ function(module, exports) {
+
+ module.exports = window.Autolinker;
+
+/***/ },
+/* 79 */
+/*!***********************************!*\
+ !*** external "window.JSEncrypt" ***!
+ \***********************************/
+/***/ function(module, exports) {
+
+ module.exports = window.JSEncrypt;
+
+/***/ },
+/* 80 */
+/*!*****************************!*\
+ !*** external "window.Jua" ***!
+ \*****************************/
+/***/ function(module, exports) {
+
+ module.exports = window.Jua;
+
+/***/ },
+/* 81 */
+/*!********************************!*\
+ !*** external "window.hasher" ***!
+ \********************************/
+/***/ function(module, exports) {
+
+ module.exports = window.hasher;
+
+/***/ },
+/* 82 */
+/*!********************************!*\
+ !*** external "window.moment" ***!
+ \********************************/
+/***/ function(module, exports) {
+
+ module.exports = window.moment;
+
+/***/ },
+/* 83 */
+/*!********************************************!*\
+ !*** external "window.rainloopProgressJs" ***!
+ \********************************************/
+/***/ function(module, exports) {
+
+ module.exports = window.rainloopProgressJs;
+
+/***/ },
+/* 84 */
+/*!*****************************!*\
+ !*** external "window.ssm" ***!
+ \*****************************/
+/***/ function(module, exports) {
+
+ module.exports = window.ssm;
+
+/***/ },
+/* 85 */
+/*!*******************************!*\
+ !*** ./dev/Helper/Message.js ***!
+ \*******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ EmailModel = __webpack_require__(/*! Model/Email */ 30)
+ ;
+
+ /**
+ * @constructor
+ */
+ function MessageHelper() {}
+
+ /**
+ * @param {Array.} aEmail
+ * @param {boolean=} bFriendlyView
+ * @param {boolean=} bWrapWithLink = false
+ * @return {string}
+ */
+ MessageHelper.prototype.emailArrayToString = function (aEmail, bFriendlyView, bWrapWithLink)
+ {
+ var
+ aResult = [],
+ iIndex = 0,
+ iLen = 0
+ ;
+
+ if (Utils.isNonEmptyArray(aEmail))
+ {
+ for (iIndex = 0, iLen = aEmail.length; iIndex < iLen; iIndex++)
+ {
+ aResult.push(aEmail[iIndex].toLine(bFriendlyView, bWrapWithLink));
+ }
+ }
+
+ return aResult.join(', ');
+ };
+
+ /**
+ * @param {Array.} aEmails
+ * @return {string}
+ */
+ MessageHelper.prototype.emailArrayToStringClear = function (aEmails)
+ {
+ var
+ aResult = [],
+ iIndex = 0,
+ iLen = 0
+ ;
+
+ if (Utils.isNonEmptyArray(aEmails))
+ {
+ for (iIndex = 0, iLen = aEmails.length; iIndex < iLen; iIndex++)
+ {
+ if (aEmails[iIndex] && aEmails[iIndex].email && '' !== aEmails[iIndex].name)
+ {
+ aResult.push(aEmails[iIndex].email);
+ }
+ }
+ }
+
+ return aResult.join(', ');
+ };
+
+ /**
+ * @param {?Array} aJson
+ * @return {Array.}
+ */
+ MessageHelper.prototype.emailArrayFromJson = function (aJson)
+ {
+ var
+ iIndex = 0,
+ iLen = 0,
+ oEmailModel = null,
+ aResult = []
+ ;
+
+ if (Utils.isNonEmptyArray(aJson))
+ {
+ for (iIndex = 0, iLen = aJson.length; iIndex < iLen; iIndex++)
+ {
+ oEmailModel = EmailModel.newInstanceFromJson(aJson[iIndex]);
+ if (oEmailModel)
+ {
+ aResult.push(oEmailModel);
+ }
+ }
+ }
+
+ return aResult;
+ };
+
+ /**
+ * @param {Array.} aInputEmails
+ * @param {Object} oUnic
+ * @param {Array} aLocalEmails
+ */
+ MessageHelper.prototype.replyHelper = function (aInputEmails, oUnic, aLocalEmails)
+ {
+ if (aInputEmails && 0 < aInputEmails.length)
+ {
+ var
+ iIndex = 0,
+ iLen = aInputEmails.length
+ ;
+
+ for (; iIndex < iLen; iIndex++)
+ {
+ if (Utils.isUnd(oUnic[aInputEmails[iIndex].email]))
+ {
+ oUnic[aInputEmails[iIndex].email] = true;
+ aLocalEmails.push(aInputEmails[iIndex]);
+ }
+ }
+ }
+ };
+
+ module.exports = new MessageHelper();
+
+ }());
+
+/***/ },
+/* 86 */
+/*!*********************************!*\
+ !*** ./dev/Model/Attachment.js ***!
+ \*********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+ Audio = __webpack_require__(/*! Common/Audio */ 65),
+
+ AbstractModel = __webpack_require__(/*! Knoin/AbstractModel */ 27)
+ ;
+
+ /**
+ * @constructor
+ */
+ function AttachmentModel()
+ {
+ AbstractModel.call(this, 'AttachmentModel');
+
+ this.checked = ko.observable(false);
+
+ this.mimeType = '';
+ this.fileName = '';
+ this.fileNameExt = '';
+ this.fileType = Enums.FileType.Unknown;
+ this.estimatedSize = 0;
+ this.friendlySize = '';
+ this.isInline = false;
+ this.isLinked = false;
+ this.isThumbnail = false;
+ this.cid = '';
+ this.cidWithOutTags = '';
+ this.contentLocation = '';
+ this.download = '';
+ this.folder = '';
+ this.uid = '';
+ this.mimeIndex = '';
+ this.framed = false;
+ }
+
+ _.extend(AttachmentModel.prototype, AbstractModel.prototype);
+
+ /**
+ * @static
+ * @param {AjaxJsonAttachment} oJsonAttachment
+ * @return {?AttachmentModel}
+ */
+ AttachmentModel.newInstanceFromJson = function (oJsonAttachment)
+ {
+ var oAttachmentModel = new AttachmentModel();
+ return oAttachmentModel.initByJson(oJsonAttachment) ? oAttachmentModel : null;
+ };
+
+ AttachmentModel.prototype.mimeType = '';
+ AttachmentModel.prototype.fileName = '';
+ AttachmentModel.prototype.fileType = '';
+ AttachmentModel.prototype.fileNameExt = '';
+ AttachmentModel.prototype.estimatedSize = 0;
+ AttachmentModel.prototype.friendlySize = '';
+ AttachmentModel.prototype.isInline = false;
+ AttachmentModel.prototype.isLinked = false;
+ AttachmentModel.prototype.isThumbnail = false;
+ AttachmentModel.prototype.cid = '';
+ AttachmentModel.prototype.cidWithOutTags = '';
+ AttachmentModel.prototype.contentLocation = '';
+ AttachmentModel.prototype.download = '';
+ AttachmentModel.prototype.folder = '';
+ AttachmentModel.prototype.uid = '';
+ AttachmentModel.prototype.mimeIndex = '';
+ AttachmentModel.prototype.framed = false;
+
+ /**
+ * @param {AjaxJsonAttachment} oJsonAttachment
+ */
+ AttachmentModel.prototype.initByJson = function (oJsonAttachment)
+ {
+ var bResult = false;
+ if (oJsonAttachment && 'Object/Attachment' === oJsonAttachment['@Object'])
+ {
+ this.mimeType = Utils.trim((oJsonAttachment.MimeType || '').toLowerCase());
+ this.fileName = Utils.trim(oJsonAttachment.FileName);
+ this.estimatedSize = Utils.pInt(oJsonAttachment.EstimatedSize);
+ this.isInline = !!oJsonAttachment.IsInline;
+ this.isLinked = !!oJsonAttachment.IsLinked;
+ this.isThumbnail = !!oJsonAttachment.IsThumbnail;
+ this.cid = oJsonAttachment.CID;
+ this.contentLocation = oJsonAttachment.ContentLocation;
+ this.download = oJsonAttachment.Download;
+
+ this.folder = oJsonAttachment.Folder;
+ this.uid = oJsonAttachment.Uid;
+ this.mimeIndex = oJsonAttachment.MimeIndex;
+ this.framed = !!oJsonAttachment.Framed;
+
+ this.friendlySize = Utils.friendlySize(this.estimatedSize);
+ this.cidWithOutTags = this.cid.replace(/^<+/, '').replace(/>+$/, '');
+
+ this.fileNameExt = Utils.getFileExtension(this.fileName);
+ this.fileType = AttachmentModel.staticFileType(this.fileNameExt, this.mimeType);
+
+ bResult = true;
+ }
+
+ return bResult;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ AttachmentModel.prototype.isImage = function ()
+ {
+ return Enums.FileType.Image === this.fileType;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ AttachmentModel.prototype.isMp3 = function ()
+ {
+ return Enums.FileType.Audio === this.fileType &&
+ 'mp3' === this.fileNameExt;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ AttachmentModel.prototype.isOgg = function ()
+ {
+ return Enums.FileType.Audio === this.fileType &&
+ ('oga' === this.fileNameExt || 'ogg' === this.fileNameExt);
+ };
+
+ /**
+ * @return {boolean}
+ */
+ AttachmentModel.prototype.isWav = function ()
+ {
+ return Enums.FileType.Audio === this.fileType &&
+ 'wav' === this.fileNameExt;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ AttachmentModel.prototype.hasThumbnail = function ()
+ {
+ return this.isThumbnail;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ AttachmentModel.prototype.isText = function ()
+ {
+ return Enums.FileType.Text === this.fileType ||
+ Enums.FileType.Eml === this.fileType ||
+ Enums.FileType.Certificate === this.fileType ||
+ Enums.FileType.Html === this.fileType ||
+ Enums.FileType.Code === this.fileType
+ ;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ AttachmentModel.prototype.isPdf = function ()
+ {
+ return Enums.FileType.Pdf === this.fileType;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ AttachmentModel.prototype.isFramed = function ()
+ {
+ return this.framed && (Globals.__APP__ && Globals.__APP__.googlePreviewSupported()) &&
+ !(this.isPdf() && Globals.bAllowPdfPreview) && !this.isText() && !this.isImage();
+ };
+
+ /**
+ * @return {boolean}
+ */
+ AttachmentModel.prototype.hasPreview = function ()
+ {
+ return this.isImage() || (this.isPdf() && Globals.bAllowPdfPreview) ||
+ this.isText() || this.isFramed();
+ };
+
+ /**
+ * @return {boolean}
+ */
+ AttachmentModel.prototype.hasPreplay = function ()
+ {
+ return (Audio.supportedMp3 && this.isMp3()) ||
+ (Audio.supportedOgg && this.isOgg()) ||
+ (Audio.supportedWav && this.isWav())
+ ;
+ };
+
+ /**
+ * @return {string}
+ */
+ AttachmentModel.prototype.linkDownload = function ()
+ {
+ return Links.attachmentDownload(this.download);
+ };
+
+ /**
+ * @return {string}
+ */
+ AttachmentModel.prototype.linkPreview = function ()
+ {
+ return Links.attachmentPreview(this.download);
+ };
+
+ /**
+ * @return {string}
+ */
+ AttachmentModel.prototype.linkThumbnail = function ()
+ {
+ return this.hasThumbnail() ? Links.attachmentThumbnailPreview(this.download) : '';
+ };
+
+ /**
+ * @return {string}
+ */
+ AttachmentModel.prototype.linkThumbnailPreviewStyle = function ()
+ {
+ var sLink = this.linkThumbnail();
+ return '' === sLink ? '' : 'background:url(' + sLink + ')';
+ };
+
+ /**
+ * @return {string}
+ */
+ AttachmentModel.prototype.linkFramed = function ()
+ {
+ return Links.attachmentFramed(this.download);
+ };
+
+ /**
+ * @return {string}
+ */
+ AttachmentModel.prototype.linkPreviewAsPlain = function ()
+ {
+ return Links.attachmentPreviewAsPlain(this.download);
+ };
+
+ /**
+ * @return {string}
+ */
+ AttachmentModel.prototype.linkPreviewMain = function ()
+ {
+ var sResult = '';
+ switch (true)
+ {
+ case this.isImage():
+ case this.isPdf() && Globals.bAllowPdfPreview:
+ sResult = this.linkPreview();
+ break;
+ case this.isText():
+ sResult = this.linkPreviewAsPlain();
+ break;
+ case this.isFramed():
+ sResult = this.linkFramed();
+ break;
+ }
+
+ return sResult;
+ };
+
+ /**
+ * @return {string}
+ */
+ AttachmentModel.prototype.generateTransferDownloadUrl = function ()
+ {
+ var sLink = this.linkDownload();
+ if ('http' !== sLink.substr(0, 4))
+ {
+ sLink = window.location.protocol + '//' + window.location.host + window.location.pathname + sLink;
+ }
+
+ return this.mimeType + ':' + this.fileName + ':' + sLink;
+ };
+
+ /**
+ * @param {AttachmentModel} oAttachment
+ * @param {*} oEvent
+ * @return {boolean}
+ */
+ AttachmentModel.prototype.eventDragStart = function (oAttachment, oEvent)
+ {
+ var oLocalEvent = oEvent.originalEvent || oEvent;
+ if (oAttachment && oLocalEvent && oLocalEvent.dataTransfer && oLocalEvent.dataTransfer.setData)
+ {
+ oLocalEvent.dataTransfer.setData('DownloadURL', this.generateTransferDownloadUrl());
+ }
+
+ return true;
+ };
+
+ /**
+ * @param {string} sExt
+ * @param {string} sMimeType
+ * @return {string}
+ */
+ AttachmentModel.staticFileType = _.memoize(function (sExt, sMimeType)
+ {
+ sExt = Utils.trim(sExt).toLowerCase();
+ sMimeType = Utils.trim(sMimeType).toLowerCase();
+
+ var
+ sResult = Enums.FileType.Unknown,
+ aMimeTypeParts = sMimeType.split('/')
+ ;
+
+ switch (true)
+ {
+ case 'image' === aMimeTypeParts[0] || -1 < Utils.inArray(sExt, [
+ 'png', 'jpg', 'jpeg', 'gif', 'bmp'
+ ]):
+ sResult = Enums.FileType.Image;
+ break;
+ case 'audio' === aMimeTypeParts[0] || -1 < Utils.inArray(sExt, [
+ 'mp3', 'ogg', 'oga', 'wav'
+ ]):
+ sResult = Enums.FileType.Audio;
+ break;
+ case 'video' === aMimeTypeParts[0] || -1 < Utils.inArray(sExt, [
+ 'mkv', 'avi'
+ ]):
+ sResult = Enums.FileType.Video;
+ break;
+ case -1 < Utils.inArray(sExt, [
+ 'php', 'js', 'css'
+ ]):
+ sResult = Enums.FileType.Code;
+ break;
+ case 'eml' === sExt || -1 < Utils.inArray(sMimeType, [
+ 'message/delivery-status', 'message/rfc822'
+ ]):
+ sResult = Enums.FileType.Eml;
+ break;
+ case ('text' === aMimeTypeParts[0] && 'html' !== aMimeTypeParts[1]) || -1 < Utils.inArray(sExt, [
+ 'txt', 'log'
+ ]):
+ sResult = Enums.FileType.Text;
+ break;
+ case ('text/html' === sMimeType) || -1 < Utils.inArray(sExt, [
+ 'html'
+ ]):
+ sResult = Enums.FileType.Html;
+ break;
+ case -1 < Utils.inArray(aMimeTypeParts[1], [
+ 'zip', '7z', 'tar', 'rar', 'gzip', 'bzip', 'bzip2', 'x-zip', 'x-7z', 'x-rar', 'x-tar', 'x-gzip', 'x-bzip', 'x-bzip2', 'x-zip-compressed', 'x-7z-compressed', 'x-rar-compressed'
+ ]) || -1 < Utils.inArray(sExt, [
+ 'zip', '7z', 'tar', 'rar', 'gzip', 'bzip', 'bzip2'
+ ]):
+ sResult = Enums.FileType.Archive;
+ break;
+ case -1 < Utils.inArray(aMimeTypeParts[1], ['pdf', 'x-pdf']) || -1 < Utils.inArray(sExt, [
+ 'pdf'
+ ]):
+ sResult = Enums.FileType.Pdf;
+ break;
+ case -1 < Utils.inArray(sMimeType, [
+ 'application/pgp-signature', 'application/pgp-keys'
+ ]) || -1 < Utils.inArray(sExt, [
+ 'asc', 'pem', 'ppk'
+ ]):
+ sResult = Enums.FileType.Certificate;
+ break;
+ case -1 < Utils.inArray(sMimeType, ['application/pkcs7-signature']) ||
+ -1 < Utils.inArray(sExt, ['p7s']):
+
+ sResult = Enums.FileType.CertificateBin;
+ break;
+ case -1 < Utils.inArray(aMimeTypeParts[1], [
+ 'rtf', 'msword', 'vnd.msword', 'vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'vnd.openxmlformats-officedocument.wordprocessingml.template',
+ 'vnd.ms-word.document.macroEnabled.12',
+ 'vnd.ms-word.template.macroEnabled.12'
+ ]):
+ sResult = Enums.FileType.WordText;
+ break;
+ case -1 < Utils.inArray(aMimeTypeParts[1], [
+ 'excel', 'ms-excel', 'vnd.ms-excel',
+ 'vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'vnd.openxmlformats-officedocument.spreadsheetml.template',
+ 'vnd.ms-excel.sheet.macroEnabled.12',
+ 'vnd.ms-excel.template.macroEnabled.12',
+ 'vnd.ms-excel.addin.macroEnabled.12',
+ 'vnd.ms-excel.sheet.binary.macroEnabled.12'
+ ]):
+ sResult = Enums.FileType.Sheet;
+ break;
+ case -1 < Utils.inArray(aMimeTypeParts[1], [
+ 'powerpoint', 'ms-powerpoint', 'vnd.ms-powerpoint',
+ 'vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'vnd.openxmlformats-officedocument.presentationml.template',
+ 'vnd.openxmlformats-officedocument.presentationml.slideshow',
+ 'vnd.ms-powerpoint.addin.macroEnabled.12',
+ 'vnd.ms-powerpoint.presentation.macroEnabled.12',
+ 'vnd.ms-powerpoint.template.macroEnabled.12',
+ 'vnd.ms-powerpoint.slideshow.macroEnabled.12'
+ ]):
+ sResult = Enums.FileType.Presentation;
+ break;
+ }
+
+ return sResult;
+ });
+
+ /**
+ * @param {string} sFileType
+ * @return {string}
+ */
+ AttachmentModel.staticIconClass = _.memoize(function (sFileType)
+ {
+ var
+ sText = '',
+ sClass = 'icon-file'
+ ;
+
+ switch (sFileType)
+ {
+ case Enums.FileType.Text:
+ case Enums.FileType.Eml:
+ case Enums.FileType.WordText:
+ sClass = 'icon-file-text';
+ break;
+ case Enums.FileType.Html:
+ case Enums.FileType.Code:
+ sClass = 'icon-file-code';
+ break;
+ case Enums.FileType.Image:
+ sClass = 'icon-file-image';
+ break;
+ case Enums.FileType.Audio:
+ sClass = 'icon-file-music';
+ break;
+ case Enums.FileType.Video:
+ sClass = 'icon-file-movie';
+ break;
+ case Enums.FileType.Archive:
+ sClass = 'icon-file-zip';
+ break;
+ case Enums.FileType.Certificate:
+ case Enums.FileType.CertificateBin:
+ sClass = 'icon-file-certificate';
+ break;
+ case Enums.FileType.Sheet:
+ sClass = 'icon-file-excel';
+ break;
+ case Enums.FileType.Presentation:
+ sClass = 'icon-file-chart-graph';
+ break;
+ case Enums.FileType.Pdf:
+ sText = 'pdf';
+ sClass = 'icon-none';
+ break;
+ }
+
+ return [sClass, sText];
+ });
+
+ /**
+ * @param {string} sFileType
+ * @return {string}
+ */
+ AttachmentModel.staticCombinedIconClass = function (aData)
+ {
+ var
+ sClass = '',
+ aTypes = []
+ ;
+
+ if (Utils.isNonEmptyArray(aData))
+ {
+ sClass = 'icon-attachment';
+
+ aTypes = _.uniq(_.compact(_.map(aData, function (aItem) {
+ return aItem ? AttachmentModel.staticFileType(
+ Utils.getFileExtension(aItem[0]), aItem[1]) : '';
+ })));
+
+ if (aTypes && 1 === aTypes.length && aTypes[0])
+ {
+ switch (aTypes[0])
+ {
+ case Enums.FileType.Text:
+ case Enums.FileType.WordText:
+ sClass = 'icon-file-text';
+ break;
+ case Enums.FileType.Html:
+ case Enums.FileType.Code:
+ sClass = 'icon-file-code';
+ break;
+ case Enums.FileType.Image:
+ sClass = 'icon-file-image';
+ break;
+ case Enums.FileType.Audio:
+ sClass = 'icon-file-music';
+ break;
+ case Enums.FileType.Video:
+ sClass = 'icon-file-movie';
+ break;
+ case Enums.FileType.Archive:
+ sClass = 'icon-file-zip';
+ break;
+ case Enums.FileType.Certificate:
+ case Enums.FileType.CertificateBin:
+ sClass = 'icon-file-certificate';
+ break;
+ case Enums.FileType.Sheet:
+ sClass = 'icon-file-excel';
+ break;
+ case Enums.FileType.Presentation:
+ sClass = 'icon-file-chart-graph';
+ break;
+ }
+ }
+ }
+
+ return sClass;
+ };
+
+ /**
+ * @return {string}
+ */
+ AttachmentModel.prototype.iconClass = function ()
+ {
+ return AttachmentModel.staticIconClass(this.fileType)[0];
+ };
+
+ /**
+ * @return {string}
+ */
+ AttachmentModel.prototype.iconText = function ()
+ {
+ return AttachmentModel.staticIconClass(this.fileType)[1];
+ };
+
+ module.exports = AttachmentModel;
+
+ }());
+
+/***/ },
+/* 87 */
+/*!*****************************!*\
+ !*** ./dev/Model/Filter.js ***!
+ \*****************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Cache = __webpack_require__(/*! Common/Cache */ 19),
+
+ FilterConditionModel = __webpack_require__(/*! Model/FilterCondition */ 105),
+
+ AbstractModel = __webpack_require__(/*! Knoin/AbstractModel */ 27)
+ ;
+
+ /**
+ * @constructor
+ */
+ function FilterModel()
+ {
+ AbstractModel.call(this, 'FilterModel');
+
+ this.enabled = ko.observable(true);
+
+ this.id = '';
+
+ this.name = ko.observable('');
+ this.name.error = ko.observable(false);
+ this.name.focused = ko.observable(false);
+
+ this.conditions = ko.observableArray([]);
+ this.conditionsType = ko.observable(Enums.FilterRulesType.Any);
+
+ // Actions
+ this.actionValue = ko.observable('');
+ this.actionValue.error = ko.observable(false);
+
+ this.actionValueSecond = ko.observable('');
+ this.actionValueThird = ko.observable('');
+
+ this.actionValueFourth = ko.observable('');
+ this.actionValueFourth.error = ko.observable(false);
+
+ this.actionMarkAsRead = ko.observable(false);
+
+ this.actionKeep = ko.observable(true);
+ this.actionNoStop = ko.observable(false);
+
+ this.actionType = ko.observable(Enums.FiltersAction.MoveTo);
+
+ this.actionType.subscribe(function () {
+ this.actionValue('');
+ this.actionValue.error(false);
+ this.actionValueSecond('');
+ this.actionValueThird('');
+ this.actionValueFourth('');
+ this.actionValueFourth.error(false);
+ }, this);
+
+ var fGetRealFolderName = function (sFolderFullNameRaw) {
+ var oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw);
+ return oFolder ? oFolder.fullName.replace(
+ '.' === oFolder.delimiter ? /\./ : /[\\\/]+/, ' / ') : sFolderFullNameRaw;
+ };
+
+ this.nameSub = ko.computed(function () {
+
+ var
+ sResult = '',
+ sActionValue = this.actionValue()
+ ;
+
+ switch (this.actionType())
+ {
+ case Enums.FiltersAction.MoveTo:
+ sResult = Translator.i18n('SETTINGS_FILTERS/SUBNAME_MOVE_TO', {
+ 'FOLDER': fGetRealFolderName(sActionValue)
+ });
+ break;
+ case Enums.FiltersAction.Forward:
+ sResult = Translator.i18n('SETTINGS_FILTERS/SUBNAME_FORWARD_TO', {
+ 'EMAIL': sActionValue
+ });
+ break;
+ case Enums.FiltersAction.Vacation:
+ sResult = Translator.i18n('SETTINGS_FILTERS/SUBNAME_VACATION_MESSAGE');
+ break;
+ case Enums.FiltersAction.Reject:
+ sResult = Translator.i18n('SETTINGS_FILTERS/SUBNAME_REJECT');
+ break;
+ case Enums.FiltersAction.Discard:
+ sResult = Translator.i18n('SETTINGS_FILTERS/SUBNAME_DISCARD');
+ break;
+ }
+
+ return sResult ? '(' + sResult + ')' : '';
+
+ }, this);
+
+ this.actionTemplate = ko.computed(function () {
+
+ var sTemplate = '';
+ switch (this.actionType())
+ {
+ default:
+ case Enums.FiltersAction.MoveTo:
+ sTemplate = 'SettingsFiltersActionMoveToFolder';
+ break;
+ case Enums.FiltersAction.Forward:
+ sTemplate = 'SettingsFiltersActionForward';
+ break;
+ case Enums.FiltersAction.Vacation:
+ sTemplate = 'SettingsFiltersActionVacation';
+ break;
+ case Enums.FiltersAction.Reject:
+ sTemplate = 'SettingsFiltersActionReject';
+ break;
+ case Enums.FiltersAction.None:
+ sTemplate = 'SettingsFiltersActionNone';
+ break;
+ case Enums.FiltersAction.Discard:
+ sTemplate = 'SettingsFiltersActionDiscard';
+ break;
+ }
+
+ return sTemplate;
+
+ }, this);
+
+ this.regDisposables(this.conditions.subscribe(Utils.windowResizeCallback));
+
+ this.regDisposables(this.name.subscribe(function (sValue) {
+ this.name.error('' === sValue);
+ }, this));
+
+ this.regDisposables(this.actionValue.subscribe(function (sValue) {
+ this.actionValue.error('' === sValue);
+ }, this));
+
+ this.regDisposables([this.actionNoStop, this.actionTemplate]);
+
+ this.deleteAccess = ko.observable(false);
+ this.canBeDeleted = ko.observable(true);
+ }
+
+ _.extend(FilterModel.prototype, AbstractModel.prototype);
+
+ FilterModel.prototype.generateID = function ()
+ {
+ this.id = Utils.fakeMd5();
+ };
+
+ FilterModel.prototype.verify = function ()
+ {
+ if ('' === this.name())
+ {
+ this.name.error(true);
+ return false;
+ }
+
+ if (0 < this.conditions().length)
+ {
+ if (_.find(this.conditions(), function (oCond) {
+ return oCond && !oCond.verify();
+ }))
+ {
+ return false;
+ }
+ }
+
+ if ('' === this.actionValue())
+ {
+ if (-1 < Utils.inArray(this.actionType(), [
+ Enums.FiltersAction.MoveTo,
+ Enums.FiltersAction.Forward,
+ Enums.FiltersAction.Reject,
+ Enums.FiltersAction.Vacation
+ ]))
+ {
+ this.actionValue.error(true);
+ return false;
+ }
+ }
+
+ if (Enums.FiltersAction.Forward === this.actionType() &&
+ -1 === this.actionValue().indexOf('@'))
+ {
+ this.actionValue.error(true);
+ return false;
+ }
+
+ if (Enums.FiltersAction.Vacation === this.actionType() &&
+ '' !== this.actionValueFourth() && -1 === this.actionValueFourth().indexOf('@')
+ )
+ {
+ this.actionValueFourth.error(true);
+ return false;
+ }
+
+ this.name.error(false);
+ this.actionValue.error(false);
+
+ return true;
+ };
+
+ FilterModel.prototype.toJson = function ()
+ {
+ return {
+ 'ID': this.id,
+ 'Enabled': this.enabled() ? '1' : '0',
+ 'Name': this.name(),
+ 'ConditionsType': this.conditionsType(),
+ 'Conditions': _.map(this.conditions(), function (oItem) {
+ return oItem.toJson();
+ }),
+
+ 'ActionValue': this.actionValue(),
+ 'ActionValueSecond': this.actionValueSecond(),
+ 'ActionValueThird': this.actionValueThird(),
+ 'ActionValueFourth': this.actionValueFourth(),
+ 'ActionType': this.actionType(),
+
+ 'Stop': this.actionNoStop() ? '0' : '1',
+ 'Keep': this.actionKeep() ? '1' : '0',
+ 'MarkAsRead': this.actionMarkAsRead() ? '1' : '0'
+ };
+ };
+
+ FilterModel.prototype.addCondition = function ()
+ {
+ this.conditions.push(new FilterConditionModel());
+ };
+
+ FilterModel.prototype.removeCondition = function (oConditionToDelete)
+ {
+ this.conditions.remove(oConditionToDelete);
+ Utils.delegateRunOnDestroy(oConditionToDelete);
+ };
+
+ FilterModel.prototype.setRecipients = function ()
+ {
+ this.actionValueFourth(__webpack_require__(/*! Stores/User/Account */ 31).accountsEmails().join(', '));
+ };
+
+ FilterModel.prototype.parse = function (oItem)
+ {
+ var bResult = false;
+ if (oItem && 'Object/Filter' === oItem['@Object'])
+ {
+ this.id = Utils.pString(oItem['ID']);
+ this.name(Utils.pString(oItem['Name']));
+ this.enabled(!!oItem['Enabled']);
+
+ this.conditionsType(Utils.pString(oItem['ConditionsType']));
+
+ this.conditions([]);
+
+ if (Utils.isNonEmptyArray(oItem['Conditions']))
+ {
+ this.conditions(_.compact(_.map(oItem['Conditions'], function (aData) {
+ var oFilterCondition = new FilterConditionModel();
+ return oFilterCondition && oFilterCondition.parse(aData) ?
+ oFilterCondition : null;
+ })));
+ }
+
+ this.actionType(Utils.pString(oItem['ActionType']));
+
+ this.actionValue(Utils.pString(oItem['ActionValue']));
+ this.actionValueSecond(Utils.pString(oItem['ActionValueSecond']));
+ this.actionValueThird(Utils.pString(oItem['ActionValueThird']));
+ this.actionValueFourth(Utils.pString(oItem['ActionValueFourth']));
+
+ this.actionNoStop(!oItem['Stop']);
+ this.actionKeep(!!oItem['Keep']);
+ this.actionMarkAsRead(!!oItem['MarkAsRead']);
+
+ bResult = true;
+ }
+
+ return bResult;
+ };
+
+ FilterModel.prototype.cloneSelf = function ()
+ {
+ var oClone = new FilterModel();
+
+ oClone.id = this.id;
+
+ oClone.enabled(this.enabled());
+
+ oClone.name(this.name());
+ oClone.name.error(this.name.error());
+
+ oClone.conditionsType(this.conditionsType());
+
+ oClone.actionMarkAsRead(this.actionMarkAsRead());
+
+ oClone.actionType(this.actionType());
+
+ oClone.actionValue(this.actionValue());
+ oClone.actionValue.error(this.actionValue.error());
+
+ oClone.actionValueSecond(this.actionValueSecond());
+ oClone.actionValueThird(this.actionValueThird());
+ oClone.actionValueFourth(this.actionValueFourth());
+
+ oClone.actionKeep(this.actionKeep());
+ oClone.actionNoStop(this.actionNoStop());
+
+ oClone.conditions(_.map(this.conditions(), function (oCondition) {
+ return oCondition.cloneSelf();
+ }));
+
+ return oClone;
+ };
+
+ module.exports = FilterModel;
+
+ }());
+
+/***/ },
+/* 88 */
+/*!***************************************!*\
+ !*** ./dev/Promises/AbstractBasic.js ***!
+ \***************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ Q = __webpack_require__(/*! Q */ 48),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1)
+ ;
+
+ /**
+ * @constructor
+ */
+ function AbstractBasicPromises()
+ {
+ this.oPromisesStack = {};
+ }
+
+ AbstractBasicPromises.prototype.func = function (fFunc)
+ {
+ fFunc();
+ return this;
+ };
+
+ AbstractBasicPromises.prototype.fastResolve = function (mData)
+ {
+ var oDeferred = Q.defer();
+ oDeferred.resolve(mData);
+ return oDeferred.promise;
+ };
+
+ AbstractBasicPromises.prototype.fastReject = function (mData)
+ {
+ var oDeferred = Q.defer();
+ oDeferred.reject(mData);
+ return oDeferred.promise;
+ };
+
+ AbstractBasicPromises.prototype.setTrigger = function (mTrigger, bValue)
+ {
+ if (mTrigger)
+ {
+ _.each(Utils.isArray(mTrigger) ? mTrigger : [mTrigger], function (fTrigger) {
+ if (fTrigger)
+ {
+ fTrigger(!!bValue);
+ }
+ });
+ }
+ };
+
+ module.exports = AbstractBasicPromises;
+
+ }());
+
+/***/ },
+/* 89 */,
+/* 90 */
+/*!***********************************!*\
+ !*** ./dev/Stores/User/Filter.js ***!
+ \***********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2)
+ ;
+
+ /**
+ * @constructor
+ */
+ function FilterUserStore()
+ {
+ this.capa = ko.observable('');
+ this.modules = ko.observable({});
+
+ this.filters = ko.observableArray([]);
+
+ this.filters.loading = ko.observable(false).extend({'throttle': 200});
+ this.filters.saving = ko.observable(false).extend({'throttle': 200});
+
+ this.raw = ko.observable('');
+ }
+
+ module.exports = new FilterUserStore();
+
+ }());
+
+
+/***/ },
+/* 91 */
+/*!**********************************!*\
+ !*** ./dev/Stores/User/Quota.js ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ ko = __webpack_require__(/*! ko */ 2)
+ ;
+
+ /**
+ * @constructor
+ */
+ function QuotaUserStore()
+ {
+ this.quota = ko.observable(0);
+ this.usage = ko.observable(0);
+
+ this.percentage = ko.computed(function () {
+
+ var
+ iQuota = this.quota(),
+ iUsed = this.usage()
+ ;
+
+ return 0 < iQuota ? window.Math.ceil((iUsed / iQuota) * 100) : 0;
+
+ }, this);
+ }
+
+ /**
+ * @param {number} iQuota
+ * @param {number} iUsage
+ */
+ QuotaUserStore.prototype.populateData = function(iQuota, iUsage)
+ {
+ this.quota(iQuota * 1024);
+ this.usage(iUsage * 1024);
+ };
+
+ module.exports = new QuotaUserStore();
+
+ }());
+
+
+/***/ },
+/* 92 */
+/*!*************************************!*\
+ !*** ./dev/Stores/User/Template.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2)
+
+ // Remote = require('Remote/User/Ajax')
+ ;
+
+ /**
+ * @constructor
+ */
+ function TemplateUserStore()
+ {
+ this.templates = ko.observableArray([]);
+ this.templates.loading = ko.observable(false).extend({'throttle': 100});
+
+ this.templatesNames = ko.observableArray([]).extend({'throttle': 1000});
+ this.templatesNames.skipFirst = true;
+
+ this.subscribers();
+ }
+
+ TemplateUserStore.prototype.subscribers = function ()
+ {
+ this.templates.subscribe(function (aList) {
+ this.templatesNames(_.compact(_.map(aList, function (oItem) {
+ return oItem ? oItem.name : null;
+ })));
+ }, this);
+
+ // this.templatesNames.subscribe(function (aList) {
+ // if (this.templatesNames.skipFirst)
+ // {
+ // this.templatesNames.skipFirst = false;
+ // }
+ // else if (aList && 1 < aList.length)
+ // {
+ // Remote.templatesSortOrder(null, aList);
+ // }
+ // }, this);
+ };
+
+ module.exports = new TemplateUserStore();
+
+ }());
+
+
+/***/ },
+/* 93 */,
+/* 94 */
+/*!**********************************!*\
+ !*** ./dev/View/Popup/Filter.js ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ FilterStore = __webpack_require__(/*! Stores/User/Filter */ 90),
+ FolderStore = __webpack_require__(/*! Stores/User/Folder */ 21),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function FilterPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsFilter');
+
+ this.isNew = ko.observable(true);
+
+ this.modules = FilterStore.modules;
+
+ this.fTrueCallback = null;
+ this.filter = ko.observable(null);
+
+ this.allowMarkAsRead = ko.observable(false);
+
+ this.defautOptionsAfterRender = Utils.defautOptionsAfterRender;
+ this.folderSelectList = FolderStore.folderMenuForFilters;
+ this.selectedFolderValue = ko.observable('');
+
+ this.selectedFolderValue.subscribe(function() {
+ if (this.filter())
+ {
+ this.filter().actionValue.error(false);
+ }
+ }, this);
+
+ this.saveFilter = Utils.createCommand(this, function () {
+
+ if (this.filter())
+ {
+ if (Enums.FiltersAction.MoveTo === this.filter().actionType())
+ {
+ this.filter().actionValue(this.selectedFolderValue());
+ }
+
+ if (!this.filter().verify())
+ {
+ return false;
+ }
+
+ if (this.fTrueCallback)
+ {
+ this.fTrueCallback(this.filter());
+ }
+
+ if (this.modalVisibility())
+ {
+ Utils.delegateRun(this, 'closeCommand');
+ }
+ }
+
+ return true;
+ });
+
+ this.actionTypeOptions = ko.observableArray([]);
+ this.fieldOptions = ko.observableArray([]);
+ this.typeOptions = ko.observableArray([]);
+ this.typeOptionsSize = ko.observableArray([]);
+
+ Translator.initOnStartOrLangChange(this.populateOptions, this);
+
+ this.modules.subscribe(this.populateOptions, this);
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/Filter', 'PopupsFilterViewModel'], FilterPopupView);
+ _.extend(FilterPopupView.prototype, AbstractView.prototype);
+
+ FilterPopupView.prototype.populateOptions = function ()
+ {
+ this.actionTypeOptions([]);
+
+ // this.actionTypeOptions.push({'id': Enums.FiltersAction.None,
+ // 'name': Translator.i18n('POPUPS_FILTER/SELECT_ACTION_NONE')});
+
+ var oModules = this.modules();
+ if (oModules)
+ {
+ if (oModules.markasread)
+ {
+ this.allowMarkAsRead(true);
+ }
+
+ if (oModules.moveto)
+ {
+ this.actionTypeOptions.push({'id': Enums.FiltersAction.MoveTo,
+ 'name': Translator.i18n('POPUPS_FILTER/SELECT_ACTION_MOVE_TO')});
+ }
+
+ if (oModules.redirect)
+ {
+ this.actionTypeOptions.push({'id': Enums.FiltersAction.Forward,
+ 'name': Translator.i18n('POPUPS_FILTER/SELECT_ACTION_FORWARD_TO')});
+ }
+
+ if (oModules.reject)
+ {
+ this.actionTypeOptions.push({'id': Enums.FiltersAction.Reject,
+ 'name': Translator.i18n('POPUPS_FILTER/SELECT_ACTION_REJECT')});
+ }
+
+ if (oModules.vacation)
+ {
+ this.actionTypeOptions.push({'id': Enums.FiltersAction.Vacation,
+ 'name': Translator.i18n('POPUPS_FILTER/SELECT_ACTION_VACATION_MESSAGE')});
+
+ }
+ }
+
+ this.actionTypeOptions.push({'id': Enums.FiltersAction.Discard,
+ 'name': Translator.i18n('POPUPS_FILTER/SELECT_ACTION_DISCARD')});
+
+ this.fieldOptions([
+ {'id': Enums.FilterConditionField.From, 'name': Translator.i18n('POPUPS_FILTER/SELECT_FIELD_FROM')},
+ {'id': Enums.FilterConditionField.Recipient, 'name': Translator.i18n('POPUPS_FILTER/SELECT_FIELD_RECIPIENTS')},
+ {'id': Enums.FilterConditionField.Subject, 'name': Translator.i18n('POPUPS_FILTER/SELECT_FIELD_SUBJECT')},
+ {'id': Enums.FilterConditionField.Size, 'name': Translator.i18n('POPUPS_FILTER/SELECT_FIELD_SIZE')},
+ {'id': Enums.FilterConditionField.Header, 'name': Translator.i18n('POPUPS_FILTER/SELECT_FIELD_HEADER')}
+ ]);
+
+ this.typeOptions([
+ {'id': Enums.FilterConditionType.Contains, 'name': Translator.i18n('POPUPS_FILTER/SELECT_TYPE_CONTAINS')},
+ {'id': Enums.FilterConditionType.NotContains, 'name': Translator.i18n('POPUPS_FILTER/SELECT_TYPE_NOT_CONTAINS')},
+ {'id': Enums.FilterConditionType.EqualTo, 'name': Translator.i18n('POPUPS_FILTER/SELECT_TYPE_EQUAL_TO')},
+ {'id': Enums.FilterConditionType.NotEqualTo, 'name': Translator.i18n('POPUPS_FILTER/SELECT_TYPE_NOT_EQUAL_TO')}
+ ]);
+
+ this.typeOptionsSize([
+ {'id': Enums.FilterConditionType.Over, 'name': Translator.i18n('POPUPS_FILTER/SELECT_TYPE_OVER')},
+ {'id': Enums.FilterConditionType.Under, 'name': Translator.i18n('POPUPS_FILTER/SELECT_TYPE_UNDER')}
+ ]);
+ };
+
+
+ FilterPopupView.prototype.removeCondition = function (oConditionToDelete)
+ {
+ if (this.filter())
+ {
+ this.filter().removeCondition(oConditionToDelete);
+ }
+ };
+
+ FilterPopupView.prototype.clearPopup = function ()
+ {
+ this.isNew(true);
+
+ this.fTrueCallback = null;
+ this.filter(null);
+ };
+
+ FilterPopupView.prototype.onShow = function (oFilter, fTrueCallback, bEdit)
+ {
+ this.clearPopup();
+
+ this.fTrueCallback = fTrueCallback;
+ this.filter(oFilter);
+
+ if (oFilter)
+ {
+ this.selectedFolderValue(oFilter.actionValue());
+ }
+
+ this.isNew(!bEdit);
+
+ if (!bEdit && oFilter)
+ {
+ oFilter.name.focused(true);
+ }
+ };
+
+ FilterPopupView.prototype.onShowWithDelay = function ()
+ {
+ if (this.isNew() && this.filter() && !Globals.bMobile)
+ {
+ this.filter().name.focused(true);
+ }
+ };
+
+ module.exports = FilterPopupView;
+
+ }());
+
+/***/ },
+/* 95 */
+/*!****************************************!*\
+ !*** ./dev/View/Popup/FolderCreate.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ FolderStore = __webpack_require__(/*! Stores/User/Folder */ 21),
+
+ Promises = __webpack_require__(/*! Promises/User/Ajax */ 41),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function FolderCreateView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsFolderCreate');
+
+ this.folderName = ko.observable('');
+ this.folderName.focused = ko.observable(false);
+
+ this.selectedParentValue = ko.observable(Consts.UNUSED_OPTION_VALUE);
+
+ this.parentFolderSelectList = ko.computed(function () {
+
+ var
+ aTop = [],
+ fDisableCallback = null,
+ fVisibleCallback = null,
+ aList = FolderStore.folderList(),
+ fRenameCallback = function (oItem) {
+ return oItem ? (oItem.isSystemFolder() ? oItem.name() + ' ' + oItem.manageFolderSystemName() : oItem.name()) : '';
+ }
+ ;
+
+ aTop.push(['', '']);
+
+ if ('' !== FolderStore.namespace)
+ {
+ fDisableCallback = function (oItem)
+ {
+ return FolderStore.namespace !== oItem.fullNameRaw.substr(0, FolderStore.namespace.length);
+ };
+ }
+
+ return Utils.folderListOptionsBuilder([], aList, [], aTop, null, fDisableCallback, fVisibleCallback, fRenameCallback);
+
+ }, this);
+
+ // commands
+ this.createFolder = Utils.createCommand(this, function () {
+
+ var
+ sParentFolderName = this.selectedParentValue()
+ ;
+
+ if ('' === sParentFolderName && 1 < FolderStore.namespace.length)
+ {
+ sParentFolderName = FolderStore.namespace.substr(0, FolderStore.namespace.length - 1);
+ }
+
+ __webpack_require__(/*! App/User */ 7).default.foldersPromisesActionHelper(
+ Promises.folderCreate(this.folderName(), sParentFolderName, FolderStore.foldersCreating),
+ Enums.Notification.CantCreateFolder);
+
+ this.cancelCommand();
+
+ }, function () {
+ return this.simpleFolderNameValidation(this.folderName());
+ });
+
+ this.defautOptionsAfterRender = Utils.defautOptionsAfterRender;
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/FolderCreate', 'PopupsFolderCreateViewModel'], FolderCreateView);
+ _.extend(FolderCreateView.prototype, AbstractView.prototype);
+
+ FolderCreateView.prototype.simpleFolderNameValidation = function (sName)
+ {
+ return (/^[^\\\/]+$/g).test(Utils.trim(sName));
+ };
+
+ FolderCreateView.prototype.clearPopup = function ()
+ {
+ this.folderName('');
+ this.selectedParentValue('');
+ this.folderName.focused(false);
+ };
+
+ FolderCreateView.prototype.onShow = function ()
+ {
+ this.clearPopup();
+ };
+
+ FolderCreateView.prototype.onShowWithDelay = function ()
+ {
+ if (!Globals.bMobile)
+ {
+ this.folderName.focused(true);
+ }
+ };
+
+ module.exports = FolderCreateView;
+
+ }());
+
+/***/ },
+/* 96 */
+/*!*************************************************!*\
+ !*** ./dev/View/Popup/KeyboardShortcutsHelp.js ***!
+ \*************************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ key = __webpack_require__(/*! key */ 18),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function KeyboardShortcutsHelpPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsKeyboardShortcutsHelp');
+
+ this.sDefaultKeyScope = Enums.KeyState.PopupKeyboardShortcutsHelp;
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/KeyboardShortcutsHelp', 'PopupsKeyboardShortcutsHelpViewModel'], KeyboardShortcutsHelpPopupView);
+ _.extend(KeyboardShortcutsHelpPopupView.prototype, AbstractView.prototype);
+
+ KeyboardShortcutsHelpPopupView.prototype.onBuild = function (oDom)
+ {
+ key('tab, shift+tab, left, right', Enums.KeyState.PopupKeyboardShortcutsHelp, _.throttle(_.bind(function (event, handler) {
+ if (event && handler)
+ {
+ var
+ $tabs = oDom.find('.nav.nav-tabs > li'),
+ bNext = handler && ('tab' === handler.shortcut || 'right' === handler.shortcut),
+ iIndex = $tabs.index($tabs.filter('.active'))
+ ;
+
+ if (!bNext && iIndex > 0)
+ {
+ iIndex--;
+ }
+ else if (bNext && iIndex < $tabs.length - 1)
+ {
+ iIndex++;
+ }
+ else
+ {
+ iIndex = bNext ? 0 : $tabs.length - 1;
+ }
+
+ $tabs.eq(iIndex).find('a[data-toggle="tab"]').tab('show');
+ return false;
+ }
+ }, this), 100));
+ };
+
+ module.exports = KeyboardShortcutsHelpPopupView;
+
+ }());
+
+/***/ },
+/* 97 */
+/*!************************************!*\
+ !*** ./dev/View/Popup/Template.js ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+ HtmlEditor = __webpack_require__(/*! Common/HtmlEditor */ 45),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function TemplatePopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsTemplate');
+
+ this.editor = null;
+ this.signatureDom = ko.observable(null);
+
+ this.id = ko.observable('');
+
+ this.name = ko.observable('');
+ this.name.error = ko.observable(false);
+ this.name.focus = ko.observable(false);
+
+ this.body = ko.observable('');
+ this.body.loading = ko.observable(false);
+ this.body.error = ko.observable(false);
+
+ this.name.subscribe(function () {
+ this.name.error(false);
+ }, this);
+
+ this.body.subscribe(function () {
+ this.body.error(false);
+ }, this);
+
+ this.submitRequest = ko.observable(false);
+ this.submitError = ko.observable('');
+
+ this.addTemplateCommand = Utils.createCommand(this, function () {
+
+ this.populateBodyFromEditor();
+
+ this.name.error('' === Utils.trim(this.name()));
+ this.body.error('' === Utils.trim(this.body()) ||
+ ':HTML:' === Utils.trim(this.body()));
+
+ if (this.name.error() || this.body.error())
+ {
+ return false;
+ }
+
+ this.submitRequest(true);
+
+ Remote.templateSetup(_.bind(function (sResult, oData) {
+
+ this.submitRequest(false);
+ if (Enums.StorageResultType.Success === sResult && oData)
+ {
+ if (oData.Result)
+ {
+ __webpack_require__(/*! App/User */ 7).default.templates();
+ this.cancelCommand();
+ }
+ else if (oData.ErrorCode)
+ {
+ this.submitError(Translator.getNotification(oData.ErrorCode));
+ }
+ }
+ else
+ {
+ this.submitError(Translator.getNotification(Enums.Notification.UnknownError));
+ }
+
+ }, this), this.id(), this.name(), this.body());
+
+ return true;
+
+ }, function () {
+ return !this.submitRequest();
+ });
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/Template'], TemplatePopupView);
+ _.extend(TemplatePopupView.prototype, AbstractView.prototype);
+
+ TemplatePopupView.prototype.clearPopup = function ()
+ {
+ this.id('');
+
+ this.name('');
+ this.name.error(false);
+
+ this.body('');
+ this.body.loading(false);
+ this.body.error(false);
+
+ this.submitRequest(false);
+ this.submitError('');
+
+ if (this.editor)
+ {
+ this.editor.setPlain('', false);
+ }
+ };
+
+ TemplatePopupView.prototype.populateBodyFromEditor = function ()
+ {
+ if (this.editor)
+ {
+ this.body(this.editor.getDataWithHtmlMark());
+ }
+ };
+
+ TemplatePopupView.prototype.editorSetBody = function (sBody)
+ {
+ if (!this.editor && this.signatureDom())
+ {
+ var self = this;
+ this.editor = new HtmlEditor(self.signatureDom(), function () {
+ self.populateBodyFromEditor();
+ }, function () {
+ self.editor.setHtmlOrPlain(sBody);
+ });
+ }
+ else
+ {
+ this.editor.setHtmlOrPlain(sBody);
+ }
+ };
+
+ TemplatePopupView.prototype.onShow = function (oTemplate)
+ {
+ var self = this;
+
+ this.clearPopup();
+
+ if (oTemplate && oTemplate.id)
+ {
+ this.id(oTemplate.id);
+ this.name(oTemplate.name);
+ this.body(oTemplate.body);
+
+ if (oTemplate.populated)
+ {
+ self.editorSetBody(this.body());
+ }
+ else
+ {
+ this.body.loading(true);
+ self.body.error(false);
+
+ Remote.templateGetById(function (sResult, oData) {
+
+ self.body.loading(false);
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result &&
+ 'Object/Template' === oData.Result['@Object'] && Utils.isNormal(oData.Result['Body']))
+ {
+ oTemplate.body = oData.Result['Body'];
+ oTemplate.populated = true;
+
+ self.body(oTemplate.body);
+ self.body.error(false);
+ }
+ else
+ {
+ self.body('');
+ self.body.error(true);
+ }
+
+ self.editorSetBody(self.body());
+
+ }, this.id());
+ }
+ }
+ else
+ {
+ self.editorSetBody('');
+ }
+ };
+
+ TemplatePopupView.prototype.onShowWithDelay = function ()
+ {
+ this.name.focus(true);
+ };
+
+ module.exports = TemplatePopupView;
+
+ }());
+
+/***/ },
+/* 98 */
+/*!**************************************************!*\
+ !*** ./dev/View/Popup/TwoFactorConfiguration.js ***!
+ \**************************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function TwoFactorConfigurationPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsTwoFactorConfiguration');
+
+ this.lock = ko.observable(false);
+
+ this.capaTwoFactor = Settings.capa(Enums.Capa.TwoFactor);
+
+ this.processing = ko.observable(false);
+ this.clearing = ko.observable(false);
+ this.secreting = ko.observable(false);
+
+ this.viewUser = ko.observable('');
+ this.twoFactorStatus = ko.observable(false);
+
+ this.twoFactorTested = ko.observable(false);
+
+ this.viewSecret = ko.observable('');
+ this.viewBackupCodes = ko.observable('');
+ this.viewUrl = ko.observable('');
+
+ this.viewEnable_ = ko.observable(false);
+
+ this.viewEnable = ko.computed({
+ 'owner': this,
+ 'read': this.viewEnable_,
+ 'write': function (bValue) {
+
+ var self = this;
+
+ bValue = !!bValue;
+
+ if (bValue && this.twoFactorTested())
+ {
+ this.viewEnable_(bValue);
+
+ Remote.enableTwoFactor(function (sResult, oData) {
+ if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result)
+ {
+ self.viewEnable_(false);
+ }
+
+ }, true);
+ }
+ else
+ {
+ if (!bValue)
+ {
+ this.viewEnable_(bValue);
+ }
+
+ Remote.enableTwoFactor(function (sResult, oData) {
+ if (Enums.StorageResultType.Success !== sResult || !oData || !oData.Result)
+ {
+ self.viewEnable_(false);
+ }
+
+ }, false);
+ }
+ }
+ });
+
+ this.viewTwoFactorEnableTooltip = ko.computed(function () {
+ Translator.trigger();
+ return this.twoFactorTested() || this.viewEnable_() ? '' :
+ Translator.i18n('POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_TEST_BEFORE_DESC');
+ }, this);
+
+ this.viewTwoFactorStatus = ko.computed(function () {
+ Translator.trigger();
+ return Translator.i18n(
+ this.twoFactorStatus() ?
+ 'POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_CONFIGURED_DESC' :
+ 'POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC'
+ );
+ }, this);
+
+ this.twoFactorAllowedEnable = ko.computed(function () {
+ return this.viewEnable() || this.twoFactorTested();
+ }, this);
+
+ this.onResult = _.bind(this.onResult, this);
+ this.onShowSecretResult = _.bind(this.onShowSecretResult, this);
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/TwoFactorConfiguration', 'TwoFactorConfigurationPopupView'], TwoFactorConfigurationPopupView);
+ _.extend(TwoFactorConfigurationPopupView.prototype, AbstractView.prototype);
+
+
+ TwoFactorConfigurationPopupView.prototype.showSecret = function ()
+ {
+ this.secreting(true);
+ Remote.showTwoFactorSecret(this.onShowSecretResult);
+ };
+
+ TwoFactorConfigurationPopupView.prototype.hideSecret = function ()
+ {
+ this.viewSecret('');
+ this.viewBackupCodes('');
+ this.viewUrl('');
+ };
+
+ TwoFactorConfigurationPopupView.prototype.createTwoFactor = function ()
+ {
+ this.processing(true);
+ Remote.createTwoFactor(this.onResult);
+ };
+
+ TwoFactorConfigurationPopupView.prototype.logout = function ()
+ {
+ __webpack_require__(/*! App/User */ 7).default.logout();
+ };
+
+ TwoFactorConfigurationPopupView.prototype.testTwoFactor = function ()
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/TwoFactorTest */ 150), [this.twoFactorTested]);
+ };
+
+ TwoFactorConfigurationPopupView.prototype.clearTwoFactor = function ()
+ {
+ this.viewSecret('');
+ this.viewBackupCodes('');
+ this.viewUrl('');
+
+ this.twoFactorTested(false);
+
+ this.clearing(true);
+ Remote.clearTwoFactor(this.onResult);
+ };
+
+ TwoFactorConfigurationPopupView.prototype.onShow = function (bLock)
+ {
+ this.lock(!!bLock);
+
+ this.viewSecret('');
+ this.viewBackupCodes('');
+ this.viewUrl('');
+ };
+
+ TwoFactorConfigurationPopupView.prototype.onHide = function ()
+ {
+ if (this.lock())
+ {
+ window.location.reload();
+ }
+ };
+
+ TwoFactorConfigurationPopupView.prototype.onResult = function (sResult, oData)
+ {
+ this.processing(false);
+ this.clearing(false);
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ this.viewUser(Utils.pString(oData.Result.User));
+ this.viewEnable_(!!oData.Result.Enable);
+ this.twoFactorStatus(!!oData.Result.IsSet);
+ this.twoFactorTested(!!oData.Result.Tested);
+
+ this.viewSecret(Utils.pString(oData.Result.Secret));
+ this.viewBackupCodes(Utils.pString(oData.Result.BackupCodes).replace(/[\s]+/g, ' '));
+ this.viewUrl(Utils.pString(oData.Result.Url));
+ }
+ else
+ {
+ this.viewUser('');
+ this.viewEnable_(false);
+ this.twoFactorStatus(false);
+ this.twoFactorTested(false);
+
+ this.viewSecret('');
+ this.viewBackupCodes('');
+ this.viewUrl('');
+ }
+ };
+
+ TwoFactorConfigurationPopupView.prototype.onShowSecretResult = function (sResult, oData)
+ {
+ this.secreting(false);
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ this.viewSecret(Utils.pString(oData.Result.Secret));
+ this.viewUrl(Utils.pString(oData.Result.Url));
+ }
+ else
+ {
+ this.viewSecret('');
+ this.viewUrl('');
+ }
+ };
+
+ TwoFactorConfigurationPopupView.prototype.onBuild = function ()
+ {
+ if (this.capaTwoFactor)
+ {
+ this.processing(true);
+ Remote.getTwoFactor(this.onResult);
+ }
+ };
+
+ module.exports = TwoFactorConfigurationPopupView;
+
+ }());
+
+/***/ },
+/* 99 */
+/*!*************************************************!*\
+ !*** ./dev/View/User/AbstractSystemDropDown.js ***!
+ \*************************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+ key = __webpack_require__(/*! key */ 18),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+ Events = __webpack_require__(/*! Common/Events */ 25),
+
+ AppStore = __webpack_require__(/*! Stores/User/App */ 24),
+ AccountStore = __webpack_require__(/*! Stores/User/Account */ 31),
+ MessageStore = __webpack_require__(/*! Stores/User/Message */ 32),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function AbstractSystemDropDownUserView()
+ {
+ AbstractView.call(this, 'Right', 'SystemDropDown');
+
+ this.logoImg = Utils.trim(Settings.settingsGet('UserLogo'));
+ this.logoTitle = Utils.trim(Settings.settingsGet('UserLogoTitle'));
+
+ this.mobile = !!Settings.appSettingsGet('mobile');
+ this.mobileDevice = !!Settings.appSettingsGet('mobileDevice');
+
+ this.allowSettings = !!Settings.capa(Enums.Capa.Settings);
+ this.allowHelp = !!Settings.capa(Enums.Capa.Help);
+
+ this.currentAudio = AppStore.currentAudio;
+
+ this.accountEmail = AccountStore.email;
+
+ this.accounts = AccountStore.accounts;
+ this.accountsUnreadCount = AccountStore.accountsUnreadCount;
+
+ this.accountMenuDropdownTrigger = ko.observable(false);
+ this.capaAdditionalAccounts = ko.observable(Settings.capa(Enums.Capa.AdditionalAccounts));
+
+ this.accountClick = _.bind(this.accountClick, this);
+
+ this.accountClick = _.bind(this.accountClick, this);
+
+ Events.sub('audio.stop', function () {
+ AppStore.currentAudio('');
+ });
+
+ Events.sub('audio.start', function (sName) {
+ AppStore.currentAudio(sName);
+ });
+ }
+
+ _.extend(AbstractSystemDropDownUserView.prototype, AbstractView.prototype);
+
+ AbstractSystemDropDownUserView.prototype.stopPlay = function ()
+ {
+ Events.pub('audio.api.stop');
+ };
+
+ AbstractSystemDropDownUserView.prototype.accountClick = function (oAccount, oEvent)
+ {
+ if (oAccount && oEvent && !Utils.isUnd(oEvent.which) && 1 === oEvent.which)
+ {
+ AccountStore.accounts.loading(true);
+
+ _.delay(function () {
+ AccountStore.accounts.loading(false);
+ }, 1000);
+ }
+
+ return true;
+ };
+
+ AbstractSystemDropDownUserView.prototype.emailTitle = function ()
+ {
+ return AccountStore.email();
+ };
+
+ AbstractSystemDropDownUserView.prototype.settingsClick = function ()
+ {
+ if (Settings.capa(Enums.Capa.Settings))
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).setHash(Links.settings());
+ }
+ };
+
+ AbstractSystemDropDownUserView.prototype.settingsHelp = function ()
+ {
+ if (Settings.capa(Enums.Capa.Help))
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/KeyboardShortcutsHelp */ 96));
+ }
+ };
+
+ AbstractSystemDropDownUserView.prototype.addAccountClick = function ()
+ {
+ if (this.capaAdditionalAccounts())
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Account */ 61));
+ }
+ };
+
+ AbstractSystemDropDownUserView.prototype.logoutClick = function ()
+ {
+ __webpack_require__(/*! App/User */ 7).default.logout();
+ };
+
+ AbstractSystemDropDownUserView.prototype.onBuild = function ()
+ {
+ var self = this;
+ key('`', [Enums.KeyState.MessageList, Enums.KeyState.MessageView, Enums.KeyState.Settings], function () {
+ if (self.viewModelVisibility())
+ {
+ MessageStore.messageFullScreenMode(false);
+
+ self.accountMenuDropdownTrigger(true);
+ }
+ });
+
+ // shortcuts help
+ key('shift+/', [Enums.KeyState.MessageList, Enums.KeyState.MessageView, Enums.KeyState.Settings], function () {
+ if (self.viewModelVisibility())
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/KeyboardShortcutsHelp */ 96));
+ return false;
+ }
+ });
+ };
+
+ module.exports = AbstractSystemDropDownUserView;
+
+ }());
+
+/***/ },
+/* 100 */
+/*!*********************************!*\
+ !*** ./dev/Common/Selector.jsx ***!
+ \*********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.Selector = undefined;
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _ko = __webpack_require__(/*! ko */ 2);
+
+ var _ko2 = _interopRequireDefault(_ko);
+
+ var _Enums = __webpack_require__(/*! Common/Enums */ 4);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var Selector = function () {
+ /**
+ * @constructor
+ * @param {koProperty} koList
+ * @param {koProperty} koSelectedItem
+ * @param {koProperty} koFocusedItem
+ * @param {string} sItemSelector
+ * @param {string} sItemSelectedSelector
+ * @param {string} sItemCheckedSelector
+ * @param {string} sItemFocusedSelector
+ */
+
+ function Selector(koList, koSelectedItem, koFocusedItem, sItemSelector, sItemSelectedSelector, sItemCheckedSelector, sItemFocusedSelector) {
+ var _this = this;
+
+ _classCallCheck(this, Selector);
+
+ this.actionClick = function (item) {
+ var event = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1];
+
+
+ if (item) {
+ var click = true;
+ if (event) {
+ if (event.shiftKey && !(event.ctrlKey || event.metaKey) && !event.altKey) {
+ click = false;
+ if ('' === this.sLastUid) {
+ this.sLastUid = this.getItemUid(item);
+ }
+
+ item.checked(!item.checked());
+ this.eventClickFunction(item, event);
+
+ this.focusedItem(item);
+ } else if ((event.ctrlKey || event.metaKey) && !event.shiftKey && !event.altKey) {
+ click = false;
+ this.focusedItem(item);
+
+ if (this.selectedItem() && item !== this.selectedItem()) {
+ this.selectedItem().checked(true);
+ }
+
+ item.checked(!item.checked());
+ }
+ }
+
+ if (click) {
+ this.selectMessageItem(item);
+ }
+ }
+ };
+
+ this.list = koList;
+
+ this.listChecked = _ko2.default.computed(function () {
+ return _common._.filter(_this.list(), function (item) {
+ return item.checked();
+ });
+ }, this).extend({ rateLimit: 0 });
+
+ this.isListChecked = _ko2.default.computed(function () {
+ return 0 < _this.listChecked().length;
+ });
+
+ this.focusedItem = koFocusedItem || _ko2.default.observable(null);
+ this.selectedItem = koSelectedItem || _ko2.default.observable(null);
+ this.selectedItemUseCallback = true;
+
+ this.itemSelectedThrottle = _common._.debounce(_common._.bind(this.itemSelected, this), 300);
+
+ this.listChecked.subscribe(function (items) {
+ if (0 < items.length) {
+ if (null === _this.selectedItem()) {
+ if (_this.selectedItem.valueHasMutated) {
+ _this.selectedItem.valueHasMutated();
+ }
+ } else {
+ _this.selectedItem(null);
+ }
+ } else if (_this.autoSelect() && _this.focusedItem()) {
+ _this.selectedItem(_this.focusedItem());
+ }
+ }, this);
+
+ this.selectedItem.subscribe(function (item) {
+
+ if (item) {
+ if (_this.isListChecked()) {
+ _common._.each(_this.listChecked(), function (subItem) {
+ subItem.checked(false);
+ });
+ }
+
+ if (_this.selectedItemUseCallback) {
+ _this.itemSelectedThrottle(item);
+ }
+ } else if (_this.selectedItemUseCallback) {
+ _this.itemSelected(null);
+ }
+ }, this);
+
+ this.selectedItem = this.selectedItem.extend({ toggleSubscribe: [null, function (prev) {
+ if (prev) {
+ prev.selected(false);
+ }
+ }, function (next) {
+ if (next) {
+ next.selected(true);
+ }
+ }] });
+
+ this.focusedItem = this.focusedItem.extend({ toggleSubscribe: [null, function (prev) {
+ if (prev) {
+ prev.focused(false);
+ }
+ }, function (next) {
+ if (next) {
+ next.focused(true);
+ }
+ }] });
+
+ this.iSelectNextHelper = 0;
+ this.iFocusedNextHelper = 0;
+ this.oContentVisible = null;
+ this.oContentScrollable = null;
+
+ this.sItemSelector = sItemSelector;
+ this.sItemSelectedSelector = sItemSelectedSelector;
+ this.sItemCheckedSelector = sItemCheckedSelector;
+ this.sItemFocusedSelector = sItemFocusedSelector;
+
+ this.sLastUid = '';
+ this.oCallbacks = {};
+
+ this.emptyFunction = function () {};
+ this.emptyTrueFunction = function () {
+ return true;
+ };
+
+ this.focusedItem.subscribe(function (item) {
+ if (item) {
+ _this.sLastUid = _this.getItemUid(item);
+ }
+ }, this);
+
+ var aCache = [],
+ aCheckedCache = [],
+ mFocused = null,
+ mSelected = null;
+
+ this.list.subscribe(function (items) {
+
+ if (_Utils2.default.isArray(items)) {
+ _common._.each(items, function (item) {
+ if (item) {
+ var uid = _this.getItemUid(item);
+
+ aCache.push(uid);
+ if (item.checked()) {
+ aCheckedCache.push(uid);
+ }
+ if (null === mFocused && item.focused()) {
+ mFocused = uid;
+ }
+ if (null === mSelected && item.selected()) {
+ mSelected = uid;
+ }
+ }
+ });
+ }
+ }, this, 'beforeChange');
+
+ this.list.subscribe(function (aItems) {
+
+ var oTemp = null,
+ bGetNext = false,
+ aUids = [],
+ mNextFocused = mFocused,
+ bChecked = false,
+ bSelected = false,
+ iLen = 0;
+
+ _this.selectedItemUseCallback = false;
+
+ _this.focusedItem(null);
+ _this.selectedItem(null);
+
+ if (_Utils2.default.isArray(aItems)) {
+ iLen = aCheckedCache.length;
+
+ _common._.each(aItems, function (oItem) {
+
+ var sUid = _this.getItemUid(oItem);
+ aUids.push(sUid);
+
+ if (null !== mFocused && mFocused === sUid) {
+ _this.focusedItem(oItem);
+ mFocused = null;
+ }
+
+ if (0 < iLen && -1 < _Utils2.default.inArray(sUid, aCheckedCache)) {
+ bChecked = true;
+ oItem.checked(true);
+ iLen--;
+ }
+
+ if (!bChecked && null !== mSelected && mSelected === sUid) {
+ bSelected = true;
+ _this.selectedItem(oItem);
+ mSelected = null;
+ }
+ });
+
+ _this.selectedItemUseCallback = true;
+
+ if (!bChecked && !bSelected && _this.autoSelect()) {
+ if (_this.focusedItem()) {
+ _this.selectedItem(_this.focusedItem());
+ } else if (0 < aItems.length) {
+ if (null !== mNextFocused) {
+ bGetNext = false;
+ mNextFocused = _common._.find(aCache, function (sUid) {
+ if (bGetNext && -1 < _Utils2.default.inArray(sUid, aUids)) {
+ return sUid;
+ } else if (mNextFocused === sUid) {
+ bGetNext = true;
+ }
+ return false;
+ });
+
+ if (mNextFocused) {
+ oTemp = _common._.find(aItems, function (oItem) {
+ return mNextFocused === _this.getItemUid(oItem);
+ });
+ }
+ }
+
+ _this.selectedItem(oTemp || null);
+ _this.focusedItem(_this.selectedItem());
+ }
+ }
+
+ if ((0 !== _this.iSelectNextHelper || 0 !== _this.iFocusedNextHelper) && 0 < aItems.length && !_this.focusedItem()) {
+ oTemp = null;
+ if (0 !== _this.iFocusedNextHelper) {
+ oTemp = aItems[-1 === _this.iFocusedNextHelper ? aItems.length - 1 : 0] || null;
+ }
+
+ if (!oTemp && 0 !== _this.iSelectNextHelper) {
+ oTemp = aItems[-1 === _this.iSelectNextHelper ? aItems.length - 1 : 0] || null;
+ }
+
+ if (oTemp) {
+ if (0 !== _this.iSelectNextHelper) {
+ _this.selectedItem(oTemp || null);
+ }
+
+ _this.focusedItem(oTemp || null);
+
+ _this.scrollToFocused();
+
+ _common._.delay(function () {
+ return _this.scrollToFocused();
+ }, 100);
+ }
+
+ _this.iSelectNextHelper = 0;
+ _this.iFocusedNextHelper = 0;
+ }
+ }
+
+ aCache = [];
+ aCheckedCache = [];
+ mFocused = null;
+ mSelected = null;
+ }, this);
+ }
+
+ Selector.prototype.itemSelected = function itemSelected(item) {
+
+ if (this.isListChecked()) {
+ if (!item) {
+ (this.oCallbacks.onItemSelect || this.emptyFunction)(item || null);
+ }
+ } else {
+ if (item) {
+ (this.oCallbacks.onItemSelect || this.emptyFunction)(item);
+ }
+ }
+ };
+
+ /**
+ * @param {boolean} forceSelect
+ */
+
+
+ Selector.prototype.goDown = function goDown(forceSelect) {
+ this.newSelectPosition(_Enums.EventKeyCode.Down, false, forceSelect);
+ };
+
+ /**
+ * @param {boolean} forceSelect
+ */
+
+
+ Selector.prototype.goUp = function goUp(forceSelect) {
+ this.newSelectPosition(_Enums.EventKeyCode.Up, false, forceSelect);
+ };
+
+ Selector.prototype.unselect = function unselect() {
+ this.selectedItem(null);
+ this.focusedItem(null);
+ };
+
+ Selector.prototype.init = function init(contentVisible, contentScrollable) {
+ var _this2 = this;
+
+ var keyScope = arguments.length <= 2 || arguments[2] === undefined ? 'all' : arguments[2];
+
+
+ this.oContentVisible = contentVisible;
+ this.oContentScrollable = contentScrollable;
+
+ if (this.oContentVisible && this.oContentScrollable) {
+ (0, _common.$)(this.oContentVisible).on('selectstart', function (event) {
+ if (event && event.preventDefault) {
+ event.preventDefault();
+ }
+ }).on('click', this.sItemSelector, function (event) {
+ _this2.actionClick(_ko2.default.dataFor(event.currentTarget), event);
+ }).on('click', this.sItemCheckedSelector, function (event) {
+ var item = _ko2.default.dataFor(event.currentTarget);
+ if (item) {
+ if (event && event.shiftKey) {
+ _this2.actionClick(item, event);
+ } else {
+ _this2.focusedItem(item);
+ item.checked(!item.checked());
+ }
+ }
+ });
+
+ (0, _common.key)('enter', keyScope, function () {
+ if (_this2.focusedItem() && !_this2.focusedItem().selected()) {
+ _this2.actionClick(_this2.focusedItem());
+ return false;
+ }
+
+ return true;
+ });
+
+ (0, _common.key)('ctrl+up, command+up, ctrl+down, command+down', keyScope, function () {
+ return false;
+ });
+
+ (0, _common.key)('up, shift+up, down, shift+down, home, end, pageup, pagedown, insert, space', keyScope, function (event, handler) {
+ if (event && handler && handler.shortcut) {
+ var eventKey = 0;
+ switch (handler.shortcut) {
+ case 'up':
+ case 'shift+up':
+ eventKey = _Enums.EventKeyCode.Up;
+ break;
+ case 'down':
+ case 'shift+down':
+ eventKey = _Enums.EventKeyCode.Down;
+ break;
+ case 'insert':
+ eventKey = _Enums.EventKeyCode.Insert;
+ break;
+ case 'space':
+ eventKey = _Enums.EventKeyCode.Space;
+ break;
+ case 'home':
+ eventKey = _Enums.EventKeyCode.Home;
+ break;
+ case 'end':
+ eventKey = _Enums.EventKeyCode.End;
+ break;
+ case 'pageup':
+ eventKey = _Enums.EventKeyCode.PageUp;
+ break;
+ case 'pagedown':
+ eventKey = _Enums.EventKeyCode.PageDown;
+ break;
+ }
+
+ if (0 < eventKey) {
+ _this2.newSelectPosition(eventKey, _common.key.shift);
+ return false;
+ }
+ }
+ });
+ }
+ };
+
+ /**
+ * @return {boolean}
+ */
+
+
+ Selector.prototype.autoSelect = function autoSelect() {
+ return !!(this.oCallbacks.onAutoSelect || this.emptyTrueFunction)();
+ };
+
+ /**
+ * @param {boolean} up
+ */
+
+
+ Selector.prototype.doUpUpOrDownDown = function doUpUpOrDownDown(up) {
+ (this.oCallbacks.onUpUpOrDownDown || this.emptyTrueFunction)(!!up);
+ };
+
+ /**
+ * @param {Object} oItem
+ * @return {string}
+ */
+
+
+ Selector.prototype.getItemUid = function getItemUid(item) {
+
+ var uid = '';
+
+ var getItemUidCallback = this.oCallbacks.onItemGetUid || null;
+ if (getItemUidCallback && item) {
+ uid = getItemUidCallback(item);
+ }
+
+ return uid.toString();
+ };
+
+ /**
+ * @param {number} iEventKeyCode
+ * @param {boolean} bShiftKey
+ * @param {boolean=} bForceSelect = false
+ */
+
+
+ Selector.prototype.newSelectPosition = function newSelectPosition(iEventKeyCode, bShiftKey, bForceSelect) {
+
+ var iIndex = 0,
+ iPageStep = 10,
+ bNext = false,
+ bStop = false,
+ oResult = null,
+ aList = this.list(),
+ iListLen = aList ? aList.length : 0,
+ oFocused = this.focusedItem();
+
+ if (0 < iListLen) {
+ if (!oFocused) {
+ if (_Enums.EventKeyCode.Down === iEventKeyCode || _Enums.EventKeyCode.Insert === iEventKeyCode || _Enums.EventKeyCode.Space === iEventKeyCode || _Enums.EventKeyCode.Home === iEventKeyCode || _Enums.EventKeyCode.PageUp === iEventKeyCode) {
+ oResult = aList[0];
+ } else if (_Enums.EventKeyCode.Up === iEventKeyCode || _Enums.EventKeyCode.End === iEventKeyCode || _Enums.EventKeyCode.PageDown === iEventKeyCode) {
+ oResult = aList[aList.length - 1];
+ }
+ } else if (oFocused) {
+ if (_Enums.EventKeyCode.Down === iEventKeyCode || _Enums.EventKeyCode.Up === iEventKeyCode || _Enums.EventKeyCode.Insert === iEventKeyCode || _Enums.EventKeyCode.Space === iEventKeyCode) {
+ _common._.each(aList, function (item) {
+ if (!bStop) {
+ switch (iEventKeyCode) {
+ case _Enums.EventKeyCode.Up:
+ if (oFocused === item) {
+ bStop = true;
+ } else {
+ oResult = item;
+ }
+ break;
+ case _Enums.EventKeyCode.Down:
+ case _Enums.EventKeyCode.Insert:
+ if (bNext) {
+ oResult = item;
+ bStop = true;
+ } else if (oFocused === item) {
+ bNext = true;
+ }
+ break;
+ }
+ }
+ });
+
+ if (!oResult && (_Enums.EventKeyCode.Down === iEventKeyCode || _Enums.EventKeyCode.Up === iEventKeyCode)) {
+ this.doUpUpOrDownDown(_Enums.EventKeyCode.Up === iEventKeyCode);
+ }
+ } else if (_Enums.EventKeyCode.Home === iEventKeyCode || _Enums.EventKeyCode.End === iEventKeyCode) {
+ if (_Enums.EventKeyCode.Home === iEventKeyCode) {
+ oResult = aList[0];
+ } else if (_Enums.EventKeyCode.End === iEventKeyCode) {
+ oResult = aList[aList.length - 1];
+ }
+ } else if (_Enums.EventKeyCode.PageDown === iEventKeyCode) {
+ for (; iIndex < iListLen; iIndex++) {
+ if (oFocused === aList[iIndex]) {
+ iIndex += iPageStep;
+ iIndex = iListLen - 1 < iIndex ? iListLen - 1 : iIndex;
+ oResult = aList[iIndex];
+ break;
+ }
+ }
+ } else if (_Enums.EventKeyCode.PageUp === iEventKeyCode) {
+ for (iIndex = iListLen; iIndex >= 0; iIndex--) {
+ if (oFocused === aList[iIndex]) {
+ iIndex -= iPageStep;
+ iIndex = 0 > iIndex ? 0 : iIndex;
+ oResult = aList[iIndex];
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (oResult) {
+ this.focusedItem(oResult);
+
+ if (oFocused) {
+ if (bShiftKey) {
+ if (_Enums.EventKeyCode.Up === iEventKeyCode || _Enums.EventKeyCode.Down === iEventKeyCode) {
+ oFocused.checked(!oFocused.checked());
+ }
+ } else if (_Enums.EventKeyCode.Insert === iEventKeyCode || _Enums.EventKeyCode.Space === iEventKeyCode) {
+ oFocused.checked(!oFocused.checked());
+ }
+ }
+
+ if ((this.autoSelect() || !!bForceSelect) && !this.isListChecked() && _Enums.EventKeyCode.Space !== iEventKeyCode) {
+ this.selectedItem(oResult);
+ }
+
+ this.scrollToFocused();
+ } else if (oFocused) {
+ if (bShiftKey && (_Enums.EventKeyCode.Up === iEventKeyCode || _Enums.EventKeyCode.Down === iEventKeyCode)) {
+ oFocused.checked(!oFocused.checked());
+ } else if (_Enums.EventKeyCode.Insert === iEventKeyCode || _Enums.EventKeyCode.Space === iEventKeyCode) {
+ oFocused.checked(!oFocused.checked());
+ }
+
+ this.focusedItem(oFocused);
+ }
+ };
+
+ /**
+ * @return {boolean}
+ */
+
+
+ Selector.prototype.scrollToFocused = function scrollToFocused() {
+
+ if (!this.oContentVisible || !this.oContentScrollable) {
+ return false;
+ }
+
+ var offset = 20,
+ list = this.list(),
+ $focused = (0, _common.$)(this.sItemFocusedSelector, this.oContentScrollable),
+ pos = $focused.position(),
+ visibleHeight = this.oContentVisible.height(),
+ focusedHeight = $focused.outerHeight();
+
+ if (list && list[0] && list[0].focused()) {
+ this.oContentScrollable.scrollTop(0);
+ return true;
+ } else if (pos && (pos.top < 0 || pos.top + focusedHeight > visibleHeight)) {
+ this.oContentScrollable.scrollTop(pos.top < 0 ? this.oContentScrollable.scrollTop() + pos.top - offset : this.oContentScrollable.scrollTop() + pos.top - visibleHeight + focusedHeight + offset);
+
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {boolean=} fast = false
+ * @return {boolean}
+ */
+
+
+ Selector.prototype.scrollToTop = function scrollToTop() {
+ var fast = arguments.length <= 0 || arguments[0] === undefined ? false : arguments[0];
+
+
+ if (!this.oContentVisible || !this.oContentScrollable) {
+ return false;
+ }
+
+ if (fast || 50 > this.oContentScrollable.scrollTop()) {
+ this.oContentScrollable.scrollTop(0);
+ } else {
+ this.oContentScrollable.stop().animate({ scrollTop: 0 }, 200);
+ }
+
+ return true;
+ };
+
+ Selector.prototype.eventClickFunction = function eventClickFunction(item, event) {
+
+ var index = 0,
+ length = 0,
+ changeRange = false,
+ isInRange = false,
+ list = [],
+ checked = false,
+ listItem = null,
+ lineUid = '';
+
+ var uid = this.getItemUid(item);
+ if (event && event.shiftKey) {
+ if ('' !== uid && '' !== this.sLastUid && uid !== this.sLastUid) {
+ list = this.list();
+ checked = item.checked();
+
+ for (index = 0, length = list.length; index < length; index++) {
+ listItem = list[index];
+ lineUid = this.getItemUid(listItem);
+
+ changeRange = false;
+ if (lineUid === this.sLastUid || lineUid === uid) {
+ changeRange = true;
+ }
+
+ if (changeRange) {
+ isInRange = !isInRange;
+ }
+
+ if (isInRange || changeRange) {
+ listItem.checked(checked);
+ }
+ }
+ }
+ }
+
+ this.sLastUid = '' === uid ? '' : uid;
+ };
+
+ /**
+ * @param {Object} item
+ * @param {Object=} event
+ */
+
+
+ Selector.prototype.on = function on(eventName, callback) {
+ this.oCallbacks[eventName] = callback;
+ };
+
+ Selector.prototype.selectMessageItem = function selectMessageItem(messageItem) {
+ this.focusedItem(messageItem);
+ this.selectedItem(messageItem);
+ this.scrollToFocused();
+ };
+
+ return Selector;
+ }();
+
+ exports.Selector = Selector;
+ exports.default = Selector;
+
+ module.exports = Selector;
+
+/***/ },
+/* 101 */
+/*!******************************!*\
+ !*** ./dev/Model/Account.js ***!
+ \******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ AbstractModel = __webpack_require__(/*! Knoin/AbstractModel */ 27)
+ ;
+
+ /**
+ * @constructor
+ *
+ * @param {string} sEmail
+ * @param {boolean=} bCanBeDelete = true
+ * @param {number=} iCount = 0
+ */
+ function AccountModel(sEmail, bCanBeDelete, iCount)
+ {
+ AbstractModel.call(this, 'AccountModel');
+
+ this.email = sEmail;
+
+ this.count = ko.observable(iCount || 0);
+
+ this.deleteAccess = ko.observable(false);
+ this.canBeDeleted = ko.observable(Utils.isUnd(bCanBeDelete) ? true : !!bCanBeDelete);
+ this.canBeEdit = this.canBeDeleted;
+ }
+
+ _.extend(AccountModel.prototype, AbstractModel.prototype);
+
+ /**
+ * @type {string}
+ */
+ AccountModel.prototype.email = '';
+
+ /**
+ * @return {string}
+ */
+ AccountModel.prototype.changeAccountLink = function ()
+ {
+ return __webpack_require__(/*! Common/Links */ 12).change(this.email);
+ };
+
+ module.exports = AccountModel;
+
+ }());
+
+/***/ },
+/* 102 */
+/*!****************************************!*\
+ !*** ./dev/Model/ComposeAttachment.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ AttachmentModel = __webpack_require__(/*! Model/Attachment */ 86),
+
+ AbstractModel = __webpack_require__(/*! Knoin/AbstractModel */ 27)
+ ;
+
+ /**
+ * @constructor
+ * @param {string} sId
+ * @param {string} sFileName
+ * @param {?number=} nSize
+ * @param {boolean=} bInline
+ * @param {boolean=} bLinked
+ * @param {string=} sCID
+ * @param {string=} sContentLocation
+ */
+ function ComposeAttachmentModel(sId, sFileName, nSize, bInline, bLinked, sCID, sContentLocation)
+ {
+ AbstractModel.call(this, 'ComposeAttachmentModel');
+
+ this.id = sId;
+ this.isInline = Utils.isUnd(bInline) ? false : !!bInline;
+ this.isLinked = Utils.isUnd(bLinked) ? false : !!bLinked;
+ this.CID = Utils.isUnd(sCID) ? '' : sCID;
+ this.contentLocation = Utils.isUnd(sContentLocation) ? '' : sContentLocation;
+ this.fromMessage = false;
+
+ this.fileName = ko.observable(sFileName);
+ this.size = ko.observable(Utils.isUnd(nSize) ? null : nSize);
+ this.tempName = ko.observable('');
+
+ this.progress = ko.observable(0);
+ this.error = ko.observable('');
+ this.waiting = ko.observable(true);
+ this.uploading = ko.observable(false);
+ this.enabled = ko.observable(true);
+ this.complete = ko.observable(false);
+
+ this.progressText = ko.computed(function () {
+ var iP = this.progress();
+ return 0 === iP ? '' : '' + (98 < iP ? 100 : iP) + '%';
+ }, this);
+
+ this.progressStyle = ko.computed(function () {
+ var iP = this.progress();
+ return 0 === iP ? '' : 'width:' + (98 < iP ? 100 : iP) + '%';
+ }, this);
+
+ this.title = ko.computed(function () {
+ var sError = this.error();
+ return '' !== sError ? sError : this.fileName();
+ }, this);
+
+ this.friendlySize = ko.computed(function () {
+ var mSize = this.size();
+ return null === mSize ? '' : Utils.friendlySize(this.size());
+ }, this);
+
+ this.mimeType = ko.computed(function () {
+ return Utils.mimeContentType(this.fileName());
+ }, this);
+
+ this.fileExt = ko.computed(function () {
+ return Utils.getFileExtension(this.fileName());
+ }, this);
+
+ this.regDisposables([this.progressText, this.progressStyle, this.title, this.friendlySize, this.mimeType, this.fileExt]);
+ }
+
+ _.extend(ComposeAttachmentModel.prototype, AbstractModel.prototype);
+
+ ComposeAttachmentModel.prototype.id = '';
+ ComposeAttachmentModel.prototype.isInline = false;
+ ComposeAttachmentModel.prototype.isLinked = false;
+ ComposeAttachmentModel.prototype.CID = '';
+ ComposeAttachmentModel.prototype.contentLocation = '';
+ ComposeAttachmentModel.prototype.fromMessage = false;
+ ComposeAttachmentModel.prototype.cancel = Utils.emptyFunction;
+
+ /**
+ * @param {AjaxJsonComposeAttachment} oJsonAttachment
+ * @return {boolean}
+ */
+ ComposeAttachmentModel.prototype.initByUploadJson = function (oJsonAttachment)
+ {
+ var bResult = false;
+ if (oJsonAttachment)
+ {
+ this.fileName(oJsonAttachment.Name);
+ this.size(Utils.isUnd(oJsonAttachment.Size) ? 0 : Utils.pInt(oJsonAttachment.Size));
+ this.tempName(Utils.isUnd(oJsonAttachment.TempName) ? '' : oJsonAttachment.TempName);
+ this.isInline = false;
+
+ bResult = true;
+ }
+
+ return bResult;
+ };
+
+ /**
+ * @return {string}
+ */
+ ComposeAttachmentModel.prototype.iconClass = function ()
+ {
+ return AttachmentModel.staticIconClass(
+ AttachmentModel.staticFileType(this.fileExt(), this.mimeType()))[0];
+ };
+
+ /**
+ * @return {string}
+ */
+ ComposeAttachmentModel.prototype.iconText = function ()
+ {
+ return AttachmentModel.staticIconClass(
+ AttachmentModel.staticFileType(this.fileExt(), this.mimeType()))[1];
+ };
+
+ module.exports = ComposeAttachmentModel;
+
+ }());
+
+/***/ },
+/* 103 */
+/*!******************************!*\
+ !*** ./dev/Model/Contact.js ***!
+ \******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+
+ AbstractModel = __webpack_require__(/*! Knoin/AbstractModel */ 27)
+ ;
+
+ /**
+ * @constructor
+ */
+ function ContactModel()
+ {
+ AbstractModel.call(this, 'ContactModel');
+
+ this.idContact = 0;
+ this.display = '';
+ this.properties = [];
+ this.readOnly = false;
+
+ this.focused = ko.observable(false);
+ this.selected = ko.observable(false);
+ this.checked = ko.observable(false);
+ this.deleted = ko.observable(false);
+ }
+
+ _.extend(ContactModel.prototype, AbstractModel.prototype);
+
+ /**
+ * @return {Array|null}
+ */
+ ContactModel.prototype.getNameAndEmailHelper = function ()
+ {
+ var
+ sName = '',
+ sEmail = ''
+ ;
+
+ if (Utils.isNonEmptyArray(this.properties))
+ {
+ _.each(this.properties, function (aProperty) {
+ if (aProperty)
+ {
+ if (Enums.ContactPropertyType.FirstName === aProperty[0])
+ {
+ sName = Utils.trim(aProperty[1] + ' ' + sName);
+ }
+ else if (Enums.ContactPropertyType.LastName === aProperty[0])
+ {
+ sName = Utils.trim(sName + ' ' + aProperty[1]);
+ }
+ else if ('' === sEmail && Enums.ContactPropertyType.Email === aProperty[0])
+ {
+ sEmail = aProperty[1];
+ }
+ }
+ }, this);
+ }
+
+ return '' === sEmail ? null : [sEmail, sName];
+ };
+
+ ContactModel.prototype.parse = function (oItem)
+ {
+ var bResult = false;
+ if (oItem && 'Object/Contact' === oItem['@Object'])
+ {
+ this.idContact = Utils.pInt(oItem['IdContact']);
+ this.display = Utils.pString(oItem['Display']);
+ this.readOnly = !!oItem['ReadOnly'];
+
+ if (Utils.isNonEmptyArray(oItem['Properties']))
+ {
+ _.each(oItem['Properties'], function (oProperty) {
+ if (oProperty && oProperty['Type'] && Utils.isNormal(oProperty['Value']) && Utils.isNormal(oProperty['TypeStr']))
+ {
+ this.properties.push([Utils.pInt(oProperty['Type']), Utils.pString(oProperty['Value']), Utils.pString(oProperty['TypeStr'])]);
+ }
+ }, this);
+ }
+
+ bResult = true;
+ }
+
+ return bResult;
+ };
+
+ /**
+ * @return {string}
+ */
+ ContactModel.prototype.srcAttr = function ()
+ {
+ return Links.emptyContactPic();
+ };
+
+ /**
+ * @return {string}
+ */
+ ContactModel.prototype.generateUid = function ()
+ {
+ return '' + this.idContact;
+ };
+
+ /**
+ * @return string
+ */
+ ContactModel.prototype.lineAsCss = function ()
+ {
+ var aResult = [];
+ if (this.deleted())
+ {
+ aResult.push('deleted');
+ }
+ if (this.selected())
+ {
+ aResult.push('selected');
+ }
+ if (this.checked())
+ {
+ aResult.push('checked');
+ }
+ if (this.focused())
+ {
+ aResult.push('focused');
+ }
+
+ return aResult.join(' ');
+ };
+
+ module.exports = ContactModel;
+
+ }());
+
+/***/ },
+/* 104 */
+/*!**************************************!*\
+ !*** ./dev/Model/ContactProperty.js ***!
+ \**************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ AbstractModel = __webpack_require__(/*! Knoin/AbstractModel */ 27)
+ ;
+
+ /**
+ * @constructor
+ * @param {number=} iType = Enums.ContactPropertyType.Unknown
+ * @param {string=} sTypeStr = ''
+ * @param {string=} sValue = ''
+ * @param {boolean=} bFocused = false
+ * @param {string=} sPlaceholder = ''
+ */
+ function ContactPropertyModel(iType, sTypeStr, sValue, bFocused, sPlaceholder)
+ {
+ AbstractModel.call(this, 'ContactPropertyModel');
+
+ this.type = ko.observable(Utils.isUnd(iType) ? Enums.ContactPropertyType.Unknown : iType);
+ this.typeStr = ko.observable(Utils.isUnd(sTypeStr) ? '' : sTypeStr);
+ this.focused = ko.observable(Utils.isUnd(bFocused) ? false : !!bFocused);
+ this.value = ko.observable(Utils.pString(sValue));
+
+ this.placeholder = ko.observable(sPlaceholder || '');
+
+ this.placeholderValue = ko.computed(function () {
+ var sPlaceholder = this.placeholder();
+ return sPlaceholder ? Translator.i18n(sPlaceholder) : '';
+ }, this);
+
+ this.largeValue = ko.computed(function () {
+ return Enums.ContactPropertyType.Note === this.type();
+ }, this);
+
+ this.regDisposables([this.placeholderValue, this.largeValue]);
+ }
+
+ _.extend(ContactPropertyModel.prototype, AbstractModel.prototype);
+
+ module.exports = ContactPropertyModel;
+
+ }());
+
+/***/ },
+/* 105 */
+/*!**************************************!*\
+ !*** ./dev/Model/FilterCondition.js ***!
+ \**************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ AbstractModel = __webpack_require__(/*! Knoin/AbstractModel */ 27)
+ ;
+
+ /**
+ * @constructor
+ */
+ function FilterConditionModel()
+ {
+ AbstractModel.call(this, 'FilterConditionModel');
+
+ this.field = ko.observable(Enums.FilterConditionField.From);
+ this.type = ko.observable(Enums.FilterConditionType.Contains);
+ this.value = ko.observable('');
+ this.value.error = ko.observable(false);
+
+ this.valueSecond = ko.observable('');
+ this.valueSecond.error = ko.observable(false);
+
+ this.template = ko.computed(function () {
+
+ var sTemplate = '';
+ switch (this.field())
+ {
+ case Enums.FilterConditionField.Size:
+ sTemplate = 'SettingsFiltersConditionSize';
+ break;
+ case Enums.FilterConditionField.Header:
+ sTemplate = 'SettingsFiltersConditionMore';
+ break;
+ default:
+ sTemplate = 'SettingsFiltersConditionDefault';
+ break;
+ }
+
+ return sTemplate;
+
+ }, this);
+
+ this.field.subscribe(function () {
+ this.value('');
+ this.valueSecond('');
+ }, this);
+
+ this.regDisposables([this.template]);
+ }
+
+ _.extend(FilterConditionModel.prototype, AbstractModel.prototype);
+
+ FilterConditionModel.prototype.verify = function ()
+ {
+ if ('' === this.value())
+ {
+ this.value.error(true);
+ return false;
+ }
+
+ if (Enums.FilterConditionField.Header === this.field() && '' === this.valueSecond())
+ {
+ this.valueSecond.error(true);
+ return false;
+ }
+
+ return true;
+ };
+
+ FilterConditionModel.prototype.parse = function (oItem)
+ {
+ if (oItem && oItem['Field'] && oItem['Type'])
+ {
+ this.field(Utils.pString(oItem['Field']));
+ this.type(Utils.pString(oItem['Type']));
+ this.value(Utils.pString(oItem['Value']));
+ this.valueSecond(Utils.pString(oItem['ValueSecond']));
+
+ return true;
+ }
+
+ return false;
+ };
+
+ FilterConditionModel.prototype.toJson = function ()
+ {
+ return {
+ 'Field': this.field(),
+ 'Type': this.type(),
+ 'Value': this.value(),
+ 'ValueSecond': this.valueSecond()
+ };
+ };
+
+ FilterConditionModel.prototype.cloneSelf = function ()
+ {
+ var oClone = new FilterConditionModel();
+
+ oClone.field(this.field());
+ oClone.type(this.type());
+ oClone.value(this.value());
+ oClone.valueSecond(this.valueSecond());
+
+ return oClone;
+ };
+
+ module.exports = FilterConditionModel;
+
+ }());
+
+/***/ },
+/* 106 */
+/*!*****************************!*\
+ !*** ./dev/Model/Folder.js ***!
+ \*****************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Events = __webpack_require__(/*! Common/Events */ 25),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Cache = __webpack_require__(/*! Common/Cache */ 19),
+
+ AbstractModel = __webpack_require__(/*! Knoin/AbstractModel */ 27)
+ ;
+
+ /**
+ * @constructor
+ */
+ function FolderModel()
+ {
+ AbstractModel.call(this, 'FolderModel');
+
+ this.name = ko.observable('');
+ this.fullName = '';
+ this.fullNameRaw = '';
+ this.fullNameHash = '';
+ this.delimiter = '';
+ this.namespace = '';
+ this.deep = 0;
+ this.interval = 0;
+
+ this.selectable = false;
+ this.existen = true;
+
+ this.type = ko.observable(Enums.FolderType.User);
+
+ this.focused = ko.observable(false);
+ this.selected = ko.observable(false);
+ this.edited = ko.observable(false);
+ this.collapsed = ko.observable(true);
+ this.subScribed = ko.observable(true);
+ this.checkable = ko.observable(false);
+ this.subFolders = ko.observableArray([]);
+ this.deleteAccess = ko.observable(false);
+ this.actionBlink = ko.observable(false).extend({'falseTimeout': 1000});
+
+ this.nameForEdit = ko.observable('');
+
+ this.privateMessageCountAll = ko.observable(0);
+ this.privateMessageCountUnread = ko.observable(0);
+
+ this.collapsedPrivate = ko.observable(true);
+ }
+
+ _.extend(FolderModel.prototype, AbstractModel.prototype);
+
+ /**
+ * @static
+ * @param {AjaxJsonFolder} oJsonFolder
+ * @return {?FolderModel}
+ */
+ FolderModel.newInstanceFromJson = function (oJsonFolder)
+ {
+ var oFolderModel = new FolderModel();
+ return oFolderModel.initByJson(oJsonFolder) ? oFolderModel.initComputed() : null;
+ };
+
+ /**
+ * @return {FolderModel}
+ */
+ FolderModel.prototype.initComputed = function ()
+ {
+ var sInboxFolderName = Cache.getFolderInboxName();
+
+ this.isInbox = ko.computed(function () {
+ return Enums.FolderType.Inbox === this.type();
+ }, this);
+
+ this.hasSubScribedSubfolders = ko.computed(function () {
+ return !!_.find(this.subFolders(), function (oFolder) {
+ return (oFolder.subScribed() || oFolder.hasSubScribedSubfolders()) && !oFolder.isSystemFolder();
+ });
+ }, this);
+
+ this.canBeEdited = ko.computed(function () {
+ return Enums.FolderType.User === this.type() && this.existen && this.selectable;
+ }, this);
+
+ this.visible = ko.computed(function () {
+
+ var
+ bSubScribed = this.subScribed(),
+ bSubFolders = this.hasSubScribedSubfolders()
+ ;
+
+ return (bSubScribed || (bSubFolders && (!this.existen || !this.selectable)));
+
+ }, this);
+
+ this.isSystemFolder = ko.computed(function () {
+ return Enums.FolderType.User !== this.type();
+ }, this);
+
+ this.hidden = ko.computed(function () {
+
+ var
+ bSystem = this.isSystemFolder(),
+ bSubFolders = this.hasSubScribedSubfolders()
+ ;
+
+ return (bSystem && !bSubFolders) || (!this.selectable && !bSubFolders);
+
+ }, this);
+
+ this.selectableForFolderList = ko.computed(function () {
+ return !this.isSystemFolder() && this.selectable;
+ }, this);
+
+ this.messageCountAll = ko.computed({
+ 'read': this.privateMessageCountAll,
+ 'write': function (iValue) {
+ if (Utils.isPosNumeric(iValue, true))
+ {
+ this.privateMessageCountAll(iValue);
+ }
+ else
+ {
+ this.privateMessageCountAll.valueHasMutated();
+ }
+ },
+ 'owner': this
+ }).extend({'notify': 'always'});
+
+ this.messageCountUnread = ko.computed({
+ 'read': this.privateMessageCountUnread,
+ 'write': function (iValue) {
+ if (Utils.isPosNumeric(iValue, true))
+ {
+ this.privateMessageCountUnread(iValue);
+ }
+ else
+ {
+ this.privateMessageCountUnread.valueHasMutated();
+ }
+ },
+ 'owner': this
+ }).extend({'notify': 'always'});
+
+ this.printableUnreadCount = ko.computed(function () {
+ var
+ iCount = this.messageCountAll(),
+ iUnread = this.messageCountUnread(),
+ iType = this.type()
+ ;
+
+ if (0 < iCount)
+ {
+ if (Enums.FolderType.Draft === iType)
+ {
+ return '' + iCount;
+ }
+ else if (0 < iUnread && Enums.FolderType.Trash !== iType && Enums.FolderType.Archive !== iType && Enums.FolderType.SentItems !== iType)
+ {
+ return '' + iUnread;
+ }
+ }
+
+ return '';
+
+ }, this);
+
+ this.canBeDeleted = ko.computed(function () {
+ var
+ bSystem = this.isSystemFolder()
+ ;
+ return !bSystem && 0 === this.subFolders().length && sInboxFolderName !== this.fullNameRaw;
+ }, this);
+
+ this.canBeSubScribed = ko.computed(function () {
+ return !this.isSystemFolder() && this.selectable && sInboxFolderName !== this.fullNameRaw;
+ }, this);
+
+ this.canBeChecked = this.canBeSubScribed;
+
+ // this.visible.subscribe(function () {
+ // Utils.timeOutAction('folder-list-folder-visibility-change', function () {
+ // Globals.$win.trigger('folder-list-folder-visibility-change');
+ // }, 100);
+ // });
+
+ this.localName = ko.computed(function () {
+
+ Translator.trigger();
+
+ var
+ iType = this.type(),
+ sName = this.name()
+ ;
+
+ if (this.isSystemFolder())
+ {
+ switch (iType)
+ {
+ case Enums.FolderType.Inbox:
+ sName = Translator.i18n('FOLDER_LIST/INBOX_NAME');
+ break;
+ case Enums.FolderType.SentItems:
+ sName = Translator.i18n('FOLDER_LIST/SENT_NAME');
+ break;
+ case Enums.FolderType.Draft:
+ sName = Translator.i18n('FOLDER_LIST/DRAFTS_NAME');
+ break;
+ case Enums.FolderType.Spam:
+ sName = Translator.i18n('FOLDER_LIST/SPAM_NAME');
+ break;
+ case Enums.FolderType.Trash:
+ sName = Translator.i18n('FOLDER_LIST/TRASH_NAME');
+ break;
+ case Enums.FolderType.Archive:
+ sName = Translator.i18n('FOLDER_LIST/ARCHIVE_NAME');
+ break;
+ }
+ }
+
+ return sName;
+
+ }, this);
+
+ this.manageFolderSystemName = ko.computed(function () {
+
+ Translator.trigger();
+
+ var
+ sSuffix = '',
+ iType = this.type(),
+ sName = this.name()
+ ;
+
+ if (this.isSystemFolder())
+ {
+ switch (iType)
+ {
+ case Enums.FolderType.Inbox:
+ sSuffix = '(' + Translator.i18n('FOLDER_LIST/INBOX_NAME') + ')';
+ break;
+ case Enums.FolderType.SentItems:
+ sSuffix = '(' + Translator.i18n('FOLDER_LIST/SENT_NAME') + ')';
+ break;
+ case Enums.FolderType.Draft:
+ sSuffix = '(' + Translator.i18n('FOLDER_LIST/DRAFTS_NAME') + ')';
+ break;
+ case Enums.FolderType.Spam:
+ sSuffix = '(' + Translator.i18n('FOLDER_LIST/SPAM_NAME') + ')';
+ break;
+ case Enums.FolderType.Trash:
+ sSuffix = '(' + Translator.i18n('FOLDER_LIST/TRASH_NAME') + ')';
+ break;
+ case Enums.FolderType.Archive:
+ sSuffix = '(' + Translator.i18n('FOLDER_LIST/ARCHIVE_NAME') + ')';
+ break;
+ }
+ }
+
+ if ('' !== sSuffix && '(' + sName + ')' === sSuffix || '(inbox)' === sSuffix.toLowerCase())
+ {
+ sSuffix = '';
+ }
+
+ return sSuffix;
+
+ }, this);
+
+ this.collapsed = ko.computed({
+ 'read': function () {
+ return !this.hidden() && this.collapsedPrivate();
+ },
+ 'write': function (mValue) {
+ this.collapsedPrivate(mValue);
+ },
+ 'owner': this
+ });
+
+ this.hasUnreadMessages = ko.computed(function () {
+ return 0 < this.messageCountUnread() && '' !== this.printableUnreadCount();
+ }, this);
+
+ this.hasSubScribedUnreadMessagesSubfolders = ko.computed(function () {
+ return !!_.find(this.subFolders(), function (oFolder) {
+ return oFolder.hasUnreadMessages() || oFolder.hasSubScribedUnreadMessagesSubfolders();
+ });
+ }, this);
+
+ // subscribe
+ this.name.subscribe(function (sValue) {
+ this.nameForEdit(sValue);
+ }, this);
+
+ this.edited.subscribe(function (bValue) {
+ if (bValue)
+ {
+ this.nameForEdit(this.name());
+ }
+ }, this);
+
+ this.messageCountUnread.subscribe(function (iUnread) {
+ if (Enums.FolderType.Inbox === this.type())
+ {
+ Events.pub('mailbox.inbox-unread-count', [iUnread]);
+ }
+ }, this);
+
+ return this;
+ };
+
+ FolderModel.prototype.fullName = '';
+ FolderModel.prototype.fullNameRaw = '';
+ FolderModel.prototype.fullNameHash = '';
+ FolderModel.prototype.delimiter = '';
+ FolderModel.prototype.namespace = '';
+ FolderModel.prototype.deep = 0;
+ FolderModel.prototype.interval = 0;
+
+ /**
+ * @return {string}
+ */
+ FolderModel.prototype.collapsedCss = function ()
+ {
+ return this.hasSubScribedSubfolders() ?
+ (this.collapsed() ? 'icon-right-mini e-collapsed-sign' : 'icon-down-mini e-collapsed-sign') : 'icon-none e-collapsed-sign';
+ };
+
+ /**
+ * @param {AjaxJsonFolder} oJsonFolder
+ * @return {boolean}
+ */
+ FolderModel.prototype.initByJson = function (oJsonFolder)
+ {
+ var
+ bResult = false,
+ sInboxFolderName = Cache.getFolderInboxName()
+ ;
+
+ if (oJsonFolder && 'Object/Folder' === oJsonFolder['@Object'])
+ {
+ this.name(oJsonFolder.Name);
+ this.delimiter = oJsonFolder.Delimiter;
+ this.fullName = oJsonFolder.FullName;
+ this.fullNameRaw = oJsonFolder.FullNameRaw;
+ this.fullNameHash = oJsonFolder.FullNameHash;
+ this.deep = oJsonFolder.FullNameRaw.split(this.delimiter).length - 1;
+ this.selectable = !!oJsonFolder.IsSelectable;
+ this.existen = !!oJsonFolder.IsExists;
+
+ this.subScribed(!!oJsonFolder.IsSubscribed);
+ this.checkable(!!oJsonFolder.Checkable);
+
+ this.type(sInboxFolderName === this.fullNameRaw ? Enums.FolderType.Inbox : Enums.FolderType.User);
+
+ bResult = true;
+ }
+
+ return bResult;
+ };
+
+ /**
+ * @return {string}
+ */
+ FolderModel.prototype.printableFullName = function ()
+ {
+ return this.fullName.split(this.delimiter).join(' / ');
+ };
+
+ module.exports = FolderModel;
+
+ }());
+
+/***/ },
+/* 107 */
+/*!*******************************!*\
+ !*** ./dev/Model/Identity.js ***!
+ \*******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ AbstractModel = __webpack_require__(/*! Knoin/AbstractModel */ 27)
+ ;
+
+ /**
+ * @param {string} sId
+ * @param {string} sEmail
+ * @constructor
+ */
+ function IdentityModel(sId, sEmail)
+ {
+ AbstractModel.call(this, 'IdentityModel');
+
+ this.id = ko.observable(sId || '');
+ this.email = ko.observable(sEmail);
+ this.name = ko.observable('');
+
+ this.replyTo = ko.observable('');
+ this.bcc = ko.observable('');
+
+ this.signature = ko.observable('');
+ this.signatureInsertBefore = ko.observable(false);
+
+ this.deleteAccess = ko.observable(false);
+ this.canBeDeleted = ko.computed(function () {
+ return '' !== this.id();
+ }, this);
+ }
+
+ _.extend(IdentityModel.prototype, AbstractModel.prototype);
+
+ IdentityModel.prototype.formattedName = function ()
+ {
+ var
+ sName = this.name(),
+ sEmail = this.email()
+ ;
+
+ return ('' !== sName) ? sName + ' (' + sEmail + ')' : sEmail;
+ };
+
+ module.exports = IdentityModel;
+
+ }());
+
+/***/ },
+/* 108 */
+/*!******************************!*\
+ !*** ./dev/Model/Message.js ***!
+ \******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+
+ AttachmentModel = __webpack_require__(/*! Model/Attachment */ 86),
+
+ MessageHelper = __webpack_require__(/*! Helper/Message */ 85),
+
+ AbstractModel = __webpack_require__(/*! Knoin/AbstractModel */ 27)
+ ;
+
+ /**
+ * @constructor
+ */
+ function MessageModel()
+ {
+ AbstractModel.call(this, 'MessageModel');
+
+ this.folderFullNameRaw = '';
+ this.uid = '';
+ this.hash = '';
+ this.requestHash = '';
+ this.subject = ko.observable('');
+ this.subjectPrefix = ko.observable('');
+ this.subjectSuffix = ko.observable('');
+ this.size = ko.observable(0);
+ this.dateTimeStampInUTC = ko.observable(0);
+ this.priority = ko.observable(Enums.MessagePriority.Normal);
+
+ this.proxy = false;
+
+ this.fromEmailString = ko.observable('');
+ this.fromClearEmailString = ko.observable('');
+ this.toEmailsString = ko.observable('');
+ this.toClearEmailsString = ko.observable('');
+
+ this.senderEmailsString = ko.observable('');
+ this.senderClearEmailsString = ko.observable('');
+
+ this.emails = [];
+
+ this.from = [];
+ this.to = [];
+ this.cc = [];
+ this.bcc = [];
+ this.replyTo = [];
+ this.deliveredTo = [];
+
+ this.newForAnimation = ko.observable(false);
+
+ this.deleted = ko.observable(false);
+ this.deletedMark = ko.observable(false);
+ this.unseen = ko.observable(false);
+ this.flagged = ko.observable(false);
+ this.answered = ko.observable(false);
+ this.forwarded = ko.observable(false);
+ this.isReadReceipt = ko.observable(false);
+
+ this.focused = ko.observable(false);
+ this.selected = ko.observable(false);
+ this.checked = ko.observable(false);
+ this.hasAttachments = ko.observable(false);
+ this.attachmentsSpecData = ko.observableArray([]);
+
+ this.attachmentIconClass = ko.computed(function () {
+ return AttachmentModel.staticCombinedIconClass(
+ this.hasAttachments() ? this.attachmentsSpecData() : []);
+ }, this);
+
+ this.body = null;
+
+ this.isHtml = ko.observable(false);
+ this.hasImages = ko.observable(false);
+ this.attachments = ko.observableArray([]);
+
+ this.isPgpSigned = ko.observable(false);
+ this.isPgpEncrypted = ko.observable(false);
+ this.pgpSignedVerifyStatus = ko.observable(Enums.SignedVerifyStatus.None);
+ this.pgpSignedVerifyUser = ko.observable('');
+
+ this.priority = ko.observable(Enums.MessagePriority.Normal);
+ this.readReceipt = ko.observable('');
+
+ this.aDraftInfo = [];
+ this.sMessageId = '';
+ this.sInReplyTo = '';
+ this.sReferences = '';
+
+ this.hasUnseenSubMessage = ko.observable(false);
+ this.hasFlaggedSubMessage = ko.observable(false);
+
+ this.threads = ko.observableArray([]);
+
+ this.threadsLen = ko.computed(function () {
+ return this.threads().length;
+ }, this);
+
+ this.isImportant = ko.computed(function () {
+ return Enums.MessagePriority.High === this.priority();
+ }, this);
+
+ this.regDisposables([this.attachmentIconClass, this.threadsLen, this.isImportant]);
+ }
+
+ _.extend(MessageModel.prototype, AbstractModel.prototype);
+
+ /**
+ * @static
+ * @param {AjaxJsonMessage} oJsonMessage
+ * @return {?MessageModel}
+ */
+ MessageModel.newInstanceFromJson = function (oJsonMessage)
+ {
+ var oMessageModel = new MessageModel();
+ return oMessageModel.initByJson(oJsonMessage) ? oMessageModel : null;
+ };
+
+ MessageModel.prototype.clear = function ()
+ {
+ this.folderFullNameRaw = '';
+ this.uid = '';
+ this.hash = '';
+ this.requestHash = '';
+ this.subject('');
+ this.subjectPrefix('');
+ this.subjectSuffix('');
+ this.size(0);
+ this.dateTimeStampInUTC(0);
+ this.priority(Enums.MessagePriority.Normal);
+
+ this.proxy = false;
+
+ this.fromEmailString('');
+ this.fromClearEmailString('');
+ this.toEmailsString('');
+ this.toClearEmailsString('');
+ this.senderEmailsString('');
+ this.senderClearEmailsString('');
+
+ this.emails = [];
+
+ this.from = [];
+ this.to = [];
+ this.cc = [];
+ this.bcc = [];
+ this.replyTo = [];
+ this.deliveredTo = [];
+
+ this.newForAnimation(false);
+
+ this.deleted(false);
+ this.deletedMark(false);
+ this.unseen(false);
+ this.flagged(false);
+ this.answered(false);
+ this.forwarded(false);
+ this.isReadReceipt(false);
+
+ this.selected(false);
+ this.checked(false);
+ this.hasAttachments(false);
+ this.attachmentsSpecData([]);
+
+ this.body = null;
+ this.isHtml(false);
+ this.hasImages(false);
+ this.attachments([]);
+
+ this.isPgpSigned(false);
+ this.isPgpEncrypted(false);
+ this.pgpSignedVerifyStatus(Enums.SignedVerifyStatus.None);
+ this.pgpSignedVerifyUser('');
+
+ this.priority(Enums.MessagePriority.Normal);
+ this.readReceipt('');
+ this.aDraftInfo = [];
+ this.sMessageId = '';
+ this.sInReplyTo = '';
+ this.sReferences = '';
+
+ this.threads([]);
+
+ this.hasUnseenSubMessage(false);
+ this.hasFlaggedSubMessage(false);
+ };
+
+ /**
+ * @return {Array}
+ */
+ MessageModel.prototype.getRecipientsEmails = function ()
+ {
+ return this.getEmails(['to', 'cc']);
+ };
+
+ /**
+ * @param {Array} aProperties
+ * @return {Array}
+ */
+ MessageModel.prototype.getEmails = function (aProperties)
+ {
+ var self = this;
+ return _.compact(_.uniq(_.map(_.reduce(aProperties, function (aCarry, sProperty) {
+ return aCarry.concat(self[sProperty]);
+ }, []), function (oItem) {
+ return oItem ? oItem.email : '';
+ })));
+ };
+
+ /**
+ * @return {string}
+ */
+ MessageModel.prototype.friendlySize = function ()
+ {
+ return Utils.friendlySize(this.size());
+ };
+
+ MessageModel.prototype.computeSenderEmail = function ()
+ {
+ var
+ sSent = __webpack_require__(/*! Stores/User/Folder */ 21).sentFolder(),
+ sDraft = __webpack_require__(/*! Stores/User/Folder */ 21).draftFolder()
+ ;
+
+ this.senderEmailsString(this.folderFullNameRaw === sSent || this.folderFullNameRaw === sDraft ?
+ this.toEmailsString() : this.fromEmailString());
+
+ this.senderClearEmailsString(this.folderFullNameRaw === sSent || this.folderFullNameRaw === sDraft ?
+ this.toClearEmailsString() : this.fromClearEmailString());
+ };
+
+ /**
+ * @param {AjaxJsonMessage} oJsonMessage
+ * @return {boolean}
+ */
+ MessageModel.prototype.initByJson = function (oJsonMessage)
+ {
+ var
+ bResult = false,
+ iPriority = Enums.MessagePriority.Normal
+ ;
+
+ if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object'])
+ {
+ iPriority = Utils.pInt(oJsonMessage.Priority);
+ this.priority(-1 < Utils.inArray(iPriority, [Enums.MessagePriority.High, Enums.MessagePriority.Low]) ?
+ iPriority : Enums.MessagePriority.Normal);
+
+ this.folderFullNameRaw = oJsonMessage.Folder;
+ this.uid = oJsonMessage.Uid;
+ this.hash = oJsonMessage.Hash;
+ this.requestHash = oJsonMessage.RequestHash;
+
+ this.proxy = !!oJsonMessage.ExternalProxy;
+
+ this.size(Utils.pInt(oJsonMessage.Size));
+
+ this.from = MessageHelper.emailArrayFromJson(oJsonMessage.From);
+ this.to = MessageHelper.emailArrayFromJson(oJsonMessage.To);
+ this.cc = MessageHelper.emailArrayFromJson(oJsonMessage.Cc);
+ this.bcc = MessageHelper.emailArrayFromJson(oJsonMessage.Bcc);
+ this.replyTo = MessageHelper.emailArrayFromJson(oJsonMessage.ReplyTo);
+ this.deliveredTo = MessageHelper.emailArrayFromJson(oJsonMessage.DeliveredTo);
+
+ this.subject(oJsonMessage.Subject);
+ if (Utils.isArray(oJsonMessage.SubjectParts))
+ {
+ this.subjectPrefix(oJsonMessage.SubjectParts[0]);
+ this.subjectSuffix(oJsonMessage.SubjectParts[1]);
+ }
+ else
+ {
+ this.subjectPrefix('');
+ this.subjectSuffix(this.subject());
+ }
+
+ this.dateTimeStampInUTC(Utils.pInt(oJsonMessage.DateTimeStampInUTC));
+ this.hasAttachments(!!oJsonMessage.HasAttachments);
+ this.attachmentsSpecData(Utils.isArray(oJsonMessage.AttachmentsSpecData) ?
+ oJsonMessage.AttachmentsSpecData : []);
+
+ this.fromEmailString(MessageHelper.emailArrayToString(this.from, true));
+ this.fromClearEmailString(MessageHelper.emailArrayToStringClear(this.from));
+ this.toEmailsString(MessageHelper.emailArrayToString(this.to, true));
+ this.toClearEmailsString(MessageHelper.emailArrayToStringClear(this.to));
+
+ this.threads(Utils.isArray(oJsonMessage.Threads) ? oJsonMessage.Threads : []);
+
+ this.initFlagsByJson(oJsonMessage);
+ this.computeSenderEmail();
+
+ bResult = true;
+ }
+
+ return bResult;
+ };
+
+ /**
+ * @param {AjaxJsonMessage} oJsonMessage
+ * @return {boolean}
+ */
+ MessageModel.prototype.initUpdateByMessageJson = function (oJsonMessage)
+ {
+ var
+ bResult = false,
+ iPriority = Enums.MessagePriority.Normal
+ ;
+
+ if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object'])
+ {
+ iPriority = Utils.pInt(oJsonMessage.Priority);
+ this.priority(-1 < Utils.inArray(iPriority, [Enums.MessagePriority.High, Enums.MessagePriority.Low]) ?
+ iPriority : Enums.MessagePriority.Normal);
+
+ this.aDraftInfo = oJsonMessage.DraftInfo;
+
+ this.sMessageId = oJsonMessage.MessageId;
+ this.sInReplyTo = oJsonMessage.InReplyTo;
+ this.sReferences = oJsonMessage.References;
+
+ this.proxy = !!oJsonMessage.ExternalProxy;
+
+ if (__webpack_require__(/*! Stores/User/Pgp */ 33).capaOpenPGP())
+ {
+ this.isPgpSigned(!!oJsonMessage.PgpSigned);
+ this.isPgpEncrypted(!!oJsonMessage.PgpEncrypted);
+ }
+
+ this.hasAttachments(!!oJsonMessage.HasAttachments);
+ this.attachmentsSpecData(Utils.isArray(oJsonMessage.AttachmentsSpecData) ?
+ oJsonMessage.AttachmentsSpecData : []);
+
+ this.foundedCIDs = Utils.isArray(oJsonMessage.FoundedCIDs) ? oJsonMessage.FoundedCIDs : [];
+ this.attachments(this.initAttachmentsFromJson(oJsonMessage.Attachments));
+
+ this.readReceipt(oJsonMessage.ReadReceipt || '');
+
+ this.computeSenderEmail();
+
+ bResult = true;
+ }
+
+ return bResult;
+ };
+
+ /**
+ * @param {(AjaxJsonAttachment|null)} oJsonAttachments
+ * @return {Array}
+ */
+ MessageModel.prototype.initAttachmentsFromJson = function (oJsonAttachments)
+ {
+ var
+ iIndex = 0,
+ iLen = 0,
+ oAttachmentModel = null,
+ aResult = []
+ ;
+
+ if (oJsonAttachments && 'Collection/AttachmentCollection' === oJsonAttachments['@Object'] &&
+ Utils.isNonEmptyArray(oJsonAttachments['@Collection']))
+ {
+ for (iIndex = 0, iLen = oJsonAttachments['@Collection'].length; iIndex < iLen; iIndex++)
+ {
+ oAttachmentModel = AttachmentModel.newInstanceFromJson(oJsonAttachments['@Collection'][iIndex]);
+ if (oAttachmentModel)
+ {
+ if ('' !== oAttachmentModel.cidWithOutTags && 0 < this.foundedCIDs.length &&
+ 0 <= Utils.inArray(oAttachmentModel.cidWithOutTags, this.foundedCIDs))
+ {
+ oAttachmentModel.isLinked = true;
+ }
+
+ aResult.push(oAttachmentModel);
+ }
+ }
+ }
+
+ return aResult;
+ };
+
+ /**
+ * @param {AjaxJsonMessage} oJsonMessage
+ * @return {boolean}
+ */
+ MessageModel.prototype.initFlagsByJson = function (oJsonMessage)
+ {
+ var bResult = false;
+
+ if (oJsonMessage && 'Object/Message' === oJsonMessage['@Object'])
+ {
+ this.unseen(!oJsonMessage.IsSeen);
+ this.flagged(!!oJsonMessage.IsFlagged);
+ this.answered(!!oJsonMessage.IsAnswered);
+ this.forwarded(!!oJsonMessage.IsForwarded);
+ this.isReadReceipt(!!oJsonMessage.IsReadReceipt);
+ this.deletedMark(!!oJsonMessage.IsDeleted);
+
+ bResult = true;
+ }
+
+ return bResult;
+ };
+
+ /**
+ * @param {boolean} bFriendlyView
+ * @param {boolean=} bWrapWithLink = false
+ * @return {string}
+ */
+ MessageModel.prototype.fromToLine = function (bFriendlyView, bWrapWithLink)
+ {
+ return MessageHelper.emailArrayToString(this.from, bFriendlyView, bWrapWithLink);
+ };
+
+ /**
+ * @return {string}
+ */
+ MessageModel.prototype.fromDkimData = function ()
+ {
+ var aResult = ['none', ''];
+ if (Utils.isNonEmptyArray(this.from) && 1 === this.from.length &&
+ this.from[0] && this.from[0].dkimStatus)
+ {
+ aResult = [this.from[0].dkimStatus, this.from[0].dkimValue || ''];
+ }
+
+ return aResult;
+ };
+
+ /**
+ * @param {boolean} bFriendlyView
+ * @param {boolean=} bWrapWithLink = false
+ * @return {string}
+ */
+ MessageModel.prototype.toToLine = function (bFriendlyView, bWrapWithLink)
+ {
+ return MessageHelper.emailArrayToString(this.to, bFriendlyView, bWrapWithLink);
+ };
+
+ /**
+ * @param {boolean} bFriendlyView
+ * @param {boolean=} bWrapWithLink = false
+ * @return {string}
+ */
+ MessageModel.prototype.ccToLine = function (bFriendlyView, bWrapWithLink)
+ {
+ return MessageHelper.emailArrayToString(this.cc, bFriendlyView, bWrapWithLink);
+ };
+
+ /**
+ * @param {boolean} bFriendlyView
+ * @param {boolean=} bWrapWithLink = false
+ * @return {string}
+ */
+ MessageModel.prototype.bccToLine = function (bFriendlyView, bWrapWithLink)
+ {
+ return MessageHelper.emailArrayToString(this.bcc, bFriendlyView, bWrapWithLink);
+ };
+
+ /**
+ * @param {boolean} bFriendlyView
+ * @param {boolean=} bWrapWithLink = false
+ * @return {string}
+ */
+ MessageModel.prototype.replyToToLine = function (bFriendlyView, bWrapWithLink)
+ {
+ return MessageHelper.emailArrayToString(this.replyTo, bFriendlyView, bWrapWithLink);
+ };
+
+ /**
+ * @return string
+ */
+ MessageModel.prototype.lineAsCss = function ()
+ {
+ var aResult = [];
+ if (this.deleted())
+ {
+ aResult.push('deleted');
+ }
+ if (this.deletedMark())
+ {
+ aResult.push('deleted-mark');
+ }
+ if (this.selected())
+ {
+ aResult.push('selected');
+ }
+ if (this.checked())
+ {
+ aResult.push('checked');
+ }
+ if (this.flagged())
+ {
+ aResult.push('flagged');
+ }
+ if (this.unseen())
+ {
+ aResult.push('unseen');
+ }
+ if (this.answered())
+ {
+ aResult.push('answered');
+ }
+ if (this.forwarded())
+ {
+ aResult.push('forwarded');
+ }
+ if (this.focused())
+ {
+ aResult.push('focused');
+ }
+ if (this.isImportant())
+ {
+ aResult.push('important');
+ }
+ if (this.hasAttachments())
+ {
+ aResult.push('withAttachments');
+ }
+ if (this.newForAnimation())
+ {
+ aResult.push('new');
+ }
+ if ('' === this.subject())
+ {
+ aResult.push('emptySubject');
+ }
+ // if (1 < this.threadsLen())
+ // {
+ // aResult.push('hasChildrenMessage');
+ // }
+ if (this.hasUnseenSubMessage())
+ {
+ aResult.push('hasUnseenSubMessage');
+ }
+ if (this.hasFlaggedSubMessage())
+ {
+ aResult.push('hasFlaggedSubMessage');
+ }
+
+ return aResult.join(' ');
+ };
+
+ /**
+ * @return {boolean}
+ */
+ MessageModel.prototype.hasVisibleAttachments = function ()
+ {
+ return !!_.find(this.attachments(), function (oAttachment) {
+ return !oAttachment.isLinked;
+ });
+ };
+
+ /**
+ * @param {string} sCid
+ * @return {*}
+ */
+ MessageModel.prototype.findAttachmentByCid = function (sCid)
+ {
+ var
+ oResult = null,
+ aAttachments = this.attachments()
+ ;
+
+ if (Utils.isNonEmptyArray(aAttachments))
+ {
+ sCid = sCid.replace(/^<+/, '').replace(/>+$/, '');
+ oResult = _.find(aAttachments, function (oAttachment) {
+ return sCid === oAttachment.cidWithOutTags;
+ });
+ }
+
+ return oResult || null;
+ };
+
+ /**
+ * @param {string} sContentLocation
+ * @return {*}
+ */
+ MessageModel.prototype.findAttachmentByContentLocation = function (sContentLocation)
+ {
+ var
+ oResult = null,
+ aAttachments = this.attachments()
+ ;
+
+ if (Utils.isNonEmptyArray(aAttachments))
+ {
+ oResult = _.find(aAttachments, function (oAttachment) {
+ return sContentLocation === oAttachment.contentLocation;
+ });
+ }
+
+ return oResult || null;
+ };
+
+
+ /**
+ * @return {string}
+ */
+ MessageModel.prototype.messageId = function ()
+ {
+ return this.sMessageId;
+ };
+
+ /**
+ * @return {string}
+ */
+ MessageModel.prototype.inReplyTo = function ()
+ {
+ return this.sInReplyTo;
+ };
+
+ /**
+ * @return {string}
+ */
+ MessageModel.prototype.references = function ()
+ {
+ return this.sReferences;
+ };
+
+ /**
+ * @return {string}
+ */
+ MessageModel.prototype.fromAsSingleEmail = function ()
+ {
+ return Utils.isArray(this.from) && this.from[0] ? this.from[0].email : '';
+ };
+
+ /**
+ * @return {string}
+ */
+ MessageModel.prototype.viewLink = function ()
+ {
+ return Links.messageViewLink(this.requestHash);
+ };
+
+ /**
+ * @return {string}
+ */
+ MessageModel.prototype.downloadLink = function ()
+ {
+ return Links.messageDownloadLink(this.requestHash);
+ };
+
+ /**
+ * @param {Object} oExcludeEmails
+ * @param {boolean=} bLast = false
+ * @return {Array}
+ */
+ MessageModel.prototype.replyEmails = function (oExcludeEmails, bLast)
+ {
+ var
+ aResult = [],
+ oUnic = Utils.isUnd(oExcludeEmails) ? {} : oExcludeEmails
+ ;
+
+ MessageHelper.replyHelper(this.replyTo, oUnic, aResult);
+ if (0 === aResult.length)
+ {
+ MessageHelper.replyHelper(this.from, oUnic, aResult);
+ }
+
+ if (0 === aResult.length && !bLast)
+ {
+ return this.replyEmails({}, true);
+ }
+
+ return aResult;
+ };
+
+ /**
+ * @param {Object} oExcludeEmails
+ * @param {boolean=} bLast = false
+ * @return {Array.}
+ */
+ MessageModel.prototype.replyAllEmails = function (oExcludeEmails, bLast)
+ {
+ var
+ aData = [],
+ aToResult = [],
+ aCcResult = [],
+ oUnic = Utils.isUnd(oExcludeEmails) ? {} : oExcludeEmails
+ ;
+
+ MessageHelper.replyHelper(this.replyTo, oUnic, aToResult);
+ if (0 === aToResult.length)
+ {
+ MessageHelper.replyHelper(this.from, oUnic, aToResult);
+ }
+
+ MessageHelper.replyHelper(this.to, oUnic, aToResult);
+ MessageHelper.replyHelper(this.cc, oUnic, aCcResult);
+
+ if (0 === aToResult.length && !bLast)
+ {
+ aData = this.replyAllEmails({}, true);
+ return [aData[0], aCcResult];
+ }
+
+ return [aToResult, aCcResult];
+ };
+
+ /**
+ * @return {string}
+ */
+ MessageModel.prototype.textBodyToString = function ()
+ {
+ return this.body ? this.body.html() : '';
+ };
+
+ /**
+ * @return {string}
+ */
+ MessageModel.prototype.attachmentsToStringLine = function ()
+ {
+ var aAttachLines = _.map(this.attachments(), function (oItem) {
+ return oItem.fileName + ' (' + oItem.friendlySize + ')';
+ });
+
+ return aAttachLines && 0 < aAttachLines.length ? aAttachLines.join(', ') : '';
+ };
+
+ /**
+ * @return {Object}
+ */
+ MessageModel.prototype.getDataForWindowPopup = function ()
+ {
+ return {
+ 'popupFrom': this.fromToLine(false),
+ 'popupTo': this.toToLine(false),
+ 'popupCc': this.ccToLine(false),
+ 'popupBcc': this.bccToLine(false),
+ 'popupReplyTo': this.replyToToLine(false),
+ 'popupSubject': this.subject(),
+ 'popupIsHtml': this.isHtml(),
+ 'popupDate': __webpack_require__(/*! Common/Momentor */ 26).format(this.dateTimeStampInUTC(), 'FULL'),
+ 'popupAttachments': this.attachmentsToStringLine(),
+ 'popupBody': this.textBodyToString()
+ };
+ };
+
+ /**
+ * @param {boolean=} bPrint = false
+ */
+ MessageModel.prototype.viewPopupMessage = function (bPrint)
+ {
+ Utils.windowPopupKnockout(this.getDataForWindowPopup(), 'PopupsWindowSimpleMessage',
+ this.subject(), function (oPopupWin)
+ {
+ if (oPopupWin && oPopupWin.document && oPopupWin.document.body)
+ {
+ $('img.lazy', oPopupWin.document.body).each(function (iIndex, oImg) {
+
+ var
+ $oImg = $(oImg),
+ sOrig = $oImg.data('original'),
+ sSrc = $oImg.attr('src')
+ ;
+
+ if (0 <= iIndex && sOrig && !sSrc)
+ {
+ $oImg.attr('src', sOrig);
+ }
+ });
+
+ if (bPrint)
+ {
+ window.setTimeout(function () {
+ oPopupWin.print();
+ }, 100);
+ }
+ }
+ });
+ };
+
+ MessageModel.prototype.printMessage = function ()
+ {
+ this.viewPopupMessage(true);
+ };
+
+ /**
+ * @return {string}
+ */
+ MessageModel.prototype.generateUid = function ()
+ {
+ return this.folderFullNameRaw + '/' + this.uid;
+ };
+
+ /**
+ * @param {MessageModel} oMessage
+ * @return {MessageModel}
+ */
+ MessageModel.prototype.populateByMessageListItem = function (oMessage)
+ {
+ if (oMessage)
+ {
+ this.folderFullNameRaw = oMessage.folderFullNameRaw;
+ this.uid = oMessage.uid;
+ this.hash = oMessage.hash;
+ this.requestHash = oMessage.requestHash;
+ this.subject(oMessage.subject());
+ }
+
+ this.subjectPrefix(this.subjectPrefix());
+ this.subjectSuffix(this.subjectSuffix());
+
+ if (oMessage)
+ {
+
+ this.size(oMessage.size());
+ this.dateTimeStampInUTC(oMessage.dateTimeStampInUTC());
+ this.priority(oMessage.priority());
+
+ this.proxy = oMessage.proxy;
+
+ this.fromEmailString(oMessage.fromEmailString());
+ this.fromClearEmailString(oMessage.fromClearEmailString());
+ this.toEmailsString(oMessage.toEmailsString());
+ this.toClearEmailsString(oMessage.toClearEmailsString());
+
+ this.emails = oMessage.emails;
+
+ this.from = oMessage.from;
+ this.to = oMessage.to;
+ this.cc = oMessage.cc;
+ this.bcc = oMessage.bcc;
+ this.replyTo = oMessage.replyTo;
+ this.deliveredTo = oMessage.deliveredTo;
+
+ this.unseen(oMessage.unseen());
+ this.flagged(oMessage.flagged());
+ this.answered(oMessage.answered());
+ this.forwarded(oMessage.forwarded());
+ this.isReadReceipt(oMessage.isReadReceipt());
+ this.deletedMark(oMessage.deletedMark());
+
+ this.priority(oMessage.priority());
+
+ this.selected(oMessage.selected());
+ this.checked(oMessage.checked());
+ this.hasAttachments(oMessage.hasAttachments());
+ this.attachmentsSpecData(oMessage.attachmentsSpecData());
+ }
+
+ this.body = null;
+
+ this.aDraftInfo = [];
+ this.sMessageId = '';
+ this.sInReplyTo = '';
+ this.sReferences = '';
+
+ if (oMessage)
+ {
+ this.threads(oMessage.threads());
+ }
+
+ this.computeSenderEmail();
+
+ return this;
+ };
+
+ MessageModel.prototype.showExternalImages = function (bLazy)
+ {
+ if (this.body && this.body.data('rl-has-images'))
+ {
+ var sAttr = '';
+ bLazy = Utils.isUnd(bLazy) ? false : bLazy;
+
+ this.hasImages(false);
+ this.body.data('rl-has-images', false);
+
+ sAttr = this.proxy ? 'data-x-additional-src' : 'data-x-src';
+ $('[' + sAttr + ']', this.body).each(function () {
+ if (bLazy && $(this).is('img'))
+ {
+ $(this)
+ .addClass('lazy')
+ .attr('data-original', $(this).attr(sAttr))
+ .removeAttr(sAttr)
+ ;
+ }
+ else
+ {
+ $(this).attr('src', $(this).attr(sAttr)).removeAttr(sAttr);
+ }
+ });
+
+ sAttr = this.proxy ? 'data-x-additional-style-url' : 'data-x-style-url';
+ $('[' + sAttr + ']', this.body).each(function () {
+ var sStyle = Utils.trim($(this).attr('style'));
+ sStyle = '' === sStyle ? '' : (';' === sStyle.substr(-1) ? sStyle + ' ' : sStyle + '; ');
+ $(this).attr('style', sStyle + $(this).attr(sAttr)).removeAttr(sAttr);
+ });
+
+ if (bLazy)
+ {
+ $('img.lazy', this.body).addClass('lazy-inited').lazyload({
+ 'threshold': 400,
+ 'effect': 'fadeIn',
+ 'skip_invisible': false,
+ 'container': $('.RL-MailMessageView .messageView .messageItem .content')[0]
+ });
+
+ Globals.$win.resize();
+ }
+
+ Utils.windowResize(500);
+ }
+ };
+
+ MessageModel.prototype.showInternalImages = function (bLazy)
+ {
+ if (this.body && !this.body.data('rl-init-internal-images'))
+ {
+ this.body.data('rl-init-internal-images', true);
+
+ bLazy = Utils.isUnd(bLazy) ? false : bLazy;
+
+ var self = this;
+
+ $('[data-x-src-cid]', this.body).each(function () {
+
+ var oAttachment = self.findAttachmentByCid($(this).attr('data-x-src-cid'));
+ if (oAttachment && oAttachment.download)
+ {
+ if (bLazy && $(this).is('img'))
+ {
+ $(this)
+ .addClass('lazy')
+ .attr('data-original', oAttachment.linkPreview());
+ }
+ else
+ {
+ $(this).attr('src', oAttachment.linkPreview());
+ }
+ }
+ });
+
+ $('[data-x-src-location]', this.body).each(function () {
+
+ var oAttachment = self.findAttachmentByContentLocation($(this).attr('data-x-src-location'));
+ if (!oAttachment)
+ {
+ oAttachment = self.findAttachmentByCid($(this).attr('data-x-src-location'));
+ }
+
+ if (oAttachment && oAttachment.download)
+ {
+ if (bLazy && $(this).is('img'))
+ {
+ $(this)
+ .addClass('lazy')
+ .attr('data-original', oAttachment.linkPreview());
+ }
+ else
+ {
+ $(this).attr('src', oAttachment.linkPreview());
+ }
+ }
+ });
+
+ $('[data-x-style-cid]', this.body).each(function () {
+
+ var
+ sStyle = '',
+ sName = '',
+ oAttachment = self.findAttachmentByCid($(this).attr('data-x-style-cid'))
+ ;
+
+ if (oAttachment && oAttachment.linkPreview)
+ {
+ sName = $(this).attr('data-x-style-cid-name');
+ if ('' !== sName)
+ {
+ sStyle = Utils.trim($(this).attr('style'));
+ sStyle = '' === sStyle ? '' : (';' === sStyle.substr(-1) ? sStyle + ' ' : sStyle + '; ');
+ $(this).attr('style', sStyle + sName + ': url(\'' + oAttachment.linkPreview() + '\')');
+ }
+ }
+ });
+
+ if (bLazy)
+ {
+ (function ($oImg, oContainer) {
+ _.delay(function () {
+ $oImg.addClass('lazy-inited').lazyload({
+ 'threshold': 400,
+ 'effect': 'fadeIn',
+ 'skip_invisible': false,
+ 'container': oContainer
+ });
+ }, 300);
+ }($('img.lazy', self.body), $('.RL-MailMessageView .messageView .messageItem .content')[0]));
+ }
+
+ Utils.windowResize(500);
+ }
+ };
+
+ MessageModel.prototype.storeDataInDom = function ()
+ {
+ if (this.body)
+ {
+ this.body.data('rl-is-html', !!this.isHtml());
+ this.body.data('rl-has-images', !!this.hasImages());
+ }
+ };
+
+ MessageModel.prototype.fetchDataFromDom = function ()
+ {
+ if (this.body)
+ {
+ this.isHtml(!!this.body.data('rl-is-html'));
+ this.hasImages(!!this.body.data('rl-has-images'));
+ }
+ };
+
+ MessageModel.prototype.replacePlaneTextBody = function (sPlain)
+ {
+ if (this.body)
+ {
+ this.body.html(sPlain).addClass('b-text-part plain');
+ }
+ };
+
+ /**
+ * @return {string}
+ */
+ MessageModel.prototype.flagHash = function ()
+ {
+ return [this.deleted(), this.deletedMark(), this.unseen(), this.flagged(), this.answered(), this.forwarded(),
+ this.isReadReceipt()].join(',');
+ };
+
+ module.exports = MessageModel;
+
+ }());
+
+
+/***/ },
+/* 109 */
+/*!*********************************!*\
+ !*** ./dev/Model/OpenPgpKey.js ***!
+ \*********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ PgpStore = __webpack_require__(/*! Stores/User/Pgp */ 33),
+
+ AbstractModel = __webpack_require__(/*! Knoin/AbstractModel */ 27)
+ ;
+
+ /**
+ * @param {string} iIndex
+ * @param {string} sGuID
+ * @param {string} sID
+ * @param {array} aIDs
+ * @param {array} aUserIDs
+ * @param {array} aEmails
+ * @param {boolean} bIsPrivate
+ * @param {string} sArmor
+ * @param {string} sUserID
+ * @constructor
+ */
+ function OpenPgpKeyModel(iIndex, sGuID, sID, aIDs, aUserIDs, aEmails, bIsPrivate, sArmor, sUserID)
+ {
+ AbstractModel.call(this, 'OpenPgpKeyModel');
+
+ this.index = iIndex;
+ this.id = sID;
+ this.ids = Utils.isNonEmptyArray(aIDs) ? aIDs : [sID];
+ this.guid = sGuID;
+ this.users = aUserIDs;
+ this.emails = aEmails;
+ this.armor = sArmor;
+ this.isPrivate = !!bIsPrivate;
+
+ this.selectUser(sUserID);
+
+ this.deleteAccess = ko.observable(false);
+ }
+
+ _.extend(OpenPgpKeyModel.prototype, AbstractModel.prototype);
+
+ OpenPgpKeyModel.prototype.index = 0;
+ OpenPgpKeyModel.prototype.id = '';
+ OpenPgpKeyModel.prototype.ids = [];
+ OpenPgpKeyModel.prototype.guid = '';
+ OpenPgpKeyModel.prototype.user = '';
+ OpenPgpKeyModel.prototype.users = [];
+ OpenPgpKeyModel.prototype.email = '';
+ OpenPgpKeyModel.prototype.emails = [];
+ OpenPgpKeyModel.prototype.armor = '';
+ OpenPgpKeyModel.prototype.isPrivate = false;
+
+ OpenPgpKeyModel.prototype.getNativeKey = function ()
+ {
+ var oKey = null;
+ try
+ {
+ oKey = PgpStore.openpgp.key.readArmored(this.armor);
+ if (oKey && !oKey.err && oKey.keys && oKey.keys[0])
+ {
+ return oKey;
+ }
+ }
+ catch (e)
+ {
+ Utils.log(e);
+ }
+
+ return null;
+ };
+
+ OpenPgpKeyModel.prototype.getNativeKeys = function ()
+ {
+ var oKey = this.getNativeKey();
+ return oKey && oKey.keys ? oKey.keys : null;
+ };
+
+ OpenPgpKeyModel.prototype.select = function (sPattern, sProperty)
+ {
+ if (this[sProperty])
+ {
+ var index = this[sProperty].indexOf(sPattern);
+ if (index !== -1)
+ {
+ this.user = this.users[index];
+ this.email = this.emails[index];
+ }
+ }
+ };
+
+ OpenPgpKeyModel.prototype.selectUser = function (sUser)
+ {
+ this.select(sUser, 'users');
+ };
+
+ OpenPgpKeyModel.prototype.selectEmail = function (sEmail)
+ {
+ this.select(sEmail, 'emails');
+ };
+
+ module.exports = OpenPgpKeyModel;
+
+ }());
+
+
+/***/ },
+/* 110 */
+/*!*******************************!*\
+ !*** ./dev/Model/Template.js ***!
+ \*******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ AbstractModel = __webpack_require__(/*! Knoin/AbstractModel */ 27)
+ ;
+
+ /**
+ * @constructor
+ *
+ * @param {string} sID
+ * @param {string} sName
+ * @param {string} sBody
+ */
+ function TemplateModel(sID, sName, sBody)
+ {
+ AbstractModel.call(this, 'TemplateModel');
+
+ this.id = sID;
+ this.name = sName;
+ this.body = sBody;
+ this.populated = true;
+
+ this.deleteAccess = ko.observable(false);
+ }
+
+ _.extend(TemplateModel.prototype, AbstractModel.prototype);
+
+ /**
+ * @type {string}
+ */
+ TemplateModel.prototype.id = '';
+
+ /**
+ * @type {string}
+ */
+ TemplateModel.prototype.name = '';
+
+ /**
+ * @type {string}
+ */
+ TemplateModel.prototype.body = '';
+
+ /**
+ * @type {boolean}
+ */
+ TemplateModel.prototype.populated = true;
+
+ /**
+ * @type {boolean}
+ */
+ TemplateModel.prototype.parse = function (oItem)
+ {
+ var bResult = false;
+ if (oItem && 'Object/Template' === oItem['@Object'])
+ {
+ this.id = Utils.pString(oItem['ID']);
+ this.name = Utils.pString(oItem['Name']);
+ this.body = Utils.pString(oItem['Body']);
+ this.populated = !!oItem['Populated'];
+
+ bResult = true;
+ }
+
+ return bResult;
+ };
+
+ module.exports = TemplateModel;
+
+ }());
+
+/***/ },
+/* 111 */
+/*!**************************************!*\
+ !*** ./dev/Promises/AbstractAjax.js ***!
+ \**************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ $ = __webpack_require__(/*! $ */ 14),
+ _ = __webpack_require__(/*! _ */ 3),
+ Q = __webpack_require__(/*! Q */ 48),
+
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+ Plugins = __webpack_require__(/*! Common/Plugins */ 23),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+
+ AbstractBasicPromises = __webpack_require__(/*! Promises/AbstractBasic */ 88)
+ ;
+
+ /**
+ * @constructor
+ */
+ function AbstractAjaxPromises()
+ {
+ AbstractBasicPromises.call(this);
+
+ this.clear();
+ }
+
+ _.extend(AbstractAjaxPromises.prototype, AbstractBasicPromises.prototype);
+
+ AbstractAjaxPromises.prototype.oRequests = {};
+
+ AbstractAjaxPromises.prototype.clear = function ()
+ {
+ this.oRequests = {};
+ };
+
+ AbstractAjaxPromises.prototype.abort = function (sAction, bClearOnly)
+ {
+ if (this.oRequests[sAction])
+ {
+ if (!bClearOnly && this.oRequests[sAction].abort)
+ {
+ this.oRequests[sAction].__aborted__ = true;
+ this.oRequests[sAction].abort();
+ }
+
+ this.oRequests[sAction] = null;
+ delete this.oRequests[sAction];
+ }
+
+ return this;
+ };
+
+ AbstractAjaxPromises.prototype.ajaxRequest = function (sAction, bPost, iTimeOut, oParameters, sAdditionalGetString, fTrigger)
+ {
+ var
+ oH = null,
+ self = this,
+ iStart = Utils.microtime(),
+ oDeferred = Q.defer()
+ ;
+
+ iTimeOut = Utils.isNormal(iTimeOut) ? iTimeOut : Consts.DEFAULT_AJAX_TIMEOUT;
+ sAdditionalGetString = Utils.isUnd(sAdditionalGetString) ? '' : Utils.pString(sAdditionalGetString);
+
+ if (bPost)
+ {
+ oParameters['XToken'] = Settings.appSettingsGet('token');
+ }
+
+ Plugins.runHook('ajax-default-request', [sAction, oParameters, sAdditionalGetString]);
+
+ this.setTrigger(fTrigger, true);
+
+ oH = $.ajax({
+ 'type': bPost ? 'POST' : 'GET',
+ 'url': Links.ajax(sAdditionalGetString),
+ 'async': true,
+ 'dataType': 'json',
+ 'data': bPost ? (oParameters || {}) : {},
+ 'timeout': iTimeOut,
+ 'global': true
+ }).always(function (oData, sTextStatus) {
+
+ var bCached = false, oErrorData = null, sType = Enums.StorageResultType.Error;
+ if (oData && oData['Time'])
+ {
+ bCached = Utils.pInt(oData['Time']) > Utils.microtime() - iStart;
+ }
+
+ // backward capability
+ switch (true)
+ {
+ case 'success' === sTextStatus && oData && oData.Result && sAction === oData.Action:
+ sType = Enums.StorageResultType.Success;
+ break;
+ case 'abort' === sTextStatus && (!oData || !oData.__aborted__):
+ sType = Enums.StorageResultType.Abort;
+ break;
+ }
+
+ Plugins.runHook('ajax-default-response', [sAction,
+ Enums.StorageResultType.Success === sType ? oData : null, sType, bCached, oParameters]);
+
+ if ('success' === sTextStatus)
+ {
+ if (oData && oData.Result && sAction === oData.Action)
+ {
+ oData.__cached__ = bCached;
+ oDeferred.resolve(oData);
+ }
+ else if (oData && oData.Action)
+ {
+ oErrorData = oData;
+ oDeferred.reject(oData.ErrorCode ? oData.ErrorCode : Enums.Notification.AjaxFalse);
+ }
+ else
+ {
+ oErrorData = oData;
+ oDeferred.reject(Enums.Notification.AjaxParse);
+ }
+ }
+ else if ('timeout' === sTextStatus)
+ {
+ oErrorData = oData;
+ oDeferred.reject(Enums.Notification.AjaxTimeout);
+ }
+ else if ('abort' === sTextStatus)
+ {
+ if (!oData || !oData.__aborted__)
+ {
+ oDeferred.reject(Enums.Notification.AjaxAbort);
+ }
+ }
+ else
+ {
+ oErrorData = oData;
+ oDeferred.reject(Enums.Notification.AjaxParse);
+ }
+
+ if (self.oRequests[sAction])
+ {
+ self.oRequests[sAction] = null;
+ delete self.oRequests[sAction];
+ }
+
+ self.setTrigger(fTrigger, false);
+
+ if (oErrorData)
+ {
+ if (-1 < Utils.inArray(oErrorData.ErrorCode, [
+ Enums.Notification.AuthError, Enums.Notification.AccessError,
+ Enums.Notification.ConnectionError, Enums.Notification.DomainNotAllowed, Enums.Notification.AccountNotAllowed,
+ Enums.Notification.MailServerError, Enums.Notification.UnknownNotification, Enums.Notification.UnknownError
+ ]))
+ {
+ Globals.iAjaxErrorCount++;
+ }
+
+ if (Enums.Notification.InvalidToken === oErrorData.ErrorCode)
+ {
+ Globals.iTokenErrorCount++;
+ }
+
+ if (Consts.TOKEN_ERROR_LIMIT < Globals.iTokenErrorCount)
+ {
+ if (Globals.__APP__ && Globals.__APP__.loginAndLogoutReload)
+ {
+ Globals.__APP__.loginAndLogoutReload(false, true);
+ }
+ }
+
+ if (oErrorData.ClearAuth || oErrorData.Logout || Consts.AJAX_ERROR_LIMIT < Globals.iAjaxErrorCount)
+ {
+ if (Globals.__APP__ && Globals.__APP__.clearClientSideToken)
+ {
+ Globals.__APP__.clearClientSideToken();
+ }
+
+ if (Globals.__APP__ && !oErrorData.ClearAuth && Globals.__APP__.loginAndLogoutReload)
+ {
+ Globals.__APP__.loginAndLogoutReload(false, true);
+ }
+ }
+ }
+
+ });
+
+ if (oH)
+ {
+ if (this.oRequests[sAction])
+ {
+ this.oRequests[sAction] = null;
+ delete this.oRequests[sAction];
+ }
+
+ this.oRequests[sAction] = oH;
+ }
+
+ return oDeferred.promise;
+ };
+
+ AbstractAjaxPromises.prototype.getRequest = function (sAction, fTrigger, sAdditionalGetString, iTimeOut)
+ {
+ sAdditionalGetString = Utils.isUnd(sAdditionalGetString) ? '' : Utils.pString(sAdditionalGetString);
+ sAdditionalGetString = sAction + '/' + sAdditionalGetString;
+
+ return this.ajaxRequest(sAction, false, iTimeOut, null, sAdditionalGetString, fTrigger);
+ };
+
+ AbstractAjaxPromises.prototype.postRequest = function (sAction, fTrigger, oParameters, iTimeOut)
+ {
+ oParameters = oParameters || {};
+ oParameters['Action'] = sAction;
+
+ return this.ajaxRequest(sAction, true, iTimeOut, oParameters, '', fTrigger);
+ };
+
+ module.exports = AbstractAjaxPromises;
+
+ }());
+
+/***/ },
+/* 112 */
+/*!****************************************!*\
+ !*** ./dev/Promises/User/Populator.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Cache = __webpack_require__(/*! Common/Cache */ 19),
+
+ AppStore = __webpack_require__(/*! Stores/User/App */ 24),
+ FolderStore = __webpack_require__(/*! Stores/User/Folder */ 21),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ Local = __webpack_require__(/*! Storage/Client */ 47),
+
+ FolderModel = __webpack_require__(/*! Model/Folder */ 106),
+
+ AbstractBasicPromises = __webpack_require__(/*! Promises/AbstractBasic */ 88)
+ ;
+
+ /**
+ * @constructor
+ */
+ function PromisesUserPopulator()
+ {
+ AbstractBasicPromises.call(this);
+ }
+
+ _.extend(PromisesUserPopulator.prototype, AbstractBasicPromises.prototype);
+
+ /**
+ * @param {string} sFullNameHash
+ * @return {boolean}
+ */
+ PromisesUserPopulator.prototype.isFolderExpanded = function (sFullNameHash)
+ {
+ var aExpandedList = Local.get(Enums.ClientSideKeyName.ExpandedFolders);
+ return Utils.isArray(aExpandedList) && -1 !== _.indexOf(aExpandedList, sFullNameHash);
+ };
+
+ /**
+ * @param {string} sFolderFullNameRaw
+ * @return {string}
+ */
+ PromisesUserPopulator.prototype.normalizeFolder = function (sFolderFullNameRaw)
+ {
+ return ('' === sFolderFullNameRaw || Consts.UNUSED_OPTION_VALUE === sFolderFullNameRaw ||
+ null !== Cache.getFolderFromCacheList(sFolderFullNameRaw)) ? sFolderFullNameRaw : '';
+ };
+
+ /**
+ * @param {string} sNamespace
+ * @param {Array} aFolders
+ * @return {Array}
+ */
+ PromisesUserPopulator.prototype.folderResponseParseRec = function (sNamespace, aFolders)
+ {
+ var
+ self = this,
+ iIndex = 0,
+ iLen = 0,
+ oFolder = null,
+ oCacheFolder = null,
+ sFolderFullNameRaw = '',
+ aSubFolders = [],
+ aList = []
+ ;
+
+ for (iIndex = 0, iLen = aFolders.length; iIndex < iLen; iIndex++)
+ {
+ oFolder = aFolders[iIndex];
+ if (oFolder)
+ {
+ sFolderFullNameRaw = oFolder.FullNameRaw;
+
+ oCacheFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw);
+ if (!oCacheFolder)
+ {
+ oCacheFolder = FolderModel.newInstanceFromJson(oFolder);
+ if (oCacheFolder)
+ {
+ Cache.setFolderToCacheList(sFolderFullNameRaw, oCacheFolder);
+ Cache.setFolderFullNameRaw(oCacheFolder.fullNameHash, sFolderFullNameRaw, oCacheFolder);
+ }
+ }
+
+ if (oCacheFolder)
+ {
+ if (!FolderStore.displaySpecSetting())
+ {
+ oCacheFolder.checkable(true);
+ }
+ else
+ {
+ oCacheFolder.checkable(!!oFolder.Checkable);
+ }
+
+ oCacheFolder.collapsed(!self.isFolderExpanded(oCacheFolder.fullNameHash));
+
+ if (oFolder.Extended)
+ {
+ if (oFolder.Extended.Hash)
+ {
+ Cache.setFolderHash(oCacheFolder.fullNameRaw, oFolder.Extended.Hash);
+ }
+
+ if (Utils.isNormal(oFolder.Extended.MessageCount))
+ {
+ oCacheFolder.messageCountAll(oFolder.Extended.MessageCount);
+ }
+
+ if (Utils.isNormal(oFolder.Extended.MessageUnseenCount))
+ {
+ oCacheFolder.messageCountUnread(oFolder.Extended.MessageUnseenCount);
+ }
+ }
+
+ aSubFolders = oFolder['SubFolders'];
+ if (aSubFolders && 'Collection/FolderCollection' === aSubFolders['@Object'] &&
+ aSubFolders['@Collection'] && Utils.isArray(aSubFolders['@Collection']))
+ {
+ oCacheFolder.subFolders(
+ this.folderResponseParseRec(sNamespace, aSubFolders['@Collection']));
+ }
+
+ aList.push(oCacheFolder);
+ }
+ }
+ }
+
+ return aList;
+ };
+
+ PromisesUserPopulator.prototype.foldersList = function (oData)
+ {
+ if (oData && 'Collection/FolderCollection' === oData['@Object'] &&
+ oData['@Collection'] && Utils.isArray(oData['@Collection']))
+ {
+ var
+ iLimit = Utils.pInt(Settings.appSettingsGet('folderSpecLimit')),
+ iC = Utils.pInt(oData['CountRec'])
+ ;
+
+ iLimit = 100 < iLimit ? 100 : (10 > iLimit ? 10 : iLimit);
+
+ FolderStore.displaySpecSetting(0 >= iC || iLimit < iC);
+ FolderStore.folderList(this.folderResponseParseRec(
+ Utils.isUnd(oData.Namespace) ? '' : oData.Namespace, oData['@Collection']));
+ }
+ };
+
+ PromisesUserPopulator.prototype.foldersAdditionalParameters = function (oData)
+ {
+ if (oData && oData && 'Collection/FolderCollection' === oData['@Object'] &&
+ oData['@Collection'] && Utils.isArray(oData['@Collection']))
+ {
+ if (!Utils.isUnd(oData.Namespace))
+ {
+ FolderStore.namespace = oData.Namespace;
+ }
+
+ AppStore.threadsAllowed(!!Settings.appSettingsGet('useImapThread') && oData.IsThreadsSupported && true);
+
+ FolderStore.folderList.optimized(!!oData.Optimized);
+
+ var bUpdate = false;
+
+ if (oData['SystemFolders'] && '' === '' +
+ Settings.settingsGet('SentFolder') +
+ Settings.settingsGet('DraftFolder') +
+ Settings.settingsGet('SpamFolder') +
+ Settings.settingsGet('TrashFolder') +
+ Settings.settingsGet('ArchiveFolder') +
+ Settings.settingsGet('NullFolder'))
+ {
+ Settings.settingsSet('SentFolder', oData['SystemFolders'][Enums.ServerFolderType.SENT] || null);
+ Settings.settingsSet('DraftFolder', oData['SystemFolders'][Enums.ServerFolderType.DRAFTS] || null);
+ Settings.settingsSet('SpamFolder', oData['SystemFolders'][Enums.ServerFolderType.JUNK] || null);
+ Settings.settingsSet('TrashFolder', oData['SystemFolders'][Enums.ServerFolderType.TRASH] || null);
+ Settings.settingsSet('ArchiveFolder', oData['SystemFolders'][Enums.ServerFolderType.ALL] || null);
+
+ bUpdate = true;
+ }
+
+ FolderStore.sentFolder(this.normalizeFolder(Settings.settingsGet('SentFolder')));
+ FolderStore.draftFolder(this.normalizeFolder(Settings.settingsGet('DraftFolder')));
+ FolderStore.spamFolder(this.normalizeFolder(Settings.settingsGet('SpamFolder')));
+ FolderStore.trashFolder(this.normalizeFolder(Settings.settingsGet('TrashFolder')));
+ FolderStore.archiveFolder(this.normalizeFolder(Settings.settingsGet('ArchiveFolder')));
+
+ if (bUpdate)
+ {
+ __webpack_require__(/*! Remote/User/Ajax */ 15).saveSystemFolders(Utils.emptyFunction, {
+ 'SentFolder': FolderStore.sentFolder(),
+ 'DraftFolder': FolderStore.draftFolder(),
+ 'SpamFolder': FolderStore.spamFolder(),
+ 'TrashFolder': FolderStore.trashFolder(),
+ 'ArchiveFolder': FolderStore.archiveFolder(),
+ 'NullFolder': 'NullFolder'
+ });
+ }
+
+ Local.set(Enums.ClientSideKeyName.FoldersLashHash, oData.FoldersHash);
+ }
+ };
+
+ module.exports = new PromisesUserPopulator();
+
+ }());
+
+/***/ },
+/* 113 */,
+/* 114 */,
+/* 115 */
+/*!**********************************!*\
+ !*** ./dev/Screen/User/Login.js ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ AbstractScreen = __webpack_require__(/*! Knoin/AbstractScreen */ 39)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractScreen
+ */
+ function LoginUserScreen()
+ {
+ AbstractScreen.call(this, 'login', [
+ __webpack_require__(/*! View/User/Login */ 153)
+ ]);
+ }
+
+ _.extend(LoginUserScreen.prototype, AbstractScreen.prototype);
+
+ LoginUserScreen.prototype.onShow = function ()
+ {
+ __webpack_require__(/*! App/User */ 7).default.setWindowTitle('');
+ };
+
+ module.exports = LoginUserScreen;
+
+ }());
+
+/***/ },
+/* 116 */
+/*!************************************!*\
+ !*** ./dev/Screen/User/MailBox.js ***!
+ \************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Events = __webpack_require__(/*! Common/Events */ 25),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Cache = __webpack_require__(/*! Common/Cache */ 19),
+
+ AppStore = __webpack_require__(/*! Stores/User/App */ 24),
+ AccountStore = __webpack_require__(/*! Stores/User/Account */ 31),
+ SettingsStore = __webpack_require__(/*! Stores/User/Settings */ 28),
+ FolderStore = __webpack_require__(/*! Stores/User/Folder */ 21),
+ MessageStore = __webpack_require__(/*! Stores/User/Message */ 32),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+
+ AbstractScreen = __webpack_require__(/*! Knoin/AbstractScreen */ 39)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractScreen
+ */
+ function MailBoxUserScreen()
+ {
+ AbstractScreen.call(this, 'mailbox', [
+ __webpack_require__(/*! View/User/MailBox/SystemDropDown */ 157),
+ __webpack_require__(/*! View/User/MailBox/FolderList */ 154),
+ __webpack_require__(/*! View/User/MailBox/MessageList */ 155),
+ __webpack_require__(/*! View/User/MailBox/MessageView */ 156)
+ ]);
+
+ this.oLastRoute = {};
+ }
+
+ _.extend(MailBoxUserScreen.prototype, AbstractScreen.prototype);
+
+ /**
+ * @type {Object}
+ */
+ MailBoxUserScreen.prototype.oLastRoute = {};
+
+ MailBoxUserScreen.prototype.updateWindowTitle = function ()
+ {
+ var
+ sEmail = AccountStore.email(),
+ nFoldersInboxUnreadCount = FolderStore.foldersInboxUnreadCount()
+ ;
+
+ if (Settings.appSettingsGet('listPermanentFiltered'))
+ {
+ nFoldersInboxUnreadCount = 0;
+ }
+
+ __webpack_require__(/*! App/User */ 7).default.setWindowTitle(('' === sEmail ? '' : '' +
+ (0 < nFoldersInboxUnreadCount ? '(' + nFoldersInboxUnreadCount + ') ' : ' ') +
+ sEmail + ' - ') + Translator.i18n('TITLES/MAILBOX'));
+ };
+
+ MailBoxUserScreen.prototype.onShow = function ()
+ {
+ this.updateWindowTitle();
+
+ AppStore.focusedState(Enums.Focused.None);
+ AppStore.focusedState(Enums.Focused.MessageList);
+
+ if (Settings.appSettingsGet('mobile'))
+ {
+ Globals.leftPanelDisabled(true);
+ }
+
+ if (!Settings.capa(Enums.Capa.Folders))
+ {
+ Globals.leftPanelType(
+ Settings.capa(Enums.Capa.Composer) || Settings.capa(Enums.Capa.Contacts) ? 'short' : 'none');
+ }
+ else
+ {
+ Globals.leftPanelType('');
+ }
+ };
+
+ /**
+ * @param {string} sFolderHash
+ * @param {number} iPage
+ * @param {string} sSearch
+ */
+ MailBoxUserScreen.prototype.onRoute = function (sFolderHash, iPage, sSearch)
+ {
+ var
+ sThreadUid = sFolderHash.replace(/^(.+)~([\d]+)$/, '$2'),
+ oFolder = Cache.getFolderFromCacheList(Cache.getFolderFullNameRaw(
+ sFolderHash.replace(/~([\d]+)$/, '')))
+ ;
+
+ if (oFolder)
+ {
+ if (sFolderHash === sThreadUid)
+ {
+ sThreadUid = '';
+ }
+
+ FolderStore.currentFolder(oFolder);
+
+ MessageStore.messageListPage(iPage);
+ MessageStore.messageListSearch(sSearch);
+ MessageStore.messageListThreadUid(sThreadUid);
+
+ __webpack_require__(/*! App/User */ 7).default.reloadMessageList();
+ }
+ };
+
+ MailBoxUserScreen.prototype.onStart = function ()
+ {
+ FolderStore.folderList.subscribe(Utils.windowResizeCallback);
+
+ MessageStore.messageList.subscribe(Utils.windowResizeCallback);
+ MessageStore.message.subscribe(Utils.windowResizeCallback);
+
+ _.delay(function () {
+ SettingsStore.layout.valueHasMutated();
+ }, 50);
+
+ Events.sub('mailbox.inbox-unread-count', _.bind(function (iCount) {
+
+ FolderStore.foldersInboxUnreadCount(iCount);
+
+ var sEmail = AccountStore.email();
+
+ _.each(AccountStore.accounts(), function (oItem) {
+ if (oItem && sEmail === oItem.email)
+ {
+ oItem.count(iCount);
+ }
+ });
+
+ this.updateWindowTitle();
+
+ }, this));
+ };
+
+ MailBoxUserScreen.prototype.onBuild = function ()
+ {
+ if (!Globals.bMobileDevice && !Settings.appSettingsGet('mobile'))
+ {
+ _.defer(function () {
+ __webpack_require__(/*! App/User */ 7).default.initHorizontalLayoutResizer(Enums.ClientSideKeyName.MessageListSize);
+ });
+ }
+ };
+
+ /**
+ * @return {Array}
+ */
+ MailBoxUserScreen.prototype.routes = function ()
+ {
+ var
+ sInboxFolderName = Cache.getFolderInboxName(),
+ fNormS = function (oRequest, oVals) {
+ oVals[0] = Utils.pString(oVals[0]);
+ oVals[1] = Utils.pInt(oVals[1]);
+ oVals[1] = 0 >= oVals[1] ? 1 : oVals[1];
+ oVals[2] = Utils.pString(oVals[2]);
+
+ if ('' === oRequest)
+ {
+ oVals[0] = sInboxFolderName;
+ oVals[1] = 1;
+ }
+
+ return [decodeURI(oVals[0]), oVals[1], decodeURI(oVals[2])];
+ },
+ fNormD = function (oRequest, oVals) {
+ oVals[0] = Utils.pString(oVals[0]);
+ oVals[1] = Utils.pString(oVals[1]);
+
+ if ('' === oRequest)
+ {
+ oVals[0] = sInboxFolderName;
+ }
+
+ return [decodeURI(oVals[0]), 1, decodeURI(oVals[1])];
+ }
+ ;
+
+ return [
+ [/^([a-zA-Z0-9~]+)\/p([1-9][0-9]*)\/(.+)\/?$/, {'normalize_': fNormS}],
+ [/^([a-zA-Z0-9~]+)\/p([1-9][0-9]*)$/, {'normalize_': fNormS}],
+ [/^([a-zA-Z0-9~]+)\/(.+)\/?$/, {'normalize_': fNormD}],
+ [/^([^\/]*)$/, {'normalize_': fNormS}]
+ ];
+ };
+
+ module.exports = MailBoxUserScreen;
+
+ }());
+
+/***/ },
+/* 117 */
+/*!*************************************!*\
+ !*** ./dev/Screen/User/Settings.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Plugins = __webpack_require__(/*! Common/Plugins */ 23),
+
+ AppStore = __webpack_require__(/*! Stores/User/App */ 24),
+ AccountStore = __webpack_require__(/*! Stores/User/Account */ 31),
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+
+ AbstractSettingsScreen = __webpack_require__(/*! Screen/AbstractSettings */ 56)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractSettingsScreen
+ */
+ function SettingsUserScreen()
+ {
+ AbstractSettingsScreen.call(this, [
+ __webpack_require__(/*! View/User/Settings/SystemDropDown */ 160),
+ __webpack_require__(/*! View/User/Settings/Menu */ 158),
+ __webpack_require__(/*! View/User/Settings/Pane */ 159)
+ ]);
+
+ Translator.initOnStartOrLangChange(function () {
+ this.sSettingsTitle = Translator.i18n('TITLES/SETTINGS');
+ }, this, function () {
+ this.setSettingsTitle();
+ });
+ }
+
+ _.extend(SettingsUserScreen.prototype, AbstractSettingsScreen.prototype);
+
+ /**
+ * @param {Function=} fCallback
+ */
+ SettingsUserScreen.prototype.setupSettings = function (fCallback)
+ {
+ if (!Settings.capa(Enums.Capa.Settings))
+ {
+ if (fCallback)
+ {
+ fCallback();
+ }
+
+ return false;
+ }
+
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/User/General */ 133),
+ 'SettingsGeneral', 'SETTINGS_LABELS/LABEL_GENERAL_NAME', 'general', true);
+
+ if (AppStore.contactsIsAllowed())
+ {
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/User/Contacts */ 130),
+ 'SettingsContacts', 'SETTINGS_LABELS/LABEL_CONTACTS_NAME', 'contacts');
+ }
+
+ if (Settings.capa(Enums.Capa.AdditionalAccounts) || Settings.capa(Enums.Capa.Identities))
+ {
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/User/Accounts */ 128), 'SettingsAccounts',
+ Settings.capa(Enums.Capa.AdditionalAccounts) ?
+ 'SETTINGS_LABELS/LABEL_ACCOUNTS_NAME' : 'SETTINGS_LABELS/LABEL_IDENTITIES_NAME', 'accounts');
+ }
+
+ if (Settings.capa(Enums.Capa.Sieve))
+ {
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/User/Filters */ 131),
+ 'SettingsFilters', 'SETTINGS_LABELS/LABEL_FILTERS_NAME', 'filters');
+ }
+
+ if (Settings.capa(Enums.Capa.AutoLogout) || Settings.capa(Enums.Capa.TwoFactor))
+ {
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/User/Security */ 135),
+ 'SettingsSecurity', 'SETTINGS_LABELS/LABEL_SECURITY_NAME', 'security');
+ }
+
+ if (AccountStore.isRootAccount() && (
+ (Settings.settingsGet('AllowGoogleSocial') && Settings.settingsGet('AllowGoogleSocialAuth')) ||
+ Settings.settingsGet('AllowFacebookSocial') ||
+ Settings.settingsGet('AllowTwitterSocial')))
+ {
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/User/Social */ 136),
+ 'SettingsSocial', 'SETTINGS_LABELS/LABEL_SOCIAL_NAME', 'social');
+ }
+
+ if (Settings.settingsGet('ChangePasswordIsAllowed'))
+ {
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/User/ChangePassword */ 129),
+ 'SettingsChangePassword', 'SETTINGS_LABELS/LABEL_CHANGE_PASSWORD_NAME', 'change-password');
+ }
+
+ if (Settings.capa(Enums.Capa.Templates))
+ {
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/User/Templates */ 137),
+ 'SettingsTemplates', 'SETTINGS_LABELS/LABEL_TEMPLATES_NAME', 'templates');
+ }
+
+ if (Settings.capa(Enums.Capa.Folders))
+ {
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/User/Folders */ 132),
+ 'SettingsFolders', 'SETTINGS_LABELS/LABEL_FOLDERS_NAME', 'folders');
+ }
+
+ if (Settings.capa(Enums.Capa.Themes))
+ {
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/User/Themes */ 138),
+ 'SettingsThemes', 'SETTINGS_LABELS/LABEL_THEMES_NAME', 'themes');
+ }
+
+ if (Settings.capa(Enums.Capa.OpenPGP))
+ {
+ kn.addSettingsViewModel(__webpack_require__(/*! Settings/User/OpenPgp */ 134),
+ 'SettingsOpenPGP', 'SETTINGS_LABELS/LABEL_OPEN_PGP_NAME', 'openpgp');
+ }
+
+ Plugins.runSettingsViewModelHooks(false);
+
+ if (fCallback)
+ {
+ fCallback();
+ }
+
+ return true;
+ };
+
+ SettingsUserScreen.prototype.onShow = function ()
+ {
+ this.setSettingsTitle();
+ Globals.keyScope(Enums.KeyState.Settings);
+ Globals.leftPanelType('');
+
+ if (Settings.appSettingsGet('mobile'))
+ {
+ Globals.leftPanelDisabled(true);
+ }
+ };
+
+ SettingsUserScreen.prototype.setSettingsTitle = function ()
+ {
+ var sEmail = AccountStore.email();
+ __webpack_require__(/*! App/User */ 7).default.setWindowTitle(('' === sEmail ? '' : sEmail + ' - ') + this.sSettingsTitle);
+ };
+
+ module.exports = SettingsUserScreen;
+
+ }());
+
+/***/ },
+/* 118 */,
+/* 119 */,
+/* 120 */,
+/* 121 */,
+/* 122 */,
+/* 123 */,
+/* 124 */,
+/* 125 */,
+/* 126 */,
+/* 127 */,
+/* 128 */
+/*!***************************************!*\
+ !*** ./dev/Settings/User/Accounts.js ***!
+ \***************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+
+ AccountStore = __webpack_require__(/*! Stores/User/Account */ 31),
+ IdentityStore = __webpack_require__(/*! Stores/User/Identity */ 53),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15)
+ ;
+
+ /**
+ * @constructor
+ */
+ function AccountsUserSettings()
+ {
+ this.allowAdditionalAccount = Settings.capa(Enums.Capa.AdditionalAccounts);
+ this.allowIdentities = Settings.capa(Enums.Capa.Identities);
+
+ this.accounts = AccountStore.accounts;
+ this.identities = IdentityStore.identities;
+
+ this.accountForDeletion = ko.observable(null).deleteAccessHelper();
+ this.identityForDeletion = ko.observable(null).deleteAccessHelper();
+ }
+
+ AccountsUserSettings.prototype.scrollableOptions = function (sWrapper)
+ {
+ return {
+ handle: '.drag-handle',
+ containment: sWrapper || 'parent',
+ axis: 'y'
+ };
+ };
+
+ AccountsUserSettings.prototype.addNewAccount = function ()
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Account */ 61));
+ };
+
+ AccountsUserSettings.prototype.editAccount = function (oAccountItem)
+ {
+ if (oAccountItem && oAccountItem.canBeEdit())
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Account */ 61), [oAccountItem]);
+ }
+ };
+
+ AccountsUserSettings.prototype.addNewIdentity = function ()
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Identity */ 63));
+ };
+
+ AccountsUserSettings.prototype.editIdentity = function (oIdentity)
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Identity */ 63), [oIdentity]);
+ };
+
+ /**
+ * @param {AccountModel} oAccountToRemove
+ */
+ AccountsUserSettings.prototype.deleteAccount = function (oAccountToRemove)
+ {
+ if (oAccountToRemove && oAccountToRemove.deleteAccess())
+ {
+ this.accountForDeletion(null);
+
+ var
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ fRemoveAccount = function (oAccount) {
+ return oAccountToRemove === oAccount;
+ }
+ ;
+
+ if (oAccountToRemove)
+ {
+ this.accounts.remove(fRemoveAccount);
+
+ Remote.accountDelete(function (sResult, oData) {
+
+ if (Enums.StorageResultType.Success === sResult && oData &&
+ oData.Result && oData.Reload)
+ {
+ kn.routeOff();
+ kn.setHash(Links.root(), true);
+ kn.routeOff();
+
+ _.defer(function () {
+ window.location.reload();
+ });
+ }
+ else
+ {
+ __webpack_require__(/*! App/User */ 7).default.accountsAndIdentities();
+ }
+
+ }, oAccountToRemove.email);
+ }
+ }
+ };
+
+ /**
+ * @param {IdentityModel} oIdentityToRemove
+ */
+ AccountsUserSettings.prototype.deleteIdentity = function (oIdentityToRemove)
+ {
+ if (oIdentityToRemove && oIdentityToRemove.deleteAccess())
+ {
+ this.identityForDeletion(null);
+
+ if (oIdentityToRemove)
+ {
+ IdentityStore.identities.remove(function (oIdentity) {
+ return oIdentityToRemove === oIdentity;
+ });
+
+ Remote.identityDelete(function () {
+ __webpack_require__(/*! App/User */ 7).default.accountsAndIdentities();
+ }, oIdentityToRemove.id);
+ }
+ }
+ };
+
+ AccountsUserSettings.prototype.accountsAndIdentitiesAfterMove = function ()
+ {
+ Remote.accountsAndIdentitiesSortOrder(null,
+ AccountStore.accountsEmails.peek(), IdentityStore.identitiesIDS.peek());
+ };
+
+ AccountsUserSettings.prototype.onBuild = function (oDom)
+ {
+ var self = this;
+
+ oDom
+ .on('click', '.accounts-list .account-item .e-action', function () {
+ var oAccountItem = ko.dataFor(this);
+ if (oAccountItem)
+ {
+ self.editAccount(oAccountItem);
+ }
+ })
+ .on('click', '.identities-list .identity-item .e-action', function () {
+ var oIdentityItem = ko.dataFor(this);
+ if (oIdentityItem)
+ {
+ self.editIdentity(oIdentityItem);
+ }
+ })
+ ;
+ };
+
+ module.exports = AccountsUserSettings;
+
+ }());
+
+/***/ },
+/* 129 */
+/*!*********************************************!*\
+ !*** ./dev/Settings/User/ChangePassword.js ***!
+ \*********************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15)
+ ;
+
+ /**
+ * @constructor
+ */
+ function ChangePasswordUserSettings()
+ {
+ this.changeProcess = ko.observable(false);
+
+ this.errorDescription = ko.observable('');
+ this.passwordMismatch = ko.observable(false);
+ this.passwordUpdateError = ko.observable(false);
+ this.passwordUpdateSuccess = ko.observable(false);
+
+ this.currentPassword = ko.observable('');
+ this.currentPassword.error = ko.observable(false);
+ this.newPassword = ko.observable('');
+ this.newPassword2 = ko.observable('');
+
+ this.currentPassword.subscribe(function () {
+ this.passwordUpdateError(false);
+ this.passwordUpdateSuccess(false);
+ this.currentPassword.error(false);
+ }, this);
+
+ this.newPassword.subscribe(function () {
+ this.passwordUpdateError(false);
+ this.passwordUpdateSuccess(false);
+ this.passwordMismatch(false);
+ }, this);
+
+ this.newPassword2.subscribe(function () {
+ this.passwordUpdateError(false);
+ this.passwordUpdateSuccess(false);
+ this.passwordMismatch(false);
+ }, this);
+
+ this.saveNewPasswordCommand = Utils.createCommand(this, function () {
+
+ if (this.newPassword() !== this.newPassword2())
+ {
+ this.passwordMismatch(true);
+ this.errorDescription(Translator.i18n('SETTINGS_CHANGE_PASSWORD/ERROR_PASSWORD_MISMATCH'));
+ }
+ else
+ {
+ this.changeProcess(true);
+
+ this.passwordUpdateError(false);
+ this.passwordUpdateSuccess(false);
+ this.currentPassword.error(false);
+ this.passwordMismatch(false);
+ this.errorDescription('');
+
+ Remote.changePassword(this.onChangePasswordResponse, this.currentPassword(), this.newPassword());
+ }
+
+ }, function () {
+ return !this.changeProcess() && '' !== this.currentPassword() &&
+ '' !== this.newPassword() && '' !== this.newPassword2();
+ });
+
+ this.onChangePasswordResponse = _.bind(this.onChangePasswordResponse, this);
+ }
+
+ ChangePasswordUserSettings.prototype.onHide = function ()
+ {
+ this.changeProcess(false);
+ this.currentPassword('');
+ this.newPassword('');
+ this.newPassword2('');
+ this.errorDescription('');
+ this.passwordMismatch(false);
+ this.currentPassword.error(false);
+ };
+
+ ChangePasswordUserSettings.prototype.onChangePasswordResponse = function (sResult, oData)
+ {
+ this.changeProcess(false);
+ this.passwordMismatch(false);
+ this.errorDescription('');
+ this.currentPassword.error(false);
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ this.currentPassword('');
+ this.newPassword('');
+ this.newPassword2('');
+
+ this.passwordUpdateSuccess(true);
+ this.currentPassword.error(false);
+
+ __webpack_require__(/*! App/User */ 7).default.setClientSideToken(oData.Result);
+ }
+ else
+ {
+ if (oData && Enums.Notification.CurrentPasswordIncorrect === oData.ErrorCode)
+ {
+ this.currentPassword.error(true);
+ }
+
+ this.passwordUpdateError(true);
+ this.errorDescription(
+ Translator.getNotificationFromResponse(oData, Enums.Notification.CouldNotSaveNewPassword));
+ }
+ };
+
+ module.exports = ChangePasswordUserSettings;
+
+ }());
+
+/***/ },
+/* 130 */
+/*!***************************************!*\
+ !*** ./dev/Settings/User/Contacts.js ***!
+ \***************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2),
+
+ AppStore = __webpack_require__(/*! Stores/User/App */ 24),
+ ContactStore = __webpack_require__(/*! Stores/User/Contact */ 51),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15)
+ ;
+
+ /**
+ * @constructor
+ */
+ function ContactsUserSettings()
+ {
+ this.contactsAutosave = AppStore.contactsAutosave;
+
+ this.allowContactsSync = ContactStore.allowContactsSync;
+ this.enableContactsSync = ContactStore.enableContactsSync;
+ this.contactsSyncUrl = ContactStore.contactsSyncUrl;
+ this.contactsSyncUser = ContactStore.contactsSyncUser;
+ this.contactsSyncPass = ContactStore.contactsSyncPass;
+
+ this.saveTrigger = ko.computed(function () {
+ return [
+ this.enableContactsSync() ? '1' : '0',
+ this.contactsSyncUrl(),
+ this.contactsSyncUser(),
+ this.contactsSyncPass()
+ ].join('|');
+ }, this).extend({'throttle': 500});
+ }
+
+ ContactsUserSettings.prototype.onBuild = function ()
+ {
+ this.contactsAutosave.subscribe(function (bValue) {
+ Remote.saveSettings(null, {
+ 'ContactsAutosave': bValue ? '1' : '0'
+ });
+ });
+
+ this.saveTrigger.subscribe(function () {
+ Remote.saveContactsSyncData(null,
+ this.enableContactsSync(),
+ this.contactsSyncUrl(),
+ this.contactsSyncUser(),
+ this.contactsSyncPass()
+ );
+ }, this);
+ };
+
+ module.exports = ContactsUserSettings;
+
+ }());
+
+/***/ },
+/* 131 */
+/*!**************************************!*\
+ !*** ./dev/Settings/User/Filters.js ***!
+ \**************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2),
+ _ = __webpack_require__(/*! _ */ 3),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ FilterStore = __webpack_require__(/*! Stores/User/Filter */ 90),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15)
+ ;
+
+ /**
+ * @constructor
+ */
+ function FiltersUserSettings()
+ {
+ var self = this;
+
+ this.modules = FilterStore.modules;
+ this.filters = FilterStore.filters;
+
+ this.inited = ko.observable(false);
+ this.serverError = ko.observable(false);
+ this.serverErrorDesc = ko.observable('');
+ this.haveChanges = ko.observable(false);
+
+ this.saveErrorText = ko.observable('');
+
+ this.filters.subscribe(Utils.windowResizeCallback);
+
+ this.serverError.subscribe(function (bValue) {
+ if (!bValue)
+ {
+ this.serverErrorDesc('');
+ }
+ }, this);
+
+ this.filterRaw = FilterStore.raw;
+ this.filterRaw.capa = FilterStore.capa;
+ this.filterRaw.active = ko.observable(false);
+ this.filterRaw.allow = ko.observable(false);
+ this.filterRaw.error = ko.observable(false);
+
+ this.filterForDeletion = ko.observable(null).extend({'falseTimeout': 3000}).extend(
+ {'toggleSubscribeProperty': [this, 'deleteAccess']});
+
+ this.saveChanges = Utils.createCommand(this, function () {
+
+ if (!this.filters.saving())
+ {
+ if (this.filterRaw.active() && '' === Utils.trim(this.filterRaw()))
+ {
+ this.filterRaw.error(true);
+ return false;
+ }
+
+ this.filters.saving(true);
+ this.saveErrorText('');
+
+ Remote.filtersSave(function (sResult, oData) {
+
+ self.filters.saving(false);
+
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ self.haveChanges(false);
+ self.updateList();
+ }
+ else if (oData && oData.ErrorCode)
+ {
+ self.saveErrorText(oData.ErrorMessageAdditional || Translator.getNotification(oData.ErrorCode));
+ }
+ else
+ {
+ self.saveErrorText(Translator.getNotification(Enums.Notification.CantSaveFilters));
+ }
+
+ }, this.filters(), this.filterRaw(), this.filterRaw.active());
+ }
+
+ return true;
+
+ }, function () {
+ return this.haveChanges();
+ });
+
+ this.filters.subscribe(function () {
+ this.haveChanges(true);
+ }, this);
+
+ this.filterRaw.subscribe(function () {
+ this.haveChanges(true);
+ this.filterRaw.error(false);
+ }, this);
+
+ this.haveChanges.subscribe(function () {
+ this.saveErrorText('');
+ }, this);
+
+ this.filterRaw.active.subscribe(function () {
+ this.haveChanges(true);
+ this.filterRaw.error(false);
+ }, this);
+ }
+
+ FiltersUserSettings.prototype.scrollableOptions = function (sWrapper)
+ {
+ return {
+ handle: '.drag-handle',
+ containment: sWrapper || 'parent',
+ axis: 'y'
+ };
+ };
+
+ FiltersUserSettings.prototype.updateList = function ()
+ {
+ var
+ self = this,
+ FilterModel = __webpack_require__(/*! Model/Filter */ 87)
+ ;
+
+ if (!this.filters.loading())
+ {
+ this.filters.loading(true);
+
+ Remote.filtersGet(function (sResult, oData) {
+
+ self.filters.loading(false);
+ self.serverError(false);
+
+ if (Enums.StorageResultType.Success === sResult && oData &&
+ oData.Result && Utils.isArray(oData.Result.Filters))
+ {
+ self.inited(true);
+ self.serverError(false);
+
+ var aResult = _.compact(_.map(oData.Result.Filters, function (aItem) {
+ var oNew = new FilterModel();
+ return (oNew && oNew.parse(aItem)) ? oNew : null;
+ }));
+
+ self.filters(aResult);
+
+ self.modules(oData.Result.Modules ? oData.Result.Modules : {});
+
+ self.filterRaw(oData.Result.Raw || '');
+ self.filterRaw.capa(Utils.isArray(oData.Result.Capa) ? oData.Result.Capa.join(' ') : '');
+ self.filterRaw.active(!!oData.Result.RawIsActive);
+ self.filterRaw.allow(!!oData.Result.RawIsAllow);
+ }
+ else
+ {
+ self.filters([]);
+ self.modules({});
+ self.filterRaw('');
+ self.filterRaw.capa({});
+
+ self.serverError(true);
+ self.serverErrorDesc(oData && oData.ErrorCode ? Translator.getNotification(oData.ErrorCode) :
+ Translator.getNotification(Enums.Notification.CantGetFilters));
+ }
+
+ self.haveChanges(false);
+ });
+ }
+ };
+
+ FiltersUserSettings.prototype.deleteFilter = function (oFilter)
+ {
+ this.filters.remove(oFilter);
+ Utils.delegateRunOnDestroy(oFilter);
+ };
+
+ FiltersUserSettings.prototype.addFilter = function ()
+ {
+ var
+ self = this,
+ FilterModel = __webpack_require__(/*! Model/Filter */ 87),
+ oNew = new FilterModel()
+ ;
+
+ oNew.generateID();
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(
+ __webpack_require__(/*! View/Popup/Filter */ 94), [oNew, function () {
+ self.filters.push(oNew);
+ self.filterRaw.active(false);
+ }, false]);
+ };
+
+ FiltersUserSettings.prototype.editFilter = function (oEdit)
+ {
+ var
+ self = this,
+ oCloned = oEdit.cloneSelf()
+ ;
+
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(
+ __webpack_require__(/*! View/Popup/Filter */ 94), [oCloned, function () {
+
+ var
+ aFilters = self.filters(),
+ iIndex = aFilters.indexOf(oEdit)
+ ;
+
+ if (-1 < iIndex && aFilters[iIndex])
+ {
+ Utils.delegateRunOnDestroy(aFilters[iIndex]);
+ aFilters[iIndex] = oCloned;
+
+ self.filters(aFilters);
+ self.haveChanges(true);
+ }
+
+ }, true]);
+ };
+
+ FiltersUserSettings.prototype.onBuild = function (oDom)
+ {
+ var self = this;
+
+ oDom
+ .on('click', '.filter-item .e-action', function () {
+ var oFilterItem = ko.dataFor(this);
+ if (oFilterItem)
+ {
+ self.editFilter(oFilterItem);
+ }
+ })
+ ;
+ };
+
+ FiltersUserSettings.prototype.onShow = function ()
+ {
+ this.updateList();
+ };
+
+ module.exports = FiltersUserSettings;
+
+ }());
+
+/***/ },
+/* 132 */
+/*!**************************************!*\
+ !*** ./dev/Settings/User/Folders.js ***!
+ \**************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Cache = __webpack_require__(/*! Common/Cache */ 19),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ Local = __webpack_require__(/*! Storage/Client */ 47),
+
+ FolderStore = __webpack_require__(/*! Stores/User/Folder */ 21),
+
+ Promises = __webpack_require__(/*! Promises/User/Ajax */ 41),
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15)
+ ;
+
+ /**
+ * @constructor
+ */
+ function FoldersUserSettings()
+ {
+ this.displaySpecSetting = FolderStore.displaySpecSetting;
+ this.folderList = FolderStore.folderList;
+
+ this.folderListHelp = ko.observable('').extend({'throttle': 100});
+
+ this.loading = ko.computed(function () {
+
+ var
+ bLoading = FolderStore.foldersLoading(),
+ bCreating = FolderStore.foldersCreating(),
+ bDeleting = FolderStore.foldersDeleting(),
+ bRenaming = FolderStore.foldersRenaming()
+ ;
+
+ return bLoading || bCreating || bDeleting || bRenaming;
+
+ }, this);
+
+ this.folderForDeletion = ko.observable(null).deleteAccessHelper();
+
+ this.folderForEdit = ko.observable(null).extend({'toggleSubscribe': [this,
+ function (oPrev) {
+ if (oPrev)
+ {
+ oPrev.edited(false);
+ }
+ }, function (oNext) {
+ if (oNext && oNext.canBeEdited())
+ {
+ oNext.edited(true);
+ }
+ }
+ ]});
+
+ this.useImapSubscribe = !!Settings.appSettingsGet('useImapSubscribe');
+ }
+
+ FoldersUserSettings.prototype.folderEditOnEnter = function (oFolder)
+ {
+ var
+ sEditName = oFolder ? Utils.trim(oFolder.nameForEdit()) : ''
+ ;
+
+ if ('' !== sEditName && oFolder.name() !== sEditName)
+ {
+ Local.set(Enums.ClientSideKeyName.FoldersLashHash, '');
+
+ __webpack_require__(/*! App/User */ 7).default.foldersPromisesActionHelper(
+ Promises.folderRename(oFolder.fullNameRaw, sEditName, FolderStore.foldersRenaming),
+ Enums.Notification.CantRenameFolder);
+
+ Cache.removeFolderFromCacheList(oFolder.fullNameRaw);
+
+ oFolder.name(sEditName);
+ }
+
+ oFolder.edited(false);
+ };
+
+ FoldersUserSettings.prototype.folderEditOnEsc = function (oFolder)
+ {
+ if (oFolder)
+ {
+ oFolder.edited(false);
+ }
+ };
+
+ FoldersUserSettings.prototype.onShow = function ()
+ {
+ FolderStore.folderList.error('');
+ };
+
+ FoldersUserSettings.prototype.onBuild = function (oDom)
+ {
+ var self = this;
+ oDom
+ .on('mouseover', '.delete-folder-parent', function () {
+ self.folderListHelp(Translator.i18n('SETTINGS_FOLDERS/HELP_DELETE_FOLDER'));
+ })
+ .on('mouseover', '.subscribe-folder-parent', function () {
+ self.folderListHelp(Translator.i18n('SETTINGS_FOLDERS/HELP_SHOW_HIDE_FOLDER'));
+ })
+ .on('mouseover', '.check-folder-parent', function () {
+ self.folderListHelp(Translator.i18n('SETTINGS_FOLDERS/HELP_CHECK_FOR_NEW_MESSAGES'));
+ })
+ .on('mouseout', '.subscribe-folder-parent, .check-folder-parent, .delete-folder-parent', function () {
+ self.folderListHelp('');
+ })
+ ;
+ };
+
+ FoldersUserSettings.prototype.createFolder = function ()
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/FolderCreate */ 95));
+ };
+
+ FoldersUserSettings.prototype.systemFolder = function ()
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/FolderSystem */ 52));
+ };
+
+ FoldersUserSettings.prototype.deleteFolder = function (oFolderToRemove)
+ {
+ if (oFolderToRemove && oFolderToRemove.canBeDeleted() && oFolderToRemove.deleteAccess() &&
+ 0 === oFolderToRemove.privateMessageCountAll())
+ {
+ this.folderForDeletion(null);
+
+ var
+ fRemoveFolder = function (oFolder) {
+
+ if (oFolderToRemove === oFolder)
+ {
+ return true;
+ }
+
+ oFolder.subFolders.remove(fRemoveFolder);
+ return false;
+ }
+ ;
+
+ if (oFolderToRemove)
+ {
+ Local.set(Enums.ClientSideKeyName.FoldersLashHash, '');
+
+ FolderStore.folderList.remove(fRemoveFolder);
+
+ __webpack_require__(/*! App/User */ 7).default.foldersPromisesActionHelper(
+ Promises.folderDelete(oFolderToRemove.fullNameRaw, FolderStore.foldersDeleting),
+ Enums.Notification.CantDeleteFolder);
+
+ Cache.removeFolderFromCacheList(oFolderToRemove.fullNameRaw);
+ }
+ }
+ else if (0 < oFolderToRemove.privateMessageCountAll())
+ {
+ FolderStore.folderList.error(Translator.getNotification(Enums.Notification.CantDeleteNonEmptyFolder));
+ }
+ };
+
+ FoldersUserSettings.prototype.subscribeFolder = function (oFolder)
+ {
+ Local.set(Enums.ClientSideKeyName.FoldersLashHash, '');
+ Remote.folderSetSubscribe(Utils.emptyFunction, oFolder.fullNameRaw, true);
+
+ oFolder.subScribed(true);
+ };
+
+ FoldersUserSettings.prototype.unSubscribeFolder = function (oFolder)
+ {
+ Local.set(Enums.ClientSideKeyName.FoldersLashHash, '');
+ Remote.folderSetSubscribe(Utils.emptyFunction, oFolder.fullNameRaw, false);
+
+ oFolder.subScribed(false);
+ };
+
+ FoldersUserSettings.prototype.checkableTrueFolder = function (oFolder)
+ {
+ Remote.folderSetCheckable(Utils.emptyFunction, oFolder.fullNameRaw, true);
+
+ oFolder.checkable(true);
+ };
+
+ FoldersUserSettings.prototype.checkableFalseFolder = function (oFolder)
+ {
+ Remote.folderSetCheckable(Utils.emptyFunction, oFolder.fullNameRaw, false);
+
+ oFolder.checkable(false);
+ };
+
+ module.exports = FoldersUserSettings;
+
+ }());
+
+/***/ },
+/* 133 */
+/*!**************************************!*\
+ !*** ./dev/Settings/User/General.js ***!
+ \**************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ AppStore = __webpack_require__(/*! Stores/User/App */ 24),
+ LanguageStore = __webpack_require__(/*! Stores/Language */ 40),
+ SettingsStore = __webpack_require__(/*! Stores/User/Settings */ 28),
+ IdentityStore = __webpack_require__(/*! Stores/User/Identity */ 53),
+ NotificationStore = __webpack_require__(/*! Stores/User/Notification */ 60),
+ MessageStore = __webpack_require__(/*! Stores/User/Message */ 32),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15)
+ ;
+
+ /**
+ * @constructor
+ */
+ function GeneralUserSettings()
+ {
+ this.language = LanguageStore.language;
+ this.languages = LanguageStore.languages;
+ this.messagesPerPage = SettingsStore.messagesPerPage;
+ this.messagesPerPageArray = Consts.MESSAGES_PER_PAGE_VALUES;
+
+ this.editorDefaultType = SettingsStore.editorDefaultType;
+ this.layout = SettingsStore.layout;
+ this.usePreviewPane = SettingsStore.usePreviewPane;
+
+ this.soundNotificationIsSupported = NotificationStore.soundNotificationIsSupported;
+ this.enableSoundNotification = NotificationStore.enableSoundNotification;
+
+ this.enableDesktopNotification = NotificationStore.enableDesktopNotification;
+ this.isDesktopNotificationSupported = NotificationStore.isDesktopNotificationSupported;
+ this.isDesktopNotificationDenied = NotificationStore.isDesktopNotificationDenied;
+
+ this.showImages = SettingsStore.showImages;
+ this.useCheckboxesInList = SettingsStore.useCheckboxesInList;
+ this.threadsAllowed = AppStore.threadsAllowed;
+ this.useThreads = SettingsStore.useThreads;
+ this.replySameFolder = SettingsStore.replySameFolder;
+ this.allowLanguagesOnSettings = AppStore.allowLanguagesOnSettings;
+
+ this.languageFullName = ko.computed(function () {
+ return Utils.convertLangName(this.language());
+ }, this);
+
+ this.languageTrigger = ko.observable(Enums.SaveSettingsStep.Idle).extend({'throttle': 100});
+
+ this.mppTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.editorDefaultTypeTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+ this.layoutTrigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.isAnimationSupported = Globals.bAnimationSupported;
+
+ this.identities = IdentityStore.identities;
+
+ this.identityMain = ko.computed(function () {
+ var aList = this.identities();
+ return Utils.isArray(aList) ? _.find(aList, function (oItem) {
+ return oItem && '' === oItem.id() ? true : false;
+ }) : null;
+ }, this);
+
+ this.identityMainDesc = ko.computed(function () {
+ var oIdentity = this.identityMain();
+ return oIdentity ? oIdentity.formattedName() : '---';
+ }, this);
+
+ this.editorDefaultTypes = ko.computed(function () {
+ Translator.trigger();
+ return [
+ {'id': Enums.EditorDefaultType.Html, 'name': Translator.i18n('SETTINGS_GENERAL/LABEL_EDITOR_HTML')},
+ {'id': Enums.EditorDefaultType.Plain, 'name': Translator.i18n('SETTINGS_GENERAL/LABEL_EDITOR_PLAIN')},
+ {'id': Enums.EditorDefaultType.HtmlForced, 'name': Translator.i18n('SETTINGS_GENERAL/LABEL_EDITOR_HTML_FORCED')},
+ {'id': Enums.EditorDefaultType.PlainForced, 'name': Translator.i18n('SETTINGS_GENERAL/LABEL_EDITOR_PLAIN_FORCED')}
+ ];
+ }, this);
+
+ this.layoutTypes = ko.computed(function () {
+ Translator.trigger();
+ return [
+ {'id': Enums.Layout.NoPreview, 'name': Translator.i18n('SETTINGS_GENERAL/LABEL_LAYOUT_NO_SPLIT')},
+ {'id': Enums.Layout.SidePreview, 'name': Translator.i18n('SETTINGS_GENERAL/LABEL_LAYOUT_VERTICAL_SPLIT')},
+ {'id': Enums.Layout.BottomPreview, 'name': Translator.i18n('SETTINGS_GENERAL/LABEL_LAYOUT_HORIZONTAL_SPLIT')}
+ ];
+ }, this);
+ }
+
+ GeneralUserSettings.prototype.editMainIdentity = function ()
+ {
+ var oIdentity = this.identityMain();
+ if (oIdentity)
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Identity */ 63), [oIdentity]);
+ }
+ };
+
+ GeneralUserSettings.prototype.testSoundNotification = function ()
+ {
+ NotificationStore.playSoundNotification(true);
+ };
+
+ GeneralUserSettings.prototype.onBuild = function ()
+ {
+ var self = this;
+
+ _.delay(function () {
+
+ var
+ f0 = Utils.settingsSaveHelperSimpleFunction(self.editorDefaultTypeTrigger, self),
+ f1 = Utils.settingsSaveHelperSimpleFunction(self.mppTrigger, self),
+ f2 = Utils.settingsSaveHelperSimpleFunction(self.layoutTrigger, self),
+ fReloadLanguageHelper = function (iSaveSettingsStep) {
+ return function() {
+ self.languageTrigger(iSaveSettingsStep);
+ _.delay(function () {
+ self.languageTrigger(Enums.SaveSettingsStep.Idle);
+ }, 1000);
+ };
+ }
+ ;
+
+ self.language.subscribe(function (sValue) {
+
+ self.languageTrigger(Enums.SaveSettingsStep.Animate);
+
+ Translator.reload(false, sValue,
+ fReloadLanguageHelper(Enums.SaveSettingsStep.TrueResult),
+ fReloadLanguageHelper(Enums.SaveSettingsStep.FalseResult));
+
+ Remote.saveSettings(null, {
+ 'Language': sValue
+ });
+ });
+
+ self.editorDefaultType.subscribe(function (sValue) {
+ Remote.saveSettings(f0, {
+ 'EditorDefaultType': sValue
+ });
+ });
+
+ self.messagesPerPage.subscribe(function (iValue) {
+ Remote.saveSettings(f1, {
+ 'MPP': iValue
+ });
+ });
+
+ self.showImages.subscribe(function (bValue) {
+ Remote.saveSettings(null, {
+ 'ShowImages': bValue ? '1' : '0'
+ });
+ });
+
+ self.enableDesktopNotification.subscribe(function (bValue) {
+ Utils.timeOutAction('SaveDesktopNotifications', function () {
+ Remote.saveSettings(null, {
+ 'DesktopNotifications': bValue ? '1' : '0'
+ });
+ }, 3000);
+ });
+
+ self.enableSoundNotification.subscribe(function (bValue) {
+ Utils.timeOutAction('SaveSoundNotification', function () {
+ Remote.saveSettings(null, {
+ 'SoundNotification': bValue ? '1' : '0'
+ });
+ }, 3000);
+ });
+
+ self.replySameFolder.subscribe(function (bValue) {
+ Utils.timeOutAction('SaveReplySameFolder', function () {
+ Remote.saveSettings(null, {
+ 'ReplySameFolder': bValue ? '1' : '0'
+ });
+ }, 3000);
+ });
+
+ self.useThreads.subscribe(function (bValue) {
+
+ MessageStore.messageList([]);
+
+ Remote.saveSettings(null, {
+ 'UseThreads': bValue ? '1' : '0'
+ });
+ });
+
+ self.layout.subscribe(function (nValue) {
+
+ MessageStore.messageList([]);
+
+ Remote.saveSettings(f2, {
+ 'Layout': nValue
+ });
+ });
+
+ self.useCheckboxesInList.subscribe(function (bValue) {
+ Remote.saveSettings(null, {
+ 'UseCheckboxesInList': bValue ? '1' : '0'
+ });
+ });
+
+ }, 50);
+ };
+
+ GeneralUserSettings.prototype.onShow = function ()
+ {
+ this.enableDesktopNotification.valueHasMutated();
+ };
+
+ GeneralUserSettings.prototype.selectLanguage = function ()
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Languages */ 44), [
+ this.language, this.languages(), LanguageStore.userLanguage()
+ ]);
+ };
+
+ module.exports = GeneralUserSettings;
+
+ }());
+
+/***/ },
+/* 134 */
+/*!**************************************!*\
+ !*** ./dev/Settings/User/OpenPgp.js ***!
+ \**************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+ window = __webpack_require__(/*! window */ 11),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+
+ PgpStore = __webpack_require__(/*! Stores/User/Pgp */ 33)
+ ;
+
+ /**
+ * @constructor
+ */
+ function OpenPgpUserSettings()
+ {
+ this.openpgpkeys = PgpStore.openpgpkeys;
+ this.openpgpkeysPublic = PgpStore.openpgpkeysPublic;
+ this.openpgpkeysPrivate = PgpStore.openpgpkeysPrivate;
+
+ this.openPgpKeyForDeletion = ko.observable(null).deleteAccessHelper();
+
+ this.isHttps = window.document && window.document.location ? 'https:' === window.document.location.protocol : false;
+ }
+
+ OpenPgpUserSettings.prototype.addOpenPgpKey = function ()
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/AddOpenPgpKey */ 143));
+ };
+
+ OpenPgpUserSettings.prototype.generateOpenPgpKey = function ()
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/NewOpenPgpKey */ 148));
+ };
+
+ OpenPgpUserSettings.prototype.viewOpenPgpKey = function (oOpenPgpKey)
+ {
+ if (oOpenPgpKey)
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/ViewOpenPgpKey */ 151), [oOpenPgpKey]);
+ }
+ };
+
+ /**
+ * @param {OpenPgpKeyModel} oOpenPgpKeyToRemove
+ */
+ OpenPgpUserSettings.prototype.deleteOpenPgpKey = function (oOpenPgpKeyToRemove)
+ {
+ if (oOpenPgpKeyToRemove && oOpenPgpKeyToRemove.deleteAccess())
+ {
+ this.openPgpKeyForDeletion(null);
+
+ if (oOpenPgpKeyToRemove && PgpStore.openpgpKeyring)
+ {
+ var oFindedItem = _.find(PgpStore.openpgpkeys(), function (oOpenPgpKey) {
+ return oOpenPgpKeyToRemove === oOpenPgpKey;
+ });
+
+ if (oFindedItem)
+ {
+ PgpStore.openpgpkeys.remove(oFindedItem);
+ Utils.delegateRunOnDestroy(oFindedItem);
+
+ PgpStore.openpgpKeyring[oFindedItem.isPrivate ? 'privateKeys' : 'publicKeys']
+ .removeForId(oFindedItem.guid);
+
+ PgpStore.openpgpKeyring.store();
+ }
+
+ __webpack_require__(/*! App/User */ 7).default.reloadOpenPgpKeys();
+ }
+ }
+ };
+
+ module.exports = OpenPgpUserSettings;
+
+ }());
+
+/***/ },
+/* 135 */
+/*!***************************************!*\
+ !*** ./dev/Settings/User/Security.js ***!
+ \***************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ SettinsStore = __webpack_require__(/*! Stores/User/Settings */ 28),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15)
+ ;
+
+ /**
+ * @constructor
+ */
+ function SecurityUserSettings()
+ {
+ this.capaAutoLogout = Settings.capa(Enums.Capa.AutoLogout);
+ this.capaTwoFactor = Settings.capa(Enums.Capa.TwoFactor);
+
+ this.autoLogout = SettinsStore.autoLogout;
+ this.autoLogout.trigger = ko.observable(Enums.SaveSettingsStep.Idle);
+
+ this.autoLogoutOptions = ko.computed(function () {
+ Translator.trigger();
+ return [
+ {'id': 0, 'name': Translator.i18n('SETTINGS_SECURITY/AUTOLOGIN_NEVER_OPTION_NAME')},
+ {'id': 5, 'name': Translator.i18n('SETTINGS_SECURITY/AUTOLOGIN_MINUTES_OPTION_NAME', {'MINUTES': 5})},
+ {'id': 10, 'name': Translator.i18n('SETTINGS_SECURITY/AUTOLOGIN_MINUTES_OPTION_NAME', {'MINUTES': 10})},
+ {'id': 30, 'name': Translator.i18n('SETTINGS_SECURITY/AUTOLOGIN_MINUTES_OPTION_NAME', {'MINUTES': 30})},
+ {'id': 60, 'name': Translator.i18n('SETTINGS_SECURITY/AUTOLOGIN_MINUTES_OPTION_NAME', {'MINUTES': 60})}
+ ];
+ });
+ }
+
+ SecurityUserSettings.prototype.configureTwoFactor = function ()
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/TwoFactorConfiguration */ 98));
+ };
+
+ SecurityUserSettings.prototype.onBuild = function ()
+ {
+ if (this.capaAutoLogout)
+ {
+ var self = this;
+
+ _.delay(function () {
+
+ var
+ f0 = Utils.settingsSaveHelperSimpleFunction(self.autoLogout.trigger, self)
+ ;
+
+ self.autoLogout.subscribe(function (sValue) {
+ Remote.saveSettings(f0, {
+ 'AutoLogout': Utils.pInt(sValue)
+ });
+ });
+
+ });
+ }
+ };
+
+ module.exports = SecurityUserSettings;
+
+ }());
+
+/***/ },
+/* 136 */
+/*!*************************************!*\
+ !*** ./dev/Settings/User/Social.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ /**
+ * @constructor
+ */
+ function SocialUserSettings()
+ {
+ var
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ SocialStore = __webpack_require__(/*! Stores/Social */ 34)
+ ;
+
+ this.googleEnable = SocialStore.google.enabled;
+ this.googleEnableAuth = SocialStore.google.capa.auth;
+ this.googleEnableAuthFast = SocialStore.google.capa.authFast;
+ this.googleEnableDrive = SocialStore.google.capa.drive;
+ this.googleEnablePreview = SocialStore.google.capa.preview;
+
+ this.googleActions = SocialStore.google.loading;
+ this.googleLoggined = SocialStore.google.loggined;
+ this.googleUserName = SocialStore.google.userName;
+
+ this.facebookEnable = SocialStore.facebook.enabled;
+
+ this.facebookActions = SocialStore.facebook.loading;
+ this.facebookLoggined = SocialStore.facebook.loggined;
+ this.facebookUserName = SocialStore.facebook.userName;
+
+ this.twitterEnable = SocialStore.twitter.enabled;
+
+ this.twitterActions = SocialStore.twitter.loading;
+ this.twitterLoggined = SocialStore.twitter.loggined;
+ this.twitterUserName = SocialStore.twitter.userName;
+
+ this.connectGoogle = Utils.createCommand(this, function () {
+ if (!this.googleLoggined())
+ {
+ __webpack_require__(/*! App/User */ 7).default.googleConnect();
+ }
+ }, function () {
+ return !this.googleLoggined() && !this.googleActions();
+ });
+
+ this.disconnectGoogle = Utils.createCommand(this, function () {
+ __webpack_require__(/*! App/User */ 7).default.googleDisconnect();
+ });
+
+ this.connectFacebook = Utils.createCommand(this, function () {
+ if (!this.facebookLoggined())
+ {
+ __webpack_require__(/*! App/User */ 7).default.facebookConnect();
+ }
+ }, function () {
+ return !this.facebookLoggined() && !this.facebookActions();
+ });
+
+ this.disconnectFacebook = Utils.createCommand(this, function () {
+ __webpack_require__(/*! App/User */ 7).default.facebookDisconnect();
+ });
+
+ this.connectTwitter = Utils.createCommand(this, function () {
+ if (!this.twitterLoggined())
+ {
+ __webpack_require__(/*! App/User */ 7).default.twitterConnect();
+ }
+ }, function () {
+ return !this.twitterLoggined() && !this.twitterActions();
+ });
+
+ this.disconnectTwitter = Utils.createCommand(this, function () {
+ __webpack_require__(/*! App/User */ 7).default.twitterDisconnect();
+ });
+ }
+
+ module.exports = SocialUserSettings;
+
+ }());
+
+/***/ },
+/* 137 */
+/*!****************************************!*\
+ !*** ./dev/Settings/User/Templates.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ TemplateStore = __webpack_require__(/*! Stores/User/Template */ 92),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15)
+ ;
+
+ /**
+ * @constructor
+ */
+ function TemplatesUserSettings()
+ {
+ this.templates = TemplateStore.templates;
+
+ this.processText = ko.computed(function () {
+ return TemplateStore.templates.loading() ? Translator.i18n('SETTINGS_TEMPLETS/LOADING_PROCESS') : '';
+ }, this);
+
+ this.visibility = ko.computed(function () {
+ return '' === this.processText() ? 'hidden' : 'visible';
+ }, this);
+
+ this.templateForDeletion = ko.observable(null).deleteAccessHelper();
+ }
+
+ TemplatesUserSettings.prototype.scrollableOptions = function (sWrapper)
+ {
+ return {
+ handle: '.drag-handle',
+ containment: sWrapper || 'parent',
+ axis: 'y'
+ };
+ };
+
+ TemplatesUserSettings.prototype.addNewTemplate = function ()
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Template */ 97));
+ };
+
+ TemplatesUserSettings.prototype.editTemplate = function (oTemplateItem)
+ {
+ if (oTemplateItem)
+ {
+ __webpack_require__(/*! Knoin/Knoin */ 5).showScreenPopup(__webpack_require__(/*! View/Popup/Template */ 97), [oTemplateItem]);
+ }
+ };
+
+ /**
+ * @param {AccountModel} oTemplateToRemove
+ */
+ TemplatesUserSettings.prototype.deleteTemplate = function (oTemplateToRemove)
+ {
+ if (oTemplateToRemove && oTemplateToRemove.deleteAccess())
+ {
+ this.templateForDeletion(null);
+
+ var
+ self = this,
+ fRemoveAccount = function (oAccount) {
+ return oTemplateToRemove === oAccount;
+ }
+ ;
+
+ if (oTemplateToRemove)
+ {
+ this.templates.remove(fRemoveAccount);
+
+ Remote.templateDelete(function () {
+ self.reloadTemplates();
+ }, oTemplateToRemove.id);
+ }
+ }
+ };
+
+ TemplatesUserSettings.prototype.reloadTemplates = function ()
+ {
+ __webpack_require__(/*! App/User */ 7).default.templates();
+ };
+
+ TemplatesUserSettings.prototype.onBuild = function (oDom)
+ {
+ var self = this;
+
+ oDom
+ .on('click', '.templates-list .template-item .e-action', function () {
+ var oTemplateItem = ko.dataFor(this);
+ if (oTemplateItem)
+ {
+ self.editTemplate(oTemplateItem);
+ }
+ })
+ ;
+
+ this.reloadTemplates();
+ };
+
+ module.exports = TemplatesUserSettings;
+
+ }());
+
+/***/ },
+/* 138 */
+/*!*************************************!*\
+ !*** ./dev/Settings/User/Themes.js ***!
+ \*************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Jua = __webpack_require__(/*! Jua */ 80),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ ThemeStore = __webpack_require__(/*! Stores/Theme */ 42),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15)
+ ;
+
+ /**
+ * @constructor
+ */
+ function ThemesUserSettings()
+ {
+ this.theme = ThemeStore.theme;
+ this.themes = ThemeStore.themes;
+ this.themesObjects = ko.observableArray([]);
+
+ this.background = {};
+ this.background.name = ThemeStore.themeBackgroundName;
+ this.background.hash = ThemeStore.themeBackgroundHash;
+ this.background.uploaderButton = ko.observable(null);
+ this.background.loading = ko.observable(false);
+ this.background.error = ko.observable('');
+
+ this.capaUserBackground = ko.observable(Settings.capa(Enums.Capa.UserBackground));
+
+ this.themeTrigger = ko.observable(Enums.SaveSettingsStep.Idle).extend({'throttle': 100});
+
+ this.iTimer = 0;
+ this.oThemeAjaxRequest = null;
+
+ this.theme.subscribe(function (sValue) {
+
+ _.each(this.themesObjects(), function (oTheme) {
+ oTheme.selected(sValue === oTheme.name);
+ });
+
+ Utils.changeTheme(sValue, this.themeTrigger);
+
+ Remote.saveSettings(null, {
+ 'Theme': sValue
+ });
+
+ }, this);
+
+ this.background.hash.subscribe(function (sValue) {
+
+ var $oBg = $('#rl-bg');
+ if (!sValue)
+ {
+ if ($oBg.data('backstretch'))
+ {
+ $oBg.backstretch('destroy').attr('style', '');
+ }
+ }
+ else
+ {
+ $('#rl-bg').attr('style', 'background-image: none !important;').backstretch(
+ Links.userBackground(sValue), {
+ 'fade': 1000, 'centeredX': true, 'centeredY': true
+ }).removeAttr('style');
+ }
+
+ }, this);
+ }
+
+ ThemesUserSettings.prototype.onBuild = function ()
+ {
+ var sCurrentTheme = this.theme();
+ this.themesObjects(_.map(this.themes(), function (sTheme) {
+ return {
+ 'name': sTheme,
+ 'nameDisplay': Utils.convertThemeName(sTheme),
+ 'selected': ko.observable(sTheme === sCurrentTheme),
+ 'themePreviewSrc': Links.themePreviewLink(sTheme)
+ };
+ }));
+
+ this.initUploader();
+ };
+
+ ThemesUserSettings.prototype.onShow = function ()
+ {
+ this.background.error('');
+ };
+
+ ThemesUserSettings.prototype.clearBackground = function ()
+ {
+ if (this.capaUserBackground())
+ {
+ var self = this;
+ Remote.clearUserBackground(function () {
+ self.background.name('');
+ self.background.hash('');
+ });
+ }
+ };
+
+ ThemesUserSettings.prototype.initUploader = function ()
+ {
+ if (this.background.uploaderButton() && this.capaUserBackground())
+ {
+ var
+ oJua = new Jua({
+ 'action': Links.uploadBackground(),
+ 'name': 'uploader',
+ 'queueSize': 1,
+ 'multipleSizeLimit': 1,
+ 'disableDragAndDrop': true,
+ 'disableMultiple': true,
+ 'clickElement': this.background.uploaderButton()
+ })
+ ;
+
+ oJua
+ .on('onStart', _.bind(function () {
+
+ this.background.loading(true);
+ this.background.error('');
+
+ return true;
+
+ }, this))
+ .on('onComplete', _.bind(function (sId, bResult, oData) {
+
+ this.background.loading(false);
+
+ if (bResult && sId && oData && oData.Result && oData.Result.Name && oData.Result.Hash)
+ {
+ this.background.name(oData.Result.Name);
+ this.background.hash(oData.Result.Hash);
+ }
+ else
+ {
+ this.background.name('');
+ this.background.hash('');
+
+ var sError = '';
+ if (oData.ErrorCode)
+ {
+ switch (oData.ErrorCode)
+ {
+ case Enums.UploadErrorCode.FileIsTooBig:
+ sError = Translator.i18n('SETTINGS_THEMES/ERROR_FILE_IS_TOO_BIG');
+ break;
+ case Enums.UploadErrorCode.FileType:
+ sError = Translator.i18n('SETTINGS_THEMES/ERROR_FILE_TYPE_ERROR');
+ break;
+ }
+ }
+
+ if (!sError && oData.ErrorMessage)
+ {
+ sError = oData.ErrorMessage;
+ }
+
+ this.background.error(sError || Translator.i18n('SETTINGS_THEMES/ERROR_UNKNOWN'));
+ }
+
+ return true;
+
+ }, this))
+ ;
+ }
+ };
+
+ module.exports = ThemesUserSettings;
+
+ }());
+
+/***/ },
+/* 139 */,
+/* 140 */,
+/* 141 */,
+/* 142 */,
+/* 143 */
+/*!*****************************************!*\
+ !*** ./dev/View/Popup/AddOpenPgpKey.js ***!
+ \*****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ PgpStore = __webpack_require__(/*! Stores/User/Pgp */ 33),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function AddOpenPgpKeyPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsAddOpenPgpKey');
+
+ this.key = ko.observable('');
+ this.key.error = ko.observable(false);
+ this.key.focus = ko.observable(false);
+
+ this.key.subscribe(function () {
+ this.key.error(false);
+ }, this);
+
+ this.addOpenPgpKeyCommand = Utils.createCommand(this, function () {
+
+ var
+ iCount = 30,
+ aMatch = null,
+ sKey = Utils.trim(this.key()),
+ oReg = /[\-]{3,6}BEGIN[\s]PGP[\s](PRIVATE|PUBLIC)[\s]KEY[\s]BLOCK[\-]{3,6}[\s\S]+?[\-]{3,6}END[\s]PGP[\s](PRIVATE|PUBLIC)[\s]KEY[\s]BLOCK[\-]{3,6}/gi,
+ oOpenpgpKeyring = PgpStore.openpgpKeyring
+ ;
+
+ if (/[\n]/.test(sKey))
+ {
+ sKey = sKey.replace(/[\r]+/g, '')
+ .replace(/[\n]{2,}/g, '\n\n');
+ }
+
+ this.key.error('' === sKey);
+
+ if (!oOpenpgpKeyring || this.key.error())
+ {
+ return false;
+ }
+
+ do
+ {
+ aMatch = oReg.exec(sKey);
+ if (!aMatch || 0 > iCount)
+ {
+ break;
+ }
+
+ if (aMatch[0] && aMatch[1] && aMatch[2] && aMatch[1] === aMatch[2])
+ {
+ if ('PRIVATE' === aMatch[1])
+ {
+ oOpenpgpKeyring.privateKeys.importKey(aMatch[0]);
+ }
+ else if ('PUBLIC' === aMatch[1])
+ {
+ oOpenpgpKeyring.publicKeys.importKey(aMatch[0]);
+ }
+ }
+
+ iCount--;
+ }
+ while (true);
+
+ oOpenpgpKeyring.store();
+
+ __webpack_require__(/*! App/User */ 7).default.reloadOpenPgpKeys();
+ Utils.delegateRun(this, 'cancelCommand');
+
+ return true;
+ });
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/AddOpenPgpKey', 'PopupsAddOpenPgpKeyViewModel'], AddOpenPgpKeyPopupView);
+ _.extend(AddOpenPgpKeyPopupView.prototype, AbstractView.prototype);
+
+ AddOpenPgpKeyPopupView.prototype.clearPopup = function ()
+ {
+ this.key('');
+ this.key.error(false);
+ };
+
+ AddOpenPgpKeyPopupView.prototype.onShow = function ()
+ {
+ this.clearPopup();
+ };
+
+ AddOpenPgpKeyPopupView.prototype.onShowWithDelay = function ()
+ {
+ this.key.focus(true);
+ };
+
+ module.exports = AddOpenPgpKeyPopupView;
+
+ }());
+
+/***/ },
+/* 144 */
+/*!******************************************!*\
+ !*** ./dev/View/Popup/AdvancedSearch.js ***!
+ \******************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ MessageStore = __webpack_require__(/*! Stores/User/Message */ 32),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function AdvancedSearchPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsAdvancedSearch');
+
+ this.fromFocus = ko.observable(false);
+
+ this.from = ko.observable('');
+ this.to = ko.observable('');
+ this.subject = ko.observable('');
+ this.text = ko.observable('');
+ this.selectedDateValue = ko.observable(-1);
+
+ this.hasAttachment = ko.observable(false);
+ this.starred = ko.observable(false);
+ this.unseen = ko.observable(false);
+
+ this.searchCommand = Utils.createCommand(this, function () {
+
+ var sSearch = this.buildSearchString();
+ if ('' !== sSearch)
+ {
+ MessageStore.mainMessageListSearch(sSearch);
+ }
+
+ this.cancelCommand();
+ });
+
+ this.selectedDates = ko.computed(function () {
+ Translator.trigger();
+ return [
+ {'id': -1, 'name': Translator.i18n('SEARCH/LABEL_ADV_DATE_ALL')},
+ {'id': 3, 'name': Translator.i18n('SEARCH/LABEL_ADV_DATE_3_DAYS')},
+ {'id': 7, 'name': Translator.i18n('SEARCH/LABEL_ADV_DATE_7_DAYS')},
+ {'id': 30, 'name': Translator.i18n('SEARCH/LABEL_ADV_DATE_MONTH')},
+ {'id': 90, 'name': Translator.i18n('SEARCH/LABEL_ADV_DATE_3_MONTHS')},
+ {'id': 180, 'name': Translator.i18n('SEARCH/LABEL_ADV_DATE_6_MONTHS')},
+ {'id': 365, 'name': Translator.i18n('SEARCH/LABEL_ADV_DATE_YEAR')}
+ ];
+ }, this);
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/AdvancedSearch', 'PopupsAdvancedSearchViewModel'], AdvancedSearchPopupView);
+ _.extend(AdvancedSearchPopupView.prototype, AbstractView.prototype);
+
+ AdvancedSearchPopupView.prototype.buildSearchStringValue = function (sValue)
+ {
+ if (-1 < sValue.indexOf(' '))
+ {
+ sValue = '"' + sValue + '"';
+ }
+
+ return sValue;
+ };
+
+ AdvancedSearchPopupView.prototype.buildSearchString = function ()
+ {
+ var
+ aResult = [],
+ sFrom = Utils.trim(this.from()),
+ sTo = Utils.trim(this.to()),
+ sSubject = Utils.trim(this.subject()),
+ sText = Utils.trim(this.text()),
+ aIs = [],
+ aHas = []
+ ;
+
+ if (sFrom && '' !== sFrom)
+ {
+ aResult.push('from:' + this.buildSearchStringValue(sFrom));
+ }
+
+ if (sTo && '' !== sTo)
+ {
+ aResult.push('to:' + this.buildSearchStringValue(sTo));
+ }
+
+ if (sSubject && '' !== sSubject)
+ {
+ aResult.push('subject:' + this.buildSearchStringValue(sSubject));
+ }
+
+ if (this.hasAttachment())
+ {
+ aHas.push('attachment');
+ }
+
+ if (this.unseen())
+ {
+ aIs.push('unseen');
+ }
+
+ if (this.starred())
+ {
+ aIs.push('flagged');
+ }
+
+ if (0 < aHas.length)
+ {
+ aResult.push('has:' + aHas.join(','));
+ }
+
+ if (0 < aIs.length)
+ {
+ aResult.push('is:' + aIs.join(','));
+ }
+
+ if (-1 < this.selectedDateValue())
+ {
+ aResult.push('date:' + __webpack_require__(/*! Common/Momentor */ 26).searchSubtractFormatDateHelper(this.selectedDateValue()) + '/');
+ }
+
+ if (sText && '' !== sText)
+ {
+ aResult.push('text:' + this.buildSearchStringValue(sText));
+ }
+
+ return Utils.trim(aResult.join(' '));
+ };
+
+ AdvancedSearchPopupView.prototype.clearPopup = function ()
+ {
+ this.from('');
+ this.to('');
+ this.subject('');
+ this.text('');
+
+ this.selectedDateValue(-1);
+ this.hasAttachment(false);
+ this.starred(false);
+ this.unseen(false);
+
+ this.fromFocus(true);
+ };
+
+ AdvancedSearchPopupView.prototype.onShow = function ()
+ {
+ this.clearPopup();
+ };
+
+ AdvancedSearchPopupView.prototype.onShowWithDelay = function ()
+ {
+ this.fromFocus(true);
+ };
+
+ module.exports = AdvancedSearchPopupView;
+
+ }());
+
+/***/ },
+/* 145 */
+/*!******************************************!*\
+ !*** ./dev/View/Popup/ComposeOpenPgp.js ***!
+ \******************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+ key = __webpack_require__(/*! key */ 18),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ PgpStore = __webpack_require__(/*! Stores/User/Pgp */ 33),
+
+ EmailModel = __webpack_require__(/*! Model/Email */ 30),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function ComposeOpenPgpPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsComposeOpenPgp');
+
+ var self = this;
+
+ this.publicKeysOptionsCaption = Translator.i18n('PGP_NOTIFICATIONS/ADD_A_PUBLICK_KEY');
+ this.privateKeysOptionsCaption = Translator.i18n('PGP_NOTIFICATIONS/SELECT_A_PRIVATE_KEY');
+
+ this.notification = ko.observable('');
+
+ this.sign = ko.observable(false);
+ this.encrypt = ko.observable(false);
+
+ this.password = ko.observable('');
+ this.password.focus = ko.observable(false);
+ this.buttonFocus = ko.observable(false);
+
+ this.text = ko.observable('');
+ this.selectedPrivateKey = ko.observable(null);
+ this.selectedPublicKey = ko.observable(null);
+
+ this.signKey = ko.observable(null);
+ this.encryptKeys = ko.observableArray([]);
+
+ this.encryptKeysView = ko.computed(function () {
+ return _.compact(_.map(this.encryptKeys(), function (oKey) {
+ return oKey ? oKey.key : null;
+ }));
+ }, this);
+
+ this.privateKeysOptions = ko.computed(function () {
+ return _.compact(_.flatten(_.map(PgpStore.openpgpkeysPrivate(), function (oKey, iIndex) {
+ return self.signKey() && self.signKey().key.id === oKey.id ? null :
+ _.map(oKey.users, function (sUser) {
+ return {
+ 'id': oKey.guid,
+ 'name': '(' + oKey.id.substr(-8).toUpperCase() + ') ' + sUser,
+ 'key': oKey,
+ 'class': iIndex % 2 ? 'odd' : 'even'
+ };
+ });
+ }), true));
+ });
+
+ this.publicKeysOptions = ko.computed(function () {
+ return _.compact(_.flatten(_.map(PgpStore.openpgpkeysPublic(), function (oKey, iIndex) {
+ return -1 < Utils.inArray(oKey, self.encryptKeysView()) ? null :
+ _.map(oKey.users, function (sUser) {
+ return {
+ 'id': oKey.guid,
+ 'name': '(' + oKey.id.substr(-8).toUpperCase() + ') ' + sUser,
+ 'key': oKey,
+ 'class': iIndex % 2 ? 'odd' : 'even'
+ };
+ });
+ }), true));
+ });
+
+ this.submitRequest = ko.observable(false);
+
+ this.resultCallback = null;
+
+ // commands
+ this.doCommand = Utils.createCommand(this, function () {
+
+ var
+ bResult = true,
+ oPrivateKey = null,
+ aPrivateKeys = [],
+ aPublicKeys = []
+ ;
+
+ this.submitRequest(true);
+
+ if (bResult && this.sign())
+ {
+ if (!this.signKey())
+ {
+ this.notification(Translator.i18n('PGP_NOTIFICATIONS/NO_PRIVATE_KEY_FOUND'));
+ bResult = false;
+ }
+ else if (!this.signKey().key)
+ {
+ this.notification(Translator.i18n('PGP_NOTIFICATIONS/NO_PRIVATE_KEY_FOUND_FOR', {
+ 'EMAIL': this.signKey().email
+ }));
+
+ bResult = false;
+ }
+
+ if (bResult)
+ {
+ aPrivateKeys = this.signKey().key.getNativeKeys();
+ oPrivateKey = aPrivateKeys[0] || null;
+
+ try
+ {
+ if (oPrivateKey)
+ {
+ oPrivateKey.decrypt(Utils.pString(this.password()));
+ }
+ }
+ catch (e)
+ {
+ oPrivateKey = null;
+ }
+
+ if (!oPrivateKey)
+ {
+ this.notification(Translator.i18n('PGP_NOTIFICATIONS/NO_PRIVATE_KEY_FOUND'));
+ bResult = false;
+ }
+ }
+ }
+
+ if (bResult && this.encrypt())
+ {
+ if (0 === this.encryptKeys().length)
+ {
+ this.notification(Translator.i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND'));
+ bResult = false;
+ }
+ else if (this.encryptKeys())
+ {
+ aPublicKeys = [];
+
+ _.each(this.encryptKeys(), function (oKey) {
+ if (oKey && oKey.key)
+ {
+ aPublicKeys = aPublicKeys.concat(_.compact(_.flatten(oKey.key.getNativeKeys())));
+ }
+ else if (oKey && oKey.email)
+ {
+ self.notification(Translator.i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND_FOR', {
+ 'EMAIL': oKey.email
+ }));
+
+ bResult = false;
+ }
+ });
+
+ if (bResult && (0 === aPublicKeys.length || this.encryptKeys().length !== aPublicKeys.length))
+ {
+ bResult = false;
+ }
+ }
+ }
+
+ if (bResult && self.resultCallback)
+ {
+ _.delay(function () {
+
+ var oPromise = null;
+
+ try
+ {
+ if (oPrivateKey && 0 === aPublicKeys.length)
+ {
+ // oPromise = PgpStore.openpgp.signClearMessage([oPrivateKey], self.text()); // 1.2.0
+ oPromise = PgpStore.openpgp.sign({
+ data: self.text(),
+ privateKeys: [oPrivateKey]
+ });
+ }
+ else if (oPrivateKey && 0 < aPublicKeys.length)
+ {
+ // oPromise = PgpStore.openpgp.signAndEncryptMessage(aPublicKeys, oPrivateKey, self.text()); // 1.2.0
+ oPromise = PgpStore.openpgp.encrypt({
+ data: self.text(),
+ publicKeys: aPublicKeys,
+ privateKeys: [oPrivateKey]
+ });
+ }
+ else if (!oPrivateKey && 0 < aPublicKeys.length)
+ {
+ // oPromise = PgpStore.openpgp.encryptMessage(aPublicKeys, self.text()); // 1.2.0
+ oPromise = PgpStore.openpgp.encrypt({
+ data: self.text(),
+ publicKeys: aPublicKeys
+ });
+ }
+ }
+ catch (e)
+ {
+ Utils.log(e);
+
+ self.notification(Translator.i18n('PGP_NOTIFICATIONS/PGP_ERROR', {
+ 'ERROR': '' + e
+ }));
+ }
+
+ if (oPromise)
+ {
+ try
+ {
+ oPromise.then(function (mData) {
+
+ self.resultCallback(mData.data);
+ self.cancelCommand();
+
+ })['catch'](function (e) {
+ self.notification(Translator.i18n('PGP_NOTIFICATIONS/PGP_ERROR', {
+ 'ERROR': '' + e
+ }));
+ });
+ }
+ catch (e)
+ {
+ self.notification(Translator.i18n('PGP_NOTIFICATIONS/PGP_ERROR', {
+ 'ERROR': '' + e
+ }));
+ }
+ }
+
+ self.submitRequest(false);
+
+ }, 10);
+ }
+ else
+ {
+ self.submitRequest(false);
+ }
+
+ return bResult;
+
+ }, function () {
+ return !this.submitRequest() && (this.sign() || this.encrypt());
+ });
+
+ this.selectCommand = Utils.createCommand(this, function () {
+
+ var
+ sKeyId = this.selectedPrivateKey(),
+ oKey = null,
+ oOption = sKeyId ? _.find(this.privateKeysOptions(), function (oItem) {
+ return oItem && sKeyId === oItem.id;
+ }) : null
+ ;
+
+ if (oOption)
+ {
+ oKey = {
+ 'empty': !oOption.key,
+ 'selected': ko.observable(!!oOption.key),
+ 'users': oOption.key.users,
+ 'hash': oOption.key.id.substr(-8).toUpperCase(),
+ 'key': oOption.key
+ };
+
+ this.signKey(oKey);
+ }
+ });
+
+ this.addCommand = Utils.createCommand(this, function () {
+
+ var
+ sKeyId = this.selectedPublicKey(),
+ aKeys = this.encryptKeys(),
+ oOption = sKeyId ? _.find(this.publicKeysOptions(), function (oItem) {
+ return oItem && sKeyId === oItem.id;
+ }) : null
+ ;
+
+ if (oOption)
+ {
+ aKeys.push({
+ 'empty': !oOption.key,
+ 'selected': ko.observable(!!oOption.key),
+ 'removable': ko.observable(!this.sign() || !this.signKey() || this.signKey().key.id !== oOption.key.id),
+ 'users': oOption.key.users,
+ 'hash': oOption.key.id.substr(-8).toUpperCase(),
+ 'key': oOption.key
+ });
+
+ this.encryptKeys(aKeys);
+ }
+ });
+
+ this.updateCommand = Utils.createCommand(this, function () {
+
+ var self = this;
+
+ _.each(this.encryptKeys(), function (oKey) {
+ oKey.removable(!self.sign() || !self.signKey() || self.signKey().key.id !== oKey.key.id);
+ });
+
+ });
+
+ this.selectedPrivateKey.subscribe(function (sValue) {
+ if (sValue)
+ {
+ this.selectCommand();
+ this.updateCommand();
+ }
+ }, this);
+
+ this.selectedPublicKey.subscribe(function (sValue) {
+ if (sValue)
+ {
+ this.addCommand();
+ }
+ }, this);
+
+ this.sDefaultKeyScope = Enums.KeyState.PopupComposeOpenPGP;
+
+ this.defautOptionsAfterRender = Utils.defautOptionsAfterRender;
+
+ this.addOptionClass = function (oDomOption, oItem) {
+
+ self.defautOptionsAfterRender(oDomOption, oItem);
+
+ if (oItem && !Utils.isUnd(oItem['class']) && oDomOption)
+ {
+ $(oDomOption).addClass(oItem['class']);
+ }
+ };
+
+ this.deletePublickKey = _.bind(this.deletePublickKey, this);
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/ComposeOpenPgp', 'PopupsComposeOpenPgpViewModel'], ComposeOpenPgpPopupView);
+ _.extend(ComposeOpenPgpPopupView.prototype, AbstractView.prototype);
+
+ ComposeOpenPgpPopupView.prototype.deletePublickKey = function (oKey)
+ {
+ this.encryptKeys.remove(oKey);
+ };
+
+ ComposeOpenPgpPopupView.prototype.clearPopup = function ()
+ {
+ this.notification('');
+
+ this.sign(false);
+ this.encrypt(false);
+
+ this.password('');
+ this.password.focus(false);
+ this.buttonFocus(false);
+
+ this.signKey(null);
+ this.encryptKeys([]);
+ this.text('');
+
+ this.resultCallback = null;
+ };
+
+ ComposeOpenPgpPopupView.prototype.onBuild = function ()
+ {
+ key('tab,shift+tab', Enums.KeyState.PopupComposeOpenPGP, _.bind(function () {
+
+ switch (true)
+ {
+ case this.password.focus():
+ this.buttonFocus(true);
+ break;
+ case this.buttonFocus():
+ this.password.focus(true);
+ break;
+ }
+
+ return false;
+
+ }, this));
+ };
+
+ ComposeOpenPgpPopupView.prototype.onHideWithDelay = function ()
+ {
+ this.clearPopup();
+ };
+
+ ComposeOpenPgpPopupView.prototype.onShowWithDelay = function ()
+ {
+ if (this.sign())
+ {
+ this.password.focus(true);
+ }
+ else
+ {
+ this.buttonFocus(true);
+ }
+ };
+
+ ComposeOpenPgpPopupView.prototype.onShow = function (fCallback, sText, oIdentity, sTo, sCc, sBcc)
+ {
+ this.clearPopup();
+
+ var
+ self = this,
+ aRec = [],
+ sEmail = '',
+ aKeys = [],
+ oEmail = new EmailModel()
+ ;
+
+ this.resultCallback = fCallback;
+
+ if ('' !== sTo)
+ {
+ aRec.push(sTo);
+ }
+
+ if ('' !== sCc)
+ {
+ aRec.push(sCc);
+ }
+
+ if ('' !== sBcc)
+ {
+ aRec.push(sBcc);
+ }
+
+ aRec = aRec.join(', ').split(',');
+ aRec = _.compact(_.map(aRec, function (sValue) {
+ oEmail.clear();
+ oEmail.mailsoParse(Utils.trim(sValue));
+ return '' === oEmail.email ? false : oEmail.email;
+ }));
+
+ if (oIdentity && oIdentity.email())
+ {
+ sEmail = oIdentity.email();
+ aRec.unshift(sEmail);
+ aKeys = PgpStore.findAllPrivateKeysByEmailNotNative(sEmail);
+ if (aKeys && aKeys[0])
+ {
+ this.signKey({
+ 'users': aKeys[0].users || [sEmail],
+ 'hash': aKeys[0].id.substr(-8).toUpperCase(),
+ 'key': aKeys[0]
+ });
+ }
+ }
+
+ if (this.signKey())
+ {
+ this.sign(true);
+ }
+
+ if (aRec && 0 < aRec.length)
+ {
+ this.encryptKeys(_.uniq(_.compact(_.flatten(_.map(aRec, function (sEmail) {
+ var aKeys = PgpStore.findAllPublicKeysByEmailNotNative(sEmail);
+ return aKeys ? _.map(aKeys, function (oKey) {
+ return {
+ 'empty': !oKey,
+ 'selected': ko.observable(!!oKey),
+ 'removable': ko.observable(!self.sign() || !self.signKey() || self.signKey().key.id !== oKey.id),
+ 'users': oKey ? (oKey.users || [sEmail]) : [sEmail],
+ 'hash': oKey ? oKey.id.substr(-8).toUpperCase() : '',
+ 'key': oKey
+ };
+ }) : [];
+ }), true)), function (oEncryptKey) {
+ return oEncryptKey.hash;
+ }));
+
+ if (0 < this.encryptKeys().length)
+ {
+ this.encrypt(true);
+ }
+ }
+
+ this.text(sText);
+ };
+
+ module.exports = ComposeOpenPgpPopupView;
+
+ }());
+
+
+/***/ },
+/* 146 */
+/*!***************************************!*\
+ !*** ./dev/View/Popup/FolderClear.js ***!
+ \***************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Cache = __webpack_require__(/*! Common/Cache */ 19),
+
+ MessageStore = __webpack_require__(/*! Stores/User/Message */ 32),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function FolderClearPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsFolderClear');
+
+ this.selectedFolder = ko.observable(null);
+ this.clearingProcess = ko.observable(false);
+ this.clearingError = ko.observable('');
+
+ this.folderFullNameForClear = ko.computed(function () {
+ var oFolder = this.selectedFolder();
+ return oFolder ? oFolder.printableFullName() : '';
+ }, this);
+
+ this.folderNameForClear = ko.computed(function () {
+ var oFolder = this.selectedFolder();
+ return oFolder ? oFolder.localName() : '';
+ }, this);
+
+ this.dangerDescHtml = ko.computed(function () {
+ return Translator.i18n('POPUPS_CLEAR_FOLDER/DANGER_DESC_HTML_1', {
+ 'FOLDER': this.folderNameForClear()
+ });
+ }, this);
+
+ this.clearCommand = Utils.createCommand(this, function () {
+
+ var
+ self = this,
+ oFolderToClear = this.selectedFolder()
+ ;
+
+ if (oFolderToClear)
+ {
+ MessageStore.message(null);
+ MessageStore.messageList([]);
+
+ this.clearingProcess(true);
+
+ oFolderToClear.messageCountAll(0);
+ oFolderToClear.messageCountUnread(0);
+
+ Cache.setFolderHash(oFolderToClear.fullNameRaw, '');
+
+ Remote.folderClear(function (sResult, oData) {
+
+ self.clearingProcess(false);
+ if (Enums.StorageResultType.Success === sResult && oData && oData.Result)
+ {
+ __webpack_require__(/*! App/User */ 7).default.reloadMessageList(true);
+ self.cancelCommand();
+ }
+ else
+ {
+ if (oData && oData.ErrorCode)
+ {
+ self.clearingError(Translator.getNotification(oData.ErrorCode));
+ }
+ else
+ {
+ self.clearingError(Translator.getNotification(Enums.Notification.MailServerError));
+ }
+ }
+ }, oFolderToClear.fullNameRaw);
+ }
+
+ }, function () {
+
+ var
+ oFolder = this.selectedFolder(),
+ bIsClearing = this.clearingProcess()
+ ;
+
+ return !bIsClearing && null !== oFolder;
+
+ });
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/FolderClear', 'PopupsFolderClearViewModel'], FolderClearPopupView);
+ _.extend(FolderClearPopupView.prototype, AbstractView.prototype);
+
+ FolderClearPopupView.prototype.clearPopup = function ()
+ {
+ this.clearingProcess(false);
+ this.selectedFolder(null);
+ };
+
+ FolderClearPopupView.prototype.onShow = function (oFolder)
+ {
+ this.clearPopup();
+ if (oFolder)
+ {
+ this.selectedFolder(oFolder);
+ }
+ };
+
+ module.exports = FolderClearPopupView;
+
+ }());
+
+
+/***/ },
+/* 147 */
+/*!******************************************!*\
+ !*** ./dev/View/Popup/MessageOpenPgp.js ***!
+ \******************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+ key = __webpack_require__(/*! key */ 18),
+ $ = __webpack_require__(/*! $ */ 14),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function MessageOpenPgpPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsMessageOpenPgp');
+
+ this.notification = ko.observable('');
+
+ this.selectedKey = ko.observable(null);
+ this.privateKeys = ko.observableArray([]);
+
+ this.password = ko.observable('');
+ this.password.focus = ko.observable(false);
+ this.buttonFocus = ko.observable(false);
+
+ this.resultCallback = null;
+
+ this.submitRequest = ko.observable(false);
+
+ // commands
+ this.doCommand = Utils.createCommand(this, function () {
+
+ this.submitRequest(true);
+
+ _.delay(_.bind(function() {
+
+ var
+ oPrivateKeys = [],
+ oPrivateKey = null
+ ;
+
+ try
+ {
+ if (this.resultCallback && this.selectedKey())
+ {
+ oPrivateKeys = this.selectedKey().getNativeKeys();
+ oPrivateKey = oPrivateKeys && oPrivateKeys[0] ? oPrivateKeys[0] : null;
+
+ if (oPrivateKey)
+ {
+ try
+ {
+ if (!oPrivateKey.decrypt(Utils.pString(this.password())))
+ {
+ Utils.log('Error: Private key cannot be decrypted');
+ oPrivateKey = null;
+ }
+ }
+ catch (e)
+ {
+ Utils.log(e);
+ oPrivateKey = null;
+ }
+ }
+ else
+ {
+ Utils.log('Error: Private key cannot be found');
+ }
+ }
+ }
+ catch (e)
+ {
+ Utils.log(e);
+ oPrivateKey = null;
+ }
+
+ this.submitRequest(false);
+
+ this.cancelCommand();
+ this.resultCallback(oPrivateKey);
+
+ }, this), 100);
+
+ }, function () {
+ return !this.submitRequest();
+ });
+
+ this.sDefaultKeyScope = Enums.KeyState.PopupMessageOpenPGP;
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/MessageOpenPgp'], MessageOpenPgpPopupView);
+ _.extend(MessageOpenPgpPopupView.prototype, AbstractView.prototype);
+
+ MessageOpenPgpPopupView.prototype.clearPopup = function ()
+ {
+ this.notification('');
+
+ this.password('');
+ this.password.focus(false);
+ this.buttonFocus(false);
+
+ this.selectedKey(false);
+ this.submitRequest(false);
+
+ this.resultCallback = null;
+ this.privateKeys([]);
+ };
+
+ MessageOpenPgpPopupView.prototype.onBuild = function (oDom)
+ {
+ key('tab,shift+tab', Enums.KeyState.PopupMessageOpenPGP, _.bind(function () {
+
+ switch (true)
+ {
+ case this.password.focus():
+ this.buttonFocus(true);
+ break;
+ case this.buttonFocus():
+ this.password.focus(true);
+ break;
+ }
+
+ return false;
+
+ }, this));
+
+ var self = this;
+
+ oDom
+ .on('click', '.key-list__item', function () {
+
+ oDom.find('.key-list__item .key-list__item__radio')
+ .addClass('icon-radio-unchecked')
+ .removeClass('icon-radio-checked')
+ ;
+
+ $(this).find('.key-list__item__radio')
+ .removeClass('icon-radio-unchecked')
+ .addClass('icon-radio-checked')
+ ;
+
+ self.selectedKey(ko.dataFor(this));
+
+ self.password.focus(true);
+ })
+ ;
+ };
+
+ MessageOpenPgpPopupView.prototype.onHideWithDelay = function ()
+ {
+ this.clearPopup();
+ };
+
+ MessageOpenPgpPopupView.prototype.onShowWithDelay = function ()
+ {
+ this.password.focus(true);
+ // this.buttonFocus(true);
+ };
+
+ MessageOpenPgpPopupView.prototype.onShow = function (fCallback, aPrivateKeys)
+ {
+ this.clearPopup();
+
+ this.resultCallback = fCallback;
+ this.privateKeys(aPrivateKeys);
+
+ if (this.viewModelDom)
+ {
+ this.viewModelDom.find('.key-list__item').first().click();
+ }
+ };
+
+ module.exports = MessageOpenPgpPopupView;
+
+ }());
+
+
+/***/ },
+/* 148 */
+/*!*****************************************!*\
+ !*** ./dev/View/Popup/NewOpenPgpKey.js ***!
+ \*****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ PgpStore = __webpack_require__(/*! Stores/User/Pgp */ 33),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function NewOpenPgpKeyPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsNewOpenPgpKey');
+
+ this.email = ko.observable('');
+ this.email.focus = ko.observable('');
+ this.email.error = ko.observable(false);
+
+ this.name = ko.observable('');
+ this.password = ko.observable('');
+ this.keyBitLength = ko.observable(2048);
+
+ this.submitRequest = ko.observable(false);
+
+ this.email.subscribe(function () {
+ this.email.error(false);
+ }, this);
+
+ this.generateOpenPgpKeyCommand = Utils.createCommand(this, function () {
+
+ var
+ self = this,
+ oUserIds = {},
+ oOpenpgpKeyring = PgpStore.openpgpKeyring
+ ;
+
+ this.email.error('' === Utils.trim(this.email()));
+ if (!oOpenpgpKeyring || this.email.error())
+ {
+ return false;
+ }
+
+ oUserIds['email'] = this.email();
+ if ('' !== this.name())
+ {
+ oUserIds['name'] = this.name();
+ }
+
+ this.submitRequest(true);
+
+ _.delay(function () {
+
+ var mPromise = false;
+
+ try {
+
+ mPromise = PgpStore.openpgp.generateKeyPair({
+ 'userId': oUserIds,
+ 'numBits': Utils.pInt(self.keyBitLength()),
+ 'passphrase': Utils.trim(self.password())
+ });
+
+ mPromise.then(function (mKeyPair) {
+
+ self.submitRequest(false);
+
+ if (mKeyPair && mKeyPair.privateKeyArmored)
+ {
+ oOpenpgpKeyring.privateKeys.importKey(mKeyPair.privateKeyArmored);
+ oOpenpgpKeyring.publicKeys.importKey(mKeyPair.publicKeyArmored);
+
+ oOpenpgpKeyring.store();
+
+ __webpack_require__(/*! App/User */ 7).default.reloadOpenPgpKeys();
+ Utils.delegateRun(self, 'cancelCommand');
+ }
+
+ })['catch'](function() {
+ self.submitRequest(false);
+ });
+ }
+ catch (e)
+ {
+ Utils.log(e);
+ self.submitRequest(false);
+ }
+
+ }, 100);
+
+ return true;
+ });
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/NewOpenPgpKey', 'PopupsNewOpenPgpKeyViewModel'], NewOpenPgpKeyPopupView);
+ _.extend(NewOpenPgpKeyPopupView.prototype, AbstractView.prototype);
+
+ NewOpenPgpKeyPopupView.prototype.clearPopup = function ()
+ {
+ this.name('');
+ this.password('');
+
+ this.email('');
+ this.email.error(false);
+ this.keyBitLength(2048);
+ };
+
+ NewOpenPgpKeyPopupView.prototype.onShow = function ()
+ {
+ this.clearPopup();
+ };
+
+ NewOpenPgpKeyPopupView.prototype.onShowWithDelay = function ()
+ {
+ this.email.focus(true);
+ };
+
+ module.exports = NewOpenPgpKeyPopupView;
+
+ }());
+
+/***/ },
+/* 149 */,
+/* 150 */
+/*!*****************************************!*\
+ !*** ./dev/View/Popup/TwoFactorTest.js ***!
+ \*****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function TwoFactorTestPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsTwoFactorTest');
+
+ var self = this;
+
+ this.code = ko.observable('');
+ this.code.focused = ko.observable(false);
+ this.code.status = ko.observable(null);
+
+ this.koTestedTrigger = null;
+
+ this.testing = ko.observable(false);
+
+ // commands
+ this.testCode = Utils.createCommand(this, function () {
+
+ this.testing(true);
+ Remote.testTwoFactor(function (sResult, oData) {
+
+ self.testing(false);
+ self.code.status(Enums.StorageResultType.Success === sResult && oData && oData.Result ? true : false);
+
+ if (self.koTestedTrigger && self.code.status())
+ {
+ self.koTestedTrigger(true);
+ }
+
+ }, this.code());
+
+ }, function () {
+ return '' !== this.code() && !this.testing();
+ });
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/TwoFactorTest', 'PopupsTwoFactorTestViewModel'], TwoFactorTestPopupView);
+ _.extend(TwoFactorTestPopupView.prototype, AbstractView.prototype);
+
+ TwoFactorTestPopupView.prototype.clearPopup = function ()
+ {
+ this.code('');
+ this.code.focused(false);
+ this.code.status(null);
+ this.testing(false);
+
+ this.koTestedTrigger = null;
+ };
+
+ TwoFactorTestPopupView.prototype.onShow = function (koTestedTrigger)
+ {
+ this.clearPopup();
+
+ this.koTestedTrigger = koTestedTrigger;
+ };
+
+ TwoFactorTestPopupView.prototype.onShowWithDelay = function ()
+ {
+ if (!Globals.bMobile)
+ {
+ this.code.focused(true);
+ }
+ };
+
+ module.exports = TwoFactorTestPopupView;
+
+ }());
+
+/***/ },
+/* 151 */
+/*!******************************************!*\
+ !*** ./dev/View/Popup/ViewOpenPgpKey.js ***!
+ \******************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+ key = __webpack_require__(/*! key */ 18),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function ViewOpenPgpKeyPopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsViewOpenPgpKey');
+
+ this.key = ko.observable('');
+ this.keyDom = ko.observable(null);
+
+ this.sDefaultKeyScope = Enums.KeyState.PopupViewOpenPGP;
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/ViewOpenPgpKey', 'PopupsViewOpenPgpKeyViewModel'], ViewOpenPgpKeyPopupView);
+ _.extend(ViewOpenPgpKeyPopupView.prototype, AbstractView.prototype);
+
+ ViewOpenPgpKeyPopupView.prototype.clearPopup = function ()
+ {
+ this.key('');
+ };
+
+ ViewOpenPgpKeyPopupView.prototype.selectKey = function ()
+ {
+ var oEl = this.keyDom();
+ if (oEl)
+ {
+ Utils.selectElement(oEl);
+ }
+ };
+
+ ViewOpenPgpKeyPopupView.prototype.onShow = function (oOpenPgpKey)
+ {
+ this.clearPopup();
+
+ if (oOpenPgpKey)
+ {
+ this.key(oOpenPgpKey.armor);
+ }
+ };
+
+ ViewOpenPgpKeyPopupView.prototype.onBuild = function ()
+ {
+ key('ctrl+a, command+a', Enums.KeyState.PopupViewOpenPGP, _.bind(function () {
+ this.selectKey();
+ return false;
+ }, this));
+ };
+
+ module.exports = ViewOpenPgpKeyPopupView;
+
+ }());
+
+/***/ },
+/* 152 */
+/*!***************************************!*\
+ !*** ./dev/View/Popup/WelcomePage.js ***!
+ \***************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Promises = __webpack_require__(/*! Promises/User/Ajax */ 41),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function WelcomePagePopupView()
+ {
+ AbstractView.call(this, 'Popups', 'PopupsWelcomePage');
+
+ this.welcomePageURL = ko.observable('');
+
+ this.closeFocused = ko.observable(false);
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/Popup/WelcomePage', 'WelcomePagePopupViewModel'], WelcomePagePopupView);
+ _.extend(WelcomePagePopupView.prototype, AbstractView.prototype);
+
+ WelcomePagePopupView.prototype.clearPopup = function ()
+ {
+ this.welcomePageURL('');
+ this.closeFocused(false);
+ };
+
+ /**
+ * @param {string} sUrl
+ */
+ WelcomePagePopupView.prototype.onShow = function (sUrl)
+ {
+ this.clearPopup();
+
+ this.welcomePageURL(sUrl);
+ };
+
+ WelcomePagePopupView.prototype.onShowWithDelay = function ()
+ {
+ this.closeFocused(true);
+ };
+
+ WelcomePagePopupView.prototype.onHide = function ()
+ {
+ Promises.welcomeClose();
+ };
+
+ module.exports = WelcomePagePopupView;
+
+ }());
+
+/***/ },
+/* 153 */
+/*!********************************!*\
+ !*** ./dev/View/User/Login.js ***!
+ \********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ ko = __webpack_require__(/*! ko */ 2),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Plugins = __webpack_require__(/*! Common/Plugins */ 23),
+
+ LanguageStore = __webpack_require__(/*! Stores/Language */ 40),
+ AppStore = __webpack_require__(/*! Stores/User/App */ 24),
+
+ Local = __webpack_require__(/*! Storage/Client */ 47),
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function LoginUserView()
+ {
+ AbstractView.call(this, 'Center', 'Login');
+
+ this.welcome = ko.observable(!!Settings.settingsGet('UseLoginWelcomePage'));
+
+ this.email = ko.observable('');
+ this.password = ko.observable('');
+ this.signMe = ko.observable(false);
+
+ this.additionalCode = ko.observable('');
+ this.additionalCode.error = ko.observable(false);
+ this.additionalCode.errorAnimation = ko.observable(false).extend({'falseTimeout': 500});
+ this.additionalCode.focused = ko.observable(false);
+ this.additionalCode.visibility = ko.observable(false);
+ this.additionalCodeSignMe = ko.observable(false);
+
+ this.logoImg = Utils.trim(Settings.settingsGet('LoginLogo'));
+ this.logoPowered = !!Settings.settingsGet('LoginPowered');
+ this.loginDescription = Utils.trim(Settings.settingsGet('LoginDescription'));
+
+ this.mobile = !!Settings.appSettingsGet('mobile');
+ this.mobileDevice = !!Settings.appSettingsGet('mobileDevice');
+
+ this.forgotPasswordLinkUrl = Settings.appSettingsGet('forgotPasswordLinkUrl');
+ this.registrationLinkUrl = Settings.appSettingsGet('registrationLinkUrl');
+
+ this.emailError = ko.observable(false);
+ this.passwordError = ko.observable(false);
+
+ this.emailErrorAnimation = ko.observable(false).extend({'falseTimeout': 500});
+ this.passwordErrorAnimation = ko.observable(false).extend({'falseTimeout': 500});
+
+ this.formHidden = ko.observable(false);
+
+ this.formError = ko.computed(function () {
+ return this.emailErrorAnimation() || this.passwordErrorAnimation() ||
+ (this.additionalCode.visibility() && this.additionalCode.errorAnimation());
+ }, this);
+
+ this.emailFocus = ko.observable(false);
+ this.passwordFocus = ko.observable(false);
+ this.submitFocus = ko.observable(false);
+
+ this.email.subscribe(function () {
+ this.emailError(false);
+ this.additionalCode('');
+ this.additionalCode.visibility(false);
+ }, this);
+
+ this.password.subscribe(function () {
+ this.passwordError(false);
+ }, this);
+
+ this.additionalCode.subscribe(function () {
+ this.additionalCode.error(false);
+ }, this);
+
+ this.additionalCode.visibility.subscribe(function () {
+ this.additionalCode.error(false);
+ }, this);
+
+ this.emailError.subscribe(function (bV) {
+ this.emailErrorAnimation(!!bV);
+ }, this);
+
+ this.passwordError.subscribe(function (bV) {
+ this.passwordErrorAnimation(!!bV);
+ }, this);
+
+ this.additionalCode.error.subscribe(function (bV) {
+ this.additionalCode.errorAnimation(!!bV);
+ }, this);
+
+ this.submitRequest = ko.observable(false);
+ this.submitError = ko.observable('');
+ this.submitErrorAddidional = ko.observable('');
+
+ this.submitError.subscribe(function (sValue) {
+ if ('' === sValue)
+ {
+ this.submitErrorAddidional('');
+ }
+ }, this);
+
+ this.allowLanguagesOnLogin = AppStore.allowLanguagesOnLogin;
+
+ this.langRequest = ko.observable(false);
+ this.language = LanguageStore.language;
+ this.languages = LanguageStore.languages;
+
+ this.bSendLanguage = false;
+
+ this.languageFullName = ko.computed(function () {
+ return Utils.convertLangName(this.language());
+ }, this);
+
+ this.signMeType = ko.observable(Enums.LoginSignMeType.Unused);
+
+ this.signMeType.subscribe(function (iValue) {
+ this.signMe(Enums.LoginSignMeType.DefaultOn === iValue);
+ }, this);
+
+ this.signMeVisibility = ko.computed(function () {
+ return Enums.LoginSignMeType.Unused !== this.signMeType();
+ }, this);
+
+ this.submitCommand = Utils.createCommand(this, function () {
+
+ Utils.triggerAutocompleteInputChange();
+
+ this.emailError(false);
+ this.passwordError(false);
+
+ this.emailError('' === Utils.trim(this.email()));
+ this.passwordError('' === Utils.trim(this.password()));
+
+ if (this.additionalCode.visibility())
+ {
+ this.additionalCode.error(false);
+ this.additionalCode.error('' === Utils.trim(this.additionalCode()));
+ }
+
+ if (this.emailError() || this.passwordError() ||
+ (this.additionalCode.visibility() && this.additionalCode.error()))
+ {
+ switch (true)
+ {
+ case this.emailError():
+ this.emailFocus(true);
+ break;
+ case this.passwordError():
+ this.passwordFocus(true);
+ break;
+ case this.additionalCode.visibility() && this.additionalCode.error():
+ this.additionalCode.focused(true);
+ break;
+ }
+
+ return false;
+ }
+
+ var
+ iPluginResultCode = 0,
+ sPluginResultMessage = '',
+ fSubmitResult = function (iResultCode, sResultMessage) {
+ iPluginResultCode = iResultCode || 0;
+ sPluginResultMessage = sResultMessage || '';
+ }
+ ;
+
+ Plugins.runHook('user-login-submit', [fSubmitResult]);
+ if (0 < iPluginResultCode)
+ {
+ this.submitError(Translator.getNotification(iPluginResultCode));
+ return false;
+ }
+ else if ('' !== sPluginResultMessage)
+ {
+ this.submitError(sPluginResultMessage);
+ return false;
+ }
+
+ this.submitRequest(true);
+
+ var
+ self = this,
+ sPassword = this.password(),
+
+ fLoginRequest = _.bind(function (sPassword) {
+
+ Remote.login(_.bind(function (sResult, oData) {
+
+ if (Enums.StorageResultType.Success === sResult && oData && 'Login' === oData.Action)
+ {
+ if (oData.Result)
+ {
+ if (oData.TwoFactorAuth)
+ {
+ this.additionalCode('');
+ this.additionalCode.visibility(true);
+ this.submitRequest(false);
+
+ _.delay(function(){
+ self.additionalCode.focused(true);
+ }, 100);
+ }
+ else if (oData.Admin)
+ {
+ __webpack_require__(/*! App/User */ 7).default.redirectToAdminPanel();
+ }
+ else
+ {
+ __webpack_require__(/*! App/User */ 7).default.loginAndLogoutReload(false);
+ }
+ }
+ else if (oData.ErrorCode)
+ {
+ this.submitRequest(false);
+ if (-1 < Utils.inArray(oData.ErrorCode, [Enums.Notification.InvalidInputArgument]))
+ {
+ oData.ErrorCode = Enums.Notification.AuthError;
+ }
+
+ this.submitError(Translator.getNotificationFromResponse(oData));
+
+ if ('' === this.submitError())
+ {
+ this.submitError(Translator.getNotification(Enums.Notification.UnknownError));
+ }
+ else
+ {
+ if (oData.ErrorMessageAdditional)
+ {
+ this.submitErrorAddidional(oData.ErrorMessageAdditional);
+ }
+ }
+ }
+ else
+ {
+ this.submitRequest(false);
+ }
+ }
+ else
+ {
+ this.submitRequest(false);
+ this.submitError(Translator.getNotification(Enums.Notification.UnknownError));
+ }
+
+ }, this), this.email(), '', sPassword, !!this.signMe(),
+ this.bSendLanguage ? this.language() : '',
+ this.additionalCode.visibility() ? this.additionalCode() : '',
+ this.additionalCode.visibility() ? !!this.additionalCodeSignMe() : false
+ );
+
+ Local.set(Enums.ClientSideKeyName.LastSignMe, !!this.signMe() ? '-1-' : '-0-');
+
+ }, this)
+ ;
+
+ if (Settings.appSettingsGet('rsaPublicKey') && Utils.rsaEncode.supported)
+ {
+ fLoginRequest(Utils.rsaEncode(sPassword, Settings.appSettingsGet('rsaPublicKey')));
+ }
+ else
+ {
+ fLoginRequest(sPassword);
+ }
+
+ return true;
+
+ }, function () {
+ return !this.submitRequest();
+ });
+
+ this.facebookLoginEnabled = ko.observable(false);
+
+ this.facebookCommand = Utils.createCommand(this, function () {
+
+ window.open(Links.socialFacebook(), 'Facebook',
+ 'left=200,top=100,width=650,height=450,menubar=no,status=no,resizable=yes,scrollbars=yes');
+
+ return true;
+
+ }, function () {
+ return !this.submitRequest() && this.facebookLoginEnabled();
+ });
+
+ this.googleLoginEnabled = ko.observable(false);
+ this.googleFastLoginEnabled = ko.observable(false);
+
+ this.googleCommand = Utils.createCommand(this, function () {
+
+ window.open(Links.socialGoogle(), 'Google',
+ 'left=200,top=100,width=650,height=500,menubar=no,status=no,resizable=yes,scrollbars=yes');
+
+ return true;
+
+ }, function () {
+ return !this.submitRequest() && this.googleLoginEnabled();
+ });
+
+ this.googleFastCommand = Utils.createCommand(this, function () {
+
+ window.open(Links.socialGoogle(true), 'Google',
+ 'left=200,top=100,width=650,height=500,menubar=no,status=no,resizable=yes,scrollbars=yes');
+
+ return true;
+
+ }, function () {
+ return !this.submitRequest() && this.googleFastLoginEnabled();
+ });
+
+ this.twitterLoginEnabled = ko.observable(false);
+
+ this.twitterCommand = Utils.createCommand(this, function () {
+
+ window.open(Links.socialTwitter(), 'Twitter',
+ 'left=200,top=100,width=650,height=450,menubar=no,status=no,resizable=yes,scrollbars=yes');
+
+ return true;
+
+ }, function () {
+ return !this.submitRequest() && this.twitterLoginEnabled();
+ });
+
+ this.socialLoginEnabled = ko.computed(function () {
+
+ var
+ bF = this.facebookLoginEnabled(),
+ bG = this.googleLoginEnabled(),
+ bT = this.twitterLoginEnabled()
+ ;
+
+ return bF || bG || bT;
+ }, this);
+
+ if (Settings.settingsGet('AdditionalLoginError') && !this.submitError())
+ {
+ this.submitError(Settings.settingsGet('AdditionalLoginError'));
+ }
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/User/Login', 'View/App/Login', 'LoginViewModel'], LoginUserView);
+ _.extend(LoginUserView.prototype, AbstractView.prototype);
+
+ LoginUserView.prototype.displayMainForm = function ()
+ {
+ this.welcome(false);
+ };
+
+ LoginUserView.prototype.onShow = function ()
+ {
+ kn.routeOff();
+ };
+
+ LoginUserView.prototype.onShowWithDelay = function ()
+ {
+ if ('' !== this.email() && '' !== this.password())
+ {
+ this.submitFocus(true);
+ }
+ else if ('' === this.email())
+ {
+ this.emailFocus(true);
+ }
+ else if ('' === this.password())
+ {
+ this.passwordFocus(true);
+ }
+ else
+ {
+ this.emailFocus(true);
+ }
+ };
+
+ LoginUserView.prototype.onHide = function ()
+ {
+ this.submitFocus(false);
+ this.emailFocus(false);
+ this.passwordFocus(false);
+ };
+
+ LoginUserView.prototype.onBuild = function ()
+ {
+ var
+ self = this,
+ sSignMeLocal = Local.get(Enums.ClientSideKeyName.LastSignMe),
+ sSignMe = (Settings.settingsGet('SignMe') || 'unused').toLowerCase(),
+ sJsHash = Settings.appSettingsGet('jsHash'),
+ fSocial = function (iErrorCode) {
+ iErrorCode = Utils.pInt(iErrorCode);
+ if (0 === iErrorCode)
+ {
+ self.submitRequest(true);
+ __webpack_require__(/*! App/User */ 7).default.loginAndLogoutReload(false);
+ }
+ else
+ {
+ self.submitError(Translator.getNotification(iErrorCode));
+ }
+ }
+ ;
+
+ this.facebookLoginEnabled(!!Settings.settingsGet('AllowFacebookSocial'));
+ this.twitterLoginEnabled(!!Settings.settingsGet('AllowTwitterSocial'));
+ this.googleLoginEnabled(!!Settings.settingsGet('AllowGoogleSocial') &&
+ !!Settings.settingsGet('AllowGoogleSocialAuth'));
+ this.googleFastLoginEnabled(!!Settings.settingsGet('AllowGoogleSocial') &&
+ !!Settings.settingsGet('AllowGoogleSocialAuthFast'));
+
+ switch (sSignMe)
+ {
+ case Enums.LoginSignMeTypeAsString.DefaultOff:
+ case Enums.LoginSignMeTypeAsString.DefaultOn:
+
+ this.signMeType(Enums.LoginSignMeTypeAsString.DefaultOn === sSignMe ?
+ Enums.LoginSignMeType.DefaultOn : Enums.LoginSignMeType.DefaultOff);
+
+ switch (sSignMeLocal)
+ {
+ case '-1-':
+ this.signMeType(Enums.LoginSignMeType.DefaultOn);
+ break;
+ case '-0-':
+ this.signMeType(Enums.LoginSignMeType.DefaultOff);
+ break;
+ }
+
+ break;
+ default:
+ case Enums.LoginSignMeTypeAsString.Unused:
+ this.signMeType(Enums.LoginSignMeType.Unused);
+ break;
+ }
+
+ this.email(AppStore.devEmail);
+ this.password(AppStore.devPassword);
+
+ if (this.googleLoginEnabled() || this.googleFastLoginEnabled())
+ {
+ window['rl_' + sJsHash + '_google_login_service'] = fSocial;
+ }
+
+ if (this.facebookLoginEnabled())
+ {
+ window['rl_' + sJsHash + '_facebook_login_service'] = fSocial;
+ }
+
+ if (this.twitterLoginEnabled())
+ {
+ window['rl_' + sJsHash + '_twitter_login_service'] = fSocial;
+ }
+
+ _.delay(function () {
+ LanguageStore.language.subscribe(function (sValue) {
+
+ self.langRequest(true);
+
+ Translator.reload(false, sValue, function() {
+ self.langRequest(false);
+ self.bSendLanguage = true;
+ }, function() {
+ self.langRequest(false);
+ });
+
+ });
+ }, 50);
+
+ Utils.triggerAutocompleteInputChange(true);
+ };
+
+ LoginUserView.prototype.submitForm = function ()
+ {
+ this.submitCommand();
+ };
+
+ LoginUserView.prototype.selectLanguage = function ()
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/Languages */ 44), [
+ this.language, this.languages(), LanguageStore.userLanguage()
+ ]);
+ };
+
+ LoginUserView.prototype.selectLanguageOnTab = function (bShift)
+ {
+ if (!bShift)
+ {
+ var self = this;
+ _.delay(function () {
+ self.emailFocus(true);
+ }, 5);
+
+ return false;
+ }
+
+ return true;
+ };
+
+ module.exports = LoginUserView;
+
+ }());
+
+/***/ },
+/* 154 */
+/*!*********************************************!*\
+ !*** ./dev/View/User/MailBox/FolderList.js ***!
+ \*********************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+ key = __webpack_require__(/*! key */ 18),
+
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+
+ Cache = __webpack_require__(/*! Common/Cache */ 19),
+
+ AppStore = __webpack_require__(/*! Stores/User/App */ 24),
+ SettingsStore = __webpack_require__(/*! Stores/User/Settings */ 28),
+ FolderStore = __webpack_require__(/*! Stores/User/Folder */ 21),
+ MessageStore = __webpack_require__(/*! Stores/User/Message */ 32),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function FolderListMailBoxUserView()
+ {
+ AbstractView.call(this, 'Left', 'MailFolderList');
+
+ this.oContentVisible = null;
+ this.oContentScrollable = null;
+
+ this.composeInEdit = AppStore.composeInEdit;
+
+ this.messageList = MessageStore.messageList;
+ this.folderList = FolderStore.folderList;
+ this.folderListSystem = FolderStore.folderListSystem;
+ this.foldersChanging = FolderStore.foldersChanging;
+
+ this.foldersListWithSingleInboxRootFolder = FolderStore.foldersListWithSingleInboxRootFolder;
+
+ this.leftPanelDisabled = Globals.leftPanelDisabled;
+
+ this.iDropOverTimer = 0;
+
+ this.allowComposer = !!Settings.capa(Enums.Capa.Composer);
+ this.allowContacts = !!AppStore.contactsIsAllowed();
+ this.allowFolders = !!Settings.capa(Enums.Capa.Folders);
+
+ this.folderListFocused = ko.computed(function () {
+ return Enums.Focused.FolderList === AppStore.focusedState();
+ });
+
+ this.isInboxStarred = ko.computed(function () {
+ return FolderStore.currentFolder() &&
+ FolderStore.currentFolder().isInbox() &&
+ -1 < Utils.trim(MessageStore.messageListSearch()).indexOf('is:flagged')
+ ;
+ });
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/User/MailBox/FolderList', 'View/App/MailBox/FolderList', 'MailBoxFolderListViewModel'], FolderListMailBoxUserView);
+ _.extend(FolderListMailBoxUserView.prototype, AbstractView.prototype);
+
+ FolderListMailBoxUserView.prototype.onBuild = function (oDom)
+ {
+ this.oContentVisible = $('.b-content', oDom);
+ this.oContentScrollable = $('.content', this.oContentVisible);
+
+ var
+ self = this,
+ bMobile = Settings.appSettingsGet('mobile'),
+ fSelectFolder = function (oEvent, bStarred) {
+
+ if (bMobile)
+ {
+ Globals.leftPanelDisabled(true);
+ }
+
+ oEvent.preventDefault();
+
+ if (bStarred)
+ {
+ oEvent.stopPropagation();
+ }
+
+ var
+ oFolder = ko.dataFor(this)
+ ;
+
+ if (oFolder)
+ {
+ if (Enums.Layout.NoPreview === SettingsStore.layout())
+ {
+ MessageStore.message(null);
+ }
+
+ if (oFolder.fullNameRaw === FolderStore.currentFolderFullNameRaw())
+ {
+ Cache.setFolderHash(oFolder.fullNameRaw, '');
+ }
+
+ if (bStarred)
+ {
+ kn.setHash(Links.mailBox(oFolder.fullNameHash, 1, 'is:flagged'));
+ }
+ else
+ {
+ kn.setHash(Links.mailBox(oFolder.fullNameHash));
+ }
+ }
+ }
+ ;
+
+ oDom
+ .on('click', '.b-folders .e-item .e-link .e-collapsed-sign', function (oEvent) {
+
+ var
+ oFolder = ko.dataFor(this),
+ bCollapsed = false
+ ;
+
+ if (oFolder && oEvent)
+ {
+ bCollapsed = oFolder.collapsed();
+ __webpack_require__(/*! App/User */ 7).default.setExpandedFolder(oFolder.fullNameHash, bCollapsed);
+
+ oFolder.collapsed(!bCollapsed);
+ oEvent.preventDefault();
+ oEvent.stopPropagation();
+ }
+ })
+ .on('click', '.b-folders .e-item .e-link.selectable .inbox-star-icon', function (oEvent) {
+ fSelectFolder.call(this, oEvent, !self.isInboxStarred());
+ })
+ .on('click', '.b-folders .e-item .e-link.selectable', function (oEvent) {
+ fSelectFolder.call(this, oEvent, false);
+ })
+ ;
+
+ key('up, down', Enums.KeyState.FolderList, function (event, handler) {
+
+ var
+ iIndex = -1,
+ iKeyCode = handler && 'up' === handler.shortcut ? 38 : 40,
+ $items = $('.b-folders .e-item .e-link:not(.hidden):visible', oDom)
+ ;
+
+ if (event && $items.length)
+ {
+ iIndex = $items.index($items.filter('.focused'));
+ if (-1 < iIndex)
+ {
+ $items.eq(iIndex).removeClass('focused');
+ }
+
+ if (iKeyCode === 38 && iIndex > 0)
+ {
+ iIndex--;
+ }
+ else if (iKeyCode === 40 && iIndex < $items.length - 1)
+ {
+ iIndex++;
+ }
+
+ $items.eq(iIndex).addClass('focused');
+ self.scrollToFocused();
+ }
+
+ return false;
+ });
+
+ key('enter', Enums.KeyState.FolderList, function () {
+ var $items = $('.b-folders .e-item .e-link:not(.hidden).focused', oDom);
+ if ($items.length && $items[0])
+ {
+ AppStore.focusedState(Enums.Focused.MessageList);
+ $items.click();
+ }
+
+ return false;
+ });
+
+ key('space', Enums.KeyState.FolderList, function () {
+ var bCollapsed = true, oFolder = null, $items = $('.b-folders .e-item .e-link:not(.hidden).focused', oDom);
+ if ($items.length && $items[0])
+ {
+ oFolder = ko.dataFor($items[0]);
+ if (oFolder)
+ {
+ bCollapsed = oFolder.collapsed();
+ __webpack_require__(/*! App/User */ 7).default.setExpandedFolder(oFolder.fullNameHash, bCollapsed);
+ oFolder.collapsed(!bCollapsed);
+ }
+ }
+
+ return false;
+ });
+
+ key('esc, tab, shift+tab, right', Enums.KeyState.FolderList, function () {
+ AppStore.focusedState(Enums.Focused.MessageList);
+ return false;
+ });
+
+ AppStore.focusedState.subscribe(function (mValue) {
+ $('.b-folders .e-item .e-link.focused', oDom).removeClass('focused');
+ if (Enums.Focused.FolderList === mValue)
+ {
+ $('.b-folders .e-item .e-link.selected', oDom).addClass('focused');
+ }
+ });
+ };
+
+ FolderListMailBoxUserView.prototype.messagesDropOver = function (oFolder)
+ {
+ window.clearTimeout(this.iDropOverTimer);
+ if (oFolder && oFolder.collapsed())
+ {
+ this.iDropOverTimer = window.setTimeout(function () {
+ oFolder.collapsed(false);
+ __webpack_require__(/*! App/User */ 7).default.setExpandedFolder(oFolder.fullNameHash, true);
+ Utils.windowResize();
+ }, 500);
+ }
+ };
+
+ FolderListMailBoxUserView.prototype.messagesDropOut = function ()
+ {
+ window.clearTimeout(this.iDropOverTimer);
+ };
+
+ FolderListMailBoxUserView.prototype.scrollToFocused = function ()
+ {
+ if (!this.oContentVisible || !this.oContentScrollable)
+ {
+ return false;
+ }
+
+ var
+ iOffset = 20,
+ oFocused = $('.e-item .e-link.focused', this.oContentScrollable),
+ oPos = oFocused.position(),
+ iVisibleHeight = this.oContentVisible.height(),
+ iFocusedHeight = oFocused.outerHeight()
+ ;
+
+ if (oPos && (oPos.top < 0 || oPos.top + iFocusedHeight > iVisibleHeight))
+ {
+ if (oPos.top < 0)
+ {
+ this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + oPos.top - iOffset);
+ }
+ else
+ {
+ this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop() + oPos.top - iVisibleHeight + iFocusedHeight + iOffset);
+ }
+
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {FolderModel} oToFolder
+ * @param {{helper:jQuery}} oUi
+ */
+ FolderListMailBoxUserView.prototype.messagesDrop = function (oToFolder, oUi)
+ {
+ if (oToFolder && oUi && oUi.helper)
+ {
+ var
+ sFromFolderFullNameRaw = oUi.helper.data('rl-folder'),
+ bCopy = Globals.$html.hasClass('rl-ctrl-key-pressed'),
+ aUids = oUi.helper.data('rl-uids')
+ ;
+
+ if (Utils.isNormal(sFromFolderFullNameRaw) && '' !== sFromFolderFullNameRaw && Utils.isArray(aUids))
+ {
+ __webpack_require__(/*! App/User */ 7).default.moveMessagesToFolder(sFromFolderFullNameRaw, aUids, oToFolder.fullNameRaw, bCopy);
+ }
+ }
+ };
+
+ FolderListMailBoxUserView.prototype.composeClick = function ()
+ {
+ if (Settings.capa(Enums.Capa.Composer))
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/Compose */ 29));
+ }
+ };
+
+ FolderListMailBoxUserView.prototype.createFolder = function ()
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/FolderCreate */ 95));
+ };
+
+ FolderListMailBoxUserView.prototype.configureFolders = function ()
+ {
+ kn.setHash(Links.settings('folders'));
+ };
+
+ FolderListMailBoxUserView.prototype.contactsClick = function ()
+ {
+ if (this.allowContacts)
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/Contacts */ 62));
+ }
+ };
+
+ module.exports = FolderListMailBoxUserView;
+
+ }());
+
+
+/***/ },
+/* 155 */
+/*!**********************************************!*\
+ !*** ./dev/View/User/MailBox/MessageList.js ***!
+ \**********************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+ key = __webpack_require__(/*! key */ 18),
+ Jua = __webpack_require__(/*! Jua */ 80),
+ ifvisible = __webpack_require__(/*! ifvisible */ 172),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+ Events = __webpack_require__(/*! Common/Events */ 25),
+ Selector = __webpack_require__(/*! Common/Selector */ 100),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+
+ Cache = __webpack_require__(/*! Common/Cache */ 19),
+
+ AppStore = __webpack_require__(/*! Stores/User/App */ 24),
+ QuotaStore = __webpack_require__(/*! Stores/User/Quota */ 91),
+ SettingsStore = __webpack_require__(/*! Stores/User/Settings */ 28),
+ FolderStore = __webpack_require__(/*! Stores/User/Folder */ 21),
+ MessageStore = __webpack_require__(/*! Stores/User/Message */ 32),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function MessageListMailBoxUserView()
+ {
+ AbstractView.call(this, 'Right', 'MailMessageList');
+
+ this.sLastUid = null;
+ this.bPrefetch = false;
+ this.emptySubjectValue = '';
+
+ this.mobile = !!Settings.appSettingsGet('mobile');
+
+ this.allowReload = !!Settings.capa(Enums.Capa.Reload);
+ this.allowSearch = !!Settings.capa(Enums.Capa.Search);
+ this.allowSearchAdv = !!Settings.capa(Enums.Capa.SearchAdv);
+ this.allowComposer = !!Settings.capa(Enums.Capa.Composer);
+ this.allowMessageListActions = !!Settings.capa(Enums.Capa.MessageListActions);
+ this.allowDangerousActions = !!Settings.capa(Enums.Capa.DangerousActions);
+
+ this.popupVisibility = Globals.popupVisibility;
+
+ this.message = MessageStore.message;
+ this.messageList = MessageStore.messageList;
+ this.messageListDisableAutoSelect = MessageStore.messageListDisableAutoSelect;
+
+ this.folderList = FolderStore.folderList;
+
+ this.composeInEdit = AppStore.composeInEdit;
+ this.leftPanelDisabled = Globals.leftPanelDisabled;
+
+ this.selectorMessageSelected = MessageStore.selectorMessageSelected;
+ this.selectorMessageFocused = MessageStore.selectorMessageFocused;
+ this.isMessageSelected = MessageStore.isMessageSelected;
+ this.messageListSearch = MessageStore.messageListSearch;
+ this.messageListThreadUid = MessageStore.messageListThreadUid;
+ this.messageListError = MessageStore.messageListError;
+ this.folderMenuForMove = FolderStore.folderMenuForMove;
+
+ this.useCheckboxesInList = SettingsStore.useCheckboxesInList;
+
+ this.mainMessageListSearch = MessageStore.mainMessageListSearch;
+ this.messageListEndFolder = MessageStore.messageListEndFolder;
+ this.messageListEndThreadUid = MessageStore.messageListEndThreadUid;
+
+ this.messageListChecked = MessageStore.messageListChecked;
+ this.messageListCheckedOrSelected = MessageStore.messageListCheckedOrSelected;
+ this.messageListCheckedOrSelectedUidsWithSubMails = MessageStore.messageListCheckedOrSelectedUidsWithSubMails;
+ this.messageListCompleteLoadingThrottle = MessageStore.messageListCompleteLoadingThrottle;
+ this.messageListCompleteLoadingThrottleForAnimation = MessageStore.messageListCompleteLoadingThrottleForAnimation;
+
+ Translator.initOnStartOrLangChange(function () {
+ this.emptySubjectValue = Translator.i18n('MESSAGE_LIST/EMPTY_SUBJECT_TEXT');
+ }, this);
+
+ this.userQuota = QuotaStore.quota;
+ this.userUsageSize = QuotaStore.usage;
+ this.userUsageProc = QuotaStore.percentage;
+
+ this.moveDropdownTrigger = ko.observable(false);
+ this.moreDropdownTrigger = ko.observable(false);
+
+ // append drag and drop
+ this.dragOver = ko.observable(false).extend({'throttle': 1});
+ this.dragOverEnter = ko.observable(false).extend({'throttle': 1});
+ this.dragOverArea = ko.observable(null);
+ this.dragOverBodyArea = ko.observable(null);
+
+ this.messageListItemTemplate = ko.computed(function () {
+ return this.mobile || Enums.Layout.SidePreview === SettingsStore.layout() ?
+ 'MailMessageListItem' : 'MailMessageListItemNoPreviewPane';
+ }, this);
+
+ this.messageListSearchDesc = ko.computed(function () {
+ var sValue = MessageStore.messageListEndSearch();
+ return '' === sValue ? '' : Translator.i18n('MESSAGE_LIST/SEARCH_RESULT_FOR', {'SEARCH': sValue});
+ });
+
+ this.messageListPagenator = ko.computed(Utils.computedPagenatorHelper(
+ MessageStore.messageListPage, MessageStore.messageListPageCount));
+
+ this.checkAll = ko.computed({
+ 'read': function () {
+ return 0 < MessageStore.messageListChecked().length;
+ },
+
+ 'write': function (bValue) {
+ bValue = !!bValue;
+ _.each(MessageStore.messageList(), function (oMessage) {
+ oMessage.checked(bValue);
+ });
+ }
+ });
+
+ this.inputMessageListSearchFocus = ko.observable(false);
+
+ this.sLastSearchValue = '';
+ this.inputProxyMessageListSearch = ko.computed({
+ 'read': this.mainMessageListSearch,
+ 'write': function (sValue) {
+ this.sLastSearchValue = sValue;
+ },
+ 'owner': this
+ });
+
+ this.isIncompleteChecked = ko.computed(function () {
+ var
+ iM = MessageStore.messageList().length,
+ iC = MessageStore.messageListChecked().length
+ ;
+ return 0 < iM && 0 < iC && iM > iC;
+ }, this);
+
+ this.hasMessages = ko.computed(function () {
+ return 0 < this.messageList().length;
+ }, this);
+
+ this.hasCheckedOrSelectedLines = ko.computed(function () {
+ return 0 < this.messageListCheckedOrSelected().length;
+ }, this);
+
+ this.isSpamFolder = ko.computed(function () {
+ return FolderStore.spamFolder() === this.messageListEndFolder() &&
+ '' !== FolderStore.spamFolder();
+ }, this);
+
+ this.isSpamDisabled = ko.computed(function () {
+ return Consts.UNUSED_OPTION_VALUE === FolderStore.spamFolder();
+ }, this);
+
+ this.isTrashFolder = ko.computed(function () {
+ return FolderStore.trashFolder() === this.messageListEndFolder() &&
+ '' !== FolderStore.trashFolder();
+ }, this);
+
+ this.isDraftFolder = ko.computed(function () {
+ return FolderStore.draftFolder() === this.messageListEndFolder() &&
+ '' !== FolderStore.draftFolder();
+ }, this);
+
+ this.isSentFolder = ko.computed(function () {
+ return FolderStore.sentFolder() === this.messageListEndFolder() &&
+ '' !== FolderStore.sentFolder();
+ }, this);
+
+ this.isArchiveFolder = ko.computed(function () {
+ return FolderStore.archiveFolder() === this.messageListEndFolder() &&
+ '' !== FolderStore.archiveFolder();
+ }, this);
+
+ this.isArchiveDisabled = ko.computed(function () {
+ return Consts.UNUSED_OPTION_VALUE === FolderStore.archiveFolder();
+ }, this);
+
+ this.isArchiveVisible = ko.computed(function () {
+ return !this.isArchiveFolder() && !this.isArchiveDisabled() && !this.isDraftFolder();
+ }, this);
+
+ this.isSpamVisible = ko.computed(function () {
+ return !this.isSpamFolder() && !this.isSpamDisabled() && !this.isDraftFolder() && !this.isSentFolder();
+ }, this);
+
+ this.isUnSpamVisible = ko.computed(function () {
+ return this.isSpamFolder() && !this.isSpamDisabled() && !this.isDraftFolder() && !this.isSentFolder();
+ }, this);
+
+ this.messageListFocused = ko.computed(function () {
+ return Enums.Focused.MessageList === AppStore.focusedState();
+ });
+
+ this.canBeMoved = this.hasCheckedOrSelectedLines;
+
+ this.clearCommand = Utils.createCommand(this, function () {
+ if (Settings.capa(Enums.Capa.DangerousActions))
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/FolderClear */ 146), [FolderStore.currentFolder()]);
+ }
+ });
+
+ this.multyForwardCommand = Utils.createCommand(this, function () {
+ if (Settings.capa(Enums.Capa.Composer))
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/Compose */ 29), [
+ Enums.ComposeType.ForwardAsAttachment, MessageStore.messageListCheckedOrSelected()]);
+ }
+ }, this.canBeMoved);
+
+ this.deleteWithoutMoveCommand = Utils.createCommand(this, function () {
+ if (Settings.capa(Enums.Capa.DangerousActions))
+ {
+ __webpack_require__(/*! App/User */ 7).default.deleteMessagesFromFolder(Enums.FolderType.Trash,
+ FolderStore.currentFolderFullNameRaw(),
+ MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), false);
+ }
+ }, this.canBeMoved);
+
+ this.deleteCommand = Utils.createCommand(this, function () {
+ __webpack_require__(/*! App/User */ 7).default.deleteMessagesFromFolder(Enums.FolderType.Trash,
+ FolderStore.currentFolderFullNameRaw(),
+ MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), true);
+ }, this.canBeMoved);
+
+ this.archiveCommand = Utils.createCommand(this, function () {
+ __webpack_require__(/*! App/User */ 7).default.deleteMessagesFromFolder(Enums.FolderType.Archive,
+ FolderStore.currentFolderFullNameRaw(),
+ MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), true);
+ }, this.canBeMoved);
+
+ this.spamCommand = Utils.createCommand(this, function () {
+ __webpack_require__(/*! App/User */ 7).default.deleteMessagesFromFolder(Enums.FolderType.Spam,
+ FolderStore.currentFolderFullNameRaw(),
+ MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), true);
+ }, this.canBeMoved);
+
+ this.notSpamCommand = Utils.createCommand(this, function () {
+ __webpack_require__(/*! App/User */ 7).default.deleteMessagesFromFolder(Enums.FolderType.NotSpam,
+ FolderStore.currentFolderFullNameRaw(),
+ MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), true);
+ }, this.canBeMoved);
+
+ this.moveCommand = Utils.createCommand(this, Utils.emptyFunction, this.canBeMoved);
+
+ this.reloadCommand = Utils.createCommand(this, function () {
+ if (!MessageStore.messageListCompleteLoadingThrottleForAnimation() && this.allowReload)
+ {
+ __webpack_require__(/*! App/User */ 7).default.reloadMessageList(false, true);
+ }
+ });
+
+ this.quotaTooltip = _.bind(this.quotaTooltip, this);
+
+ this.selector = new Selector(this.messageList, this.selectorMessageSelected, this.selectorMessageFocused,
+ '.messageListItem .actionHandle', '.messageListItem.selected', '.messageListItem .checkboxMessage',
+ '.messageListItem.focused');
+
+ this.selector.on('onItemSelect', _.bind(function (oMessage) {
+ MessageStore.selectMessage(oMessage);
+ }, this));
+
+ this.selector.on('onItemGetUid', function (oMessage) {
+ return oMessage ? oMessage.generateUid() : '';
+ });
+
+ this.selector.on('onAutoSelect', _.bind(function () {
+ return this.useAutoSelect();
+ }, this));
+
+ this.selector.on('onUpUpOrDownDown', _.bind(function (bV) {
+ this.goToUpUpOrDownDown(bV);
+ }, this));
+
+ Events
+ .sub('mailbox.message-list.selector.go-down', function (bSelect) {
+ this.selector.goDown(bSelect);
+ }, this)
+ .sub('mailbox.message-list.selector.go-up', function (bSelect) {
+ this.selector.goUp(bSelect);
+ }, this)
+ ;
+
+ Events
+ .sub('mailbox.message.show', function (sFolder, sUid) {
+
+ var oMessage = _.find(this.messageList(), function (oItem) {
+ return oItem && sFolder === oItem.folderFullNameRaw && sUid === oItem.uid;
+ });
+
+ if ('INBOX' === sFolder)
+ {
+ kn.setHash(Links.mailBox(sFolder, 1));
+ }
+
+ if (oMessage)
+ {
+ this.selector.selectMessageItem(oMessage);
+ }
+ else
+ {
+ if ('INBOX' !== sFolder)
+ {
+ kn.setHash(Links.mailBox(sFolder, 1));
+ }
+
+ MessageStore.selectMessageByFolderAndUid(sFolder, sUid);
+ }
+
+ }, this)
+ ;
+
+ MessageStore.messageListEndHash.subscribe(function () {
+ this.selector.scrollToTop();
+ }, this);
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/User/MailBox/MessageList', 'View/App/MailBox/MessageList', 'MailBoxMessageListViewModel'], MessageListMailBoxUserView);
+ _.extend(MessageListMailBoxUserView.prototype, AbstractView.prototype);
+
+ /**
+ * @type {string}
+ */
+ MessageListMailBoxUserView.prototype.emptySubjectValue = '';
+
+ MessageListMailBoxUserView.prototype.iGoToUpUpOrDownDownTimeout = 0;
+
+ MessageListMailBoxUserView.prototype.hideLeft = function (oItem, oEvent)
+ {
+ oEvent.preventDefault();
+ oEvent.stopPropagation();
+
+ Globals.leftPanelDisabled(true);
+ };
+
+ MessageListMailBoxUserView.prototype.showLeft = function (oItem, oEvent)
+ {
+ oEvent.preventDefault();
+ oEvent.stopPropagation();
+
+ Globals.leftPanelDisabled(false);
+ };
+
+ MessageListMailBoxUserView.prototype.composeClick = function ()
+ {
+ if (Settings.capa(Enums.Capa.Composer))
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/Compose */ 29));
+ }
+ };
+
+ MessageListMailBoxUserView.prototype.goToUpUpOrDownDown = function (bUp)
+ {
+ var self = this;
+
+ if (0 < this.messageListChecked().length)
+ {
+ return false;
+ }
+
+ window.clearTimeout(this.iGoToUpUpOrDownDownTimeout);
+ this.iGoToUpUpOrDownDownTimeout = window.setTimeout(function () {
+
+ var
+ oPrev = null,
+ oNext = null,
+ oTemp = null,
+ oCurrent = null,
+ aPages = self.messageListPagenator()
+ ;
+
+ _.find(aPages, function (oItem) {
+
+ if (oItem)
+ {
+ if (oCurrent)
+ {
+ oNext = oItem;
+ }
+
+ if (oItem.current)
+ {
+ oCurrent = oItem;
+ oPrev = oTemp;
+ }
+
+ if (oNext)
+ {
+ return true;
+ }
+
+ oTemp = oItem;
+ }
+
+ return false;
+ });
+
+ if (Enums.Layout.NoPreview === SettingsStore.layout() && !self.message())
+ {
+ self.selector.iFocusedNextHelper = bUp ? -1 : 1;
+ }
+ else
+ {
+ self.selector.iSelectNextHelper = bUp ? -1 : 1;
+ }
+
+ if (bUp ? oPrev : oNext)
+ {
+ self.selector.unselect();
+ self.gotoPage(bUp ? oPrev : oNext);
+ }
+
+ }, 350);
+ };
+
+ MessageListMailBoxUserView.prototype.useAutoSelect = function ()
+ {
+ if (this.messageListDisableAutoSelect())
+ {
+ return false;
+ }
+
+ if (/is:unseen/.test(this.mainMessageListSearch()))
+ {
+ return false;
+ }
+
+ return Enums.Layout.NoPreview !== SettingsStore.layout();
+ };
+
+ MessageListMailBoxUserView.prototype.searchEnterAction = function ()
+ {
+ this.mainMessageListSearch(this.sLastSearchValue);
+ this.inputMessageListSearchFocus(false);
+ };
+
+ /**
+ * @return {string}
+ */
+ MessageListMailBoxUserView.prototype.printableMessageCountForDeletion = function ()
+ {
+ var iCnt = this.messageListCheckedOrSelectedUidsWithSubMails().length;
+ return 1 < iCnt ? ' (' + (100 > iCnt ? iCnt : '99+') + ')' : '';
+ };
+
+ MessageListMailBoxUserView.prototype.cancelSearch = function ()
+ {
+ this.mainMessageListSearch('');
+ this.inputMessageListSearchFocus(false);
+ };
+
+ MessageListMailBoxUserView.prototype.cancelThreadUid = function ()
+ {
+ kn.setHash(Links.mailBox(
+ FolderStore.currentFolderFullNameHash(),
+ MessageStore.messageListPageBeforeThread(),
+ MessageStore.messageListSearch()
+ ));
+ };
+
+ /**
+ * @param {string} sToFolderFullNameRaw
+ * @param {boolean} bCopy
+ * @return {boolean}
+ */
+ MessageListMailBoxUserView.prototype.moveSelectedMessagesToFolder = function (sToFolderFullNameRaw, bCopy)
+ {
+ if (this.canBeMoved())
+ {
+ __webpack_require__(/*! App/User */ 7).default.moveMessagesToFolder(
+ FolderStore.currentFolderFullNameRaw(),
+ MessageStore.messageListCheckedOrSelectedUidsWithSubMails(), sToFolderFullNameRaw, bCopy);
+ }
+
+ return false;
+ };
+
+ MessageListMailBoxUserView.prototype.dragAndDronHelper = function (oMessageListItem)
+ {
+ if (oMessageListItem)
+ {
+ oMessageListItem.checked(true);
+ }
+
+ var
+ oEl = Utils.draggablePlace(),
+ aUids = MessageStore.messageListCheckedOrSelectedUidsWithSubMails()
+ ;
+
+ oEl.data('rl-folder', FolderStore.currentFolderFullNameRaw());
+ oEl.data('rl-uids', aUids);
+ oEl.find('.text').text('' + aUids.length);
+
+ _.defer(function () {
+ var aUids = MessageStore.messageListCheckedOrSelectedUidsWithSubMails();
+
+ oEl.data('rl-uids', aUids);
+ oEl.find('.text').text('' + aUids.length);
+ });
+
+ return oEl;
+ };
+
+ /**
+ * @param {string} sFolderFullNameRaw
+ * @param {string|bool} sUid
+ * @param {number} iSetAction
+ * @param {Array=} aMessages = null
+ */
+ MessageListMailBoxUserView.prototype.setAction = function (sFolderFullNameRaw, mUid, iSetAction, aMessages)
+ {
+ __webpack_require__(/*! App/User */ 7).default.messageListAction(sFolderFullNameRaw, mUid, iSetAction, aMessages);
+ };
+
+ /**
+ * @param {string} sFolderFullNameRaw
+ * @param {number} iSetAction
+ */
+ MessageListMailBoxUserView.prototype.setActionForAll = function (sFolderFullNameRaw, iSetAction)
+ {
+ var
+ oFolder = null,
+ aMessages = MessageStore.messageList()
+ ;
+
+ if ('' !== sFolderFullNameRaw)
+ {
+ oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw);
+
+ if (oFolder)
+ {
+ switch (iSetAction) {
+ case Enums.MessageSetAction.SetSeen:
+ oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw);
+ if (oFolder)
+ {
+ _.each(aMessages, function (oMessage) {
+ oMessage.unseen(false);
+ });
+
+ oFolder.messageCountUnread(0);
+ Cache.clearMessageFlagsFromCacheByFolder(sFolderFullNameRaw);
+ }
+
+ Remote.messageSetSeenToAll(Utils.emptyFunction, sFolderFullNameRaw, true);
+ break;
+ case Enums.MessageSetAction.UnsetSeen:
+ oFolder = Cache.getFolderFromCacheList(sFolderFullNameRaw);
+ if (oFolder)
+ {
+ _.each(aMessages, function (oMessage) {
+ oMessage.unseen(true);
+ });
+
+ oFolder.messageCountUnread(oFolder.messageCountAll());
+ Cache.clearMessageFlagsFromCacheByFolder(sFolderFullNameRaw);
+ }
+ Remote.messageSetSeenToAll(Utils.emptyFunction, sFolderFullNameRaw, false);
+ break;
+ }
+
+ __webpack_require__(/*! App/User */ 7).default.reloadFlagsCurrentMessageListAndMessageFromCache();
+ }
+ }
+ };
+
+ MessageListMailBoxUserView.prototype.listSetSeen = function ()
+ {
+ this.setAction(FolderStore.currentFolderFullNameRaw(), true,
+ Enums.MessageSetAction.SetSeen, MessageStore.messageListCheckedOrSelected());
+ };
+
+ MessageListMailBoxUserView.prototype.listSetAllSeen = function ()
+ {
+ this.setActionForAll(FolderStore.currentFolderFullNameRaw(), Enums.MessageSetAction.SetSeen);
+ };
+
+ MessageListMailBoxUserView.prototype.listUnsetSeen = function ()
+ {
+ this.setAction(FolderStore.currentFolderFullNameRaw(), true,
+ Enums.MessageSetAction.UnsetSeen, MessageStore.messageListCheckedOrSelected());
+ };
+
+ MessageListMailBoxUserView.prototype.listSetFlags = function ()
+ {
+ this.setAction(FolderStore.currentFolderFullNameRaw(), true,
+ Enums.MessageSetAction.SetFlag, MessageStore.messageListCheckedOrSelected());
+ };
+
+ MessageListMailBoxUserView.prototype.listUnsetFlags = function ()
+ {
+ this.setAction(FolderStore.currentFolderFullNameRaw(), true,
+ Enums.MessageSetAction.UnsetFlag, MessageStore.messageListCheckedOrSelected());
+ };
+
+ MessageListMailBoxUserView.prototype.flagMessages = function (oCurrentMessage)
+ {
+ var
+ aChecked = this.messageListCheckedOrSelected(),
+ aCheckedUids = []
+ ;
+
+ if (oCurrentMessage)
+ {
+ if (0 < aChecked.length)
+ {
+ aCheckedUids = _.map(aChecked, function (oMessage) {
+ return oMessage.uid;
+ });
+ }
+
+ if (0 < aCheckedUids.length && -1 < Utils.inArray(oCurrentMessage.uid, aCheckedUids))
+ {
+ this.setAction(oCurrentMessage.folderFullNameRaw, true, oCurrentMessage.flagged() ?
+ Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, aChecked);
+ }
+ else
+ {
+ this.setAction(oCurrentMessage.folderFullNameRaw, true, oCurrentMessage.flagged() ?
+ Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, [oCurrentMessage]);
+ }
+ }
+ };
+
+ MessageListMailBoxUserView.prototype.flagMessagesFast = function (bFlag)
+ {
+ var
+ aChecked = this.messageListCheckedOrSelected(),
+ aFlagged = []
+ ;
+
+ if (0 < aChecked.length)
+ {
+ aFlagged = _.filter(aChecked, function (oMessage) {
+ return oMessage.flagged();
+ });
+
+ if (Utils.isUnd(bFlag))
+ {
+ this.setAction(aChecked[0].folderFullNameRaw, true,
+ aChecked.length === aFlagged.length ? Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, aChecked);
+ }
+ else
+ {
+ this.setAction(aChecked[0].folderFullNameRaw, true,
+ !bFlag ? Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, aChecked);
+ }
+ }
+ };
+
+ MessageListMailBoxUserView.prototype.seenMessagesFast = function (bSeen)
+ {
+ var
+ aChecked = this.messageListCheckedOrSelected(),
+ aUnseen = []
+ ;
+
+ if (0 < aChecked.length)
+ {
+ aUnseen = _.filter(aChecked, function (oMessage) {
+ return oMessage.unseen();
+ });
+
+ if (Utils.isUnd(bSeen))
+ {
+ this.setAction(aChecked[0].folderFullNameRaw, true,
+ 0 < aUnseen.length ? Enums.MessageSetAction.SetSeen : Enums.MessageSetAction.UnsetSeen, aChecked);
+ }
+ else
+ {
+ this.setAction(aChecked[0].folderFullNameRaw, true,
+ bSeen ? Enums.MessageSetAction.SetSeen : Enums.MessageSetAction.UnsetSeen, aChecked);
+ }
+ }
+ };
+
+ MessageListMailBoxUserView.prototype.gotoPage = function (oPage)
+ {
+ if (oPage)
+ {
+ kn.setHash(Links.mailBox(
+ FolderStore.currentFolderFullNameHash(),
+ oPage.value,
+ MessageStore.messageListSearch(),
+ MessageStore.messageListThreadUid()
+ ));
+ }
+ };
+
+ MessageListMailBoxUserView.prototype.gotoThread = function (oMessage)
+ {
+ if (oMessage && 0 < oMessage.threadsLen())
+ {
+ MessageStore.messageListPageBeforeThread(MessageStore.messageListPage());
+
+ kn.setHash(Links.mailBox(
+ FolderStore.currentFolderFullNameHash(),
+ 1,
+ MessageStore.messageListSearch(),
+ oMessage.uid
+ ));
+ }
+ };
+
+ MessageListMailBoxUserView.prototype.clearListIsVisible = function ()
+ {
+ return '' === this.messageListSearchDesc() && '' === this.messageListError() &&
+ '' === MessageStore.messageListEndThreadUid() &&
+ 0 < this.messageList().length && (this.isSpamFolder() || this.isTrashFolder());
+ };
+
+ MessageListMailBoxUserView.prototype.onBuild = function (oDom)
+ {
+ var self = this;
+
+ this.oContentVisible = $('.b-content', oDom);
+ this.oContentScrollable = $('.content', this.oContentVisible);
+
+ this.selector.init(this.oContentVisible, this.oContentScrollable, Enums.KeyState.MessageList);
+
+ if (this.mobile)
+ {
+ oDom
+ .on('click', function () {
+ Globals.leftPanelDisabled(true);
+ })
+ ;
+ }
+
+ oDom
+ .on('click', '.messageList .b-message-list-wrapper', function () {
+ if (Enums.Focused.MessageView === AppStore.focusedState())
+ {
+ AppStore.focusedState(Enums.Focused.MessageList);
+ }
+ })
+ .on('click', '.e-pagenator .e-page', function () {
+ self.gotoPage(ko.dataFor(this));
+ })
+ .on('click', '.messageList .checkboxCkeckAll', function () {
+ self.checkAll(!self.checkAll());
+ })
+ .on('click', '.messageList .messageListItem .flagParent', function () {
+ self.flagMessages(ko.dataFor(this));
+ })
+ .on('click', '.messageList .messageListItem .threads-len', function () {
+ self.gotoThread(ko.dataFor(this));
+ })
+ .on('dblclick', '.messageList .messageListItem .actionHandle', function () {
+ self.gotoThread(ko.dataFor(this));
+ })
+ ;
+
+ this.initUploaderForAppend();
+ this.initShortcuts();
+
+ if (!Globals.bMobileDevice && ifvisible && Settings.capa(Enums.Capa.Prefetch))
+ {
+ ifvisible.setIdleDuration(10);
+
+ ifvisible.idle(function () {
+ self.prefetchNextTick();
+ });
+ }
+ };
+
+ MessageListMailBoxUserView.prototype.initShortcuts = function ()
+ {
+ var self = this;
+
+ // disable print
+ key('ctrl+p, command+p', Enums.KeyState.MessageList, function () {
+ return false;
+ });
+
+ key('enter', Enums.KeyState.MessageList, function () {
+ if (self.message() && self.useAutoSelect())
+ {
+ Events.pub('mailbox.message-view.toggle-full-screen');
+ return false;
+ }
+ });
+
+ if (Settings.capa(Enums.Capa.MessageListActions))
+ {
+ // archive (zip)
+ key('z', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ self.archiveCommand();
+ return false;
+ });
+
+ // delete
+ key('delete, shift+delete, shift+3', Enums.KeyState.MessageList, function (event, handler) {
+ if (event)
+ {
+ if (0 < MessageStore.messageListCheckedOrSelected().length)
+ {
+ if (handler && 'shift+delete' === handler.shortcut)
+ {
+ self.deleteWithoutMoveCommand();
+ }
+ else
+ {
+ self.deleteCommand();
+ }
+ }
+
+ return false;
+ }
+ });
+ }
+
+ if (Settings.capa(Enums.Capa.Reload))
+ {
+ // check mail
+ key('ctrl+r, command+r', [Enums.KeyState.FolderList, Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ self.reloadCommand();
+ return false;
+ });
+ }
+
+ // check all
+ key('ctrl+a, command+a', Enums.KeyState.MessageList, function () {
+ self.checkAll(!(self.checkAll() && !self.isIncompleteChecked()));
+ return false;
+ });
+
+ if (Settings.capa(Enums.Capa.Composer))
+ {
+ // write/compose (open compose popup)
+ key('w,c', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/Compose */ 29));
+ return false;
+ });
+ }
+
+ if (Settings.capa(Enums.Capa.MessageListActions))
+ {
+ // important - star/flag messages
+ key('i', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ self.flagMessagesFast();
+ return false;
+ });
+ }
+
+ key('t', [Enums.KeyState.MessageList], function () {
+
+ var oMessage = self.selectorMessageSelected();
+ if (!oMessage)
+ {
+ oMessage = self.selectorMessageFocused();
+ }
+
+ if (oMessage && 0 < oMessage.threadsLen())
+ {
+ self.gotoThread(oMessage);
+ }
+
+ return false;
+ });
+
+ if (Settings.capa(Enums.Capa.MessageListActions))
+ {
+ // move
+ key('m', Enums.KeyState.MessageList, function () {
+ self.moveDropdownTrigger(true);
+ return false;
+ });
+ }
+
+ if (Settings.capa(Enums.Capa.MessageListActions))
+ {
+ // read
+ key('q', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ self.seenMessagesFast(true);
+ return false;
+ });
+
+ // unread
+ key('u', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ self.seenMessagesFast(false);
+ return false;
+ });
+ }
+
+ if (Settings.capa(Enums.Capa.Composer))
+ {
+ key('shift+f', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ self.multyForwardCommand();
+ return false;
+ });
+ }
+
+ if (Settings.capa(Enums.Capa.Search))
+ {
+ // search input focus
+ key('/', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ self.inputMessageListSearchFocus(true);
+ return false;
+ });
+ }
+
+ // cancel search
+ key('esc', Enums.KeyState.MessageList, function () {
+ if ('' !== self.messageListSearchDesc())
+ {
+ self.cancelSearch();
+ return false;
+ }
+ else if ('' !== self.messageListEndThreadUid())
+ {
+ self.cancelThreadUid();
+ return false;
+ }
+ });
+
+ // change focused state
+ key('tab, shift+tab, left, right', Enums.KeyState.MessageList, function (event, handler) {
+ if (event && handler && ('shift+tab' === handler.shortcut || 'left' === handler.shortcut))
+ {
+ AppStore.focusedState(Enums.Focused.FolderList);
+ }
+ else if (self.message())
+ {
+ AppStore.focusedState(Enums.Focused.MessageView);
+ }
+
+ return false;
+ });
+
+ key('ctrl+left, command+left', Enums.KeyState.MessageView, function () {
+ return false;
+ });
+
+ key('ctrl+right, command+right', Enums.KeyState.MessageView, function () {
+ return false;
+ });
+ };
+
+ MessageListMailBoxUserView.prototype.prefetchNextTick = function ()
+ {
+ if (ifvisible && !this.bPrefetch && !ifvisible.now() && this.viewModelVisibility())
+ {
+ var
+ self = this,
+ oMessage = _.find(this.messageList(), function (oMessage) {
+ return oMessage &&
+ !Cache.hasRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid);
+ })
+ ;
+
+ if (oMessage)
+ {
+ this.bPrefetch = true;
+
+ Cache.addRequestedMessage(oMessage.folderFullNameRaw, oMessage.uid);
+
+ Remote.message(function (sResult, oData) {
+
+ var bNext = !!(Enums.StorageResultType.Success === sResult && oData && oData.Result);
+
+ _.delay(function () {
+ self.bPrefetch = false;
+ if (bNext)
+ {
+ self.prefetchNextTick();
+ }
+ }, 1000);
+
+ }, oMessage.folderFullNameRaw, oMessage.uid);
+ }
+ }
+ };
+
+ MessageListMailBoxUserView.prototype.composeClick = function ()
+ {
+ if (Settings.capa(Enums.Capa.Composer))
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/Compose */ 29));
+ }
+ };
+
+ MessageListMailBoxUserView.prototype.advancedSearchClick = function ()
+ {
+ if (Settings.capa(Enums.Capa.SearchAdv))
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/AdvancedSearch */ 144));
+ }
+ };
+
+ MessageListMailBoxUserView.prototype.quotaTooltip = function ()
+ {
+ return Translator.i18n('MESSAGE_LIST/QUOTA_SIZE', {
+ 'SIZE': Utils.friendlySize(this.userUsageSize()),
+ 'PROC': this.userUsageProc(),
+ 'LIMIT': Utils.friendlySize(this.userQuota())
+ });
+ };
+
+ MessageListMailBoxUserView.prototype.initUploaderForAppend = function ()
+ {
+ if (!Settings.appSettingsGet('allowAppendMessage') || !this.dragOverArea())
+ {
+ return false;
+ }
+
+ var
+ oJua = new Jua({
+ 'action': Links.append(),
+ 'name': 'AppendFile',
+ 'queueSize': 1,
+ 'multipleSizeLimit': 1,
+ 'hidden': {
+ 'Folder': function () {
+ return FolderStore.currentFolderFullNameRaw();
+ }
+ },
+ 'dragAndDropElement': this.dragOverArea(),
+ 'dragAndDropBodyElement': this.dragOverBodyArea()
+ })
+ ;
+
+ this.dragOver.subscribe(function (bValue) {
+ if (bValue)
+ {
+ this.selector.scrollToTop();
+ }
+ }, this);
+
+ oJua
+ .on('onDragEnter', _.bind(function () {
+ this.dragOverEnter(true);
+ }, this))
+ .on('onDragLeave', _.bind(function () {
+ this.dragOverEnter(false);
+ }, this))
+ .on('onBodyDragEnter', _.bind(function () {
+ this.dragOver(true);
+ }, this))
+ .on('onBodyDragLeave', _.bind(function () {
+ this.dragOver(false);
+ }, this))
+ .on('onSelect', _.bind(function (sUid, oData) {
+
+ if (sUid && oData && 'message/rfc822' === oData['Type'])
+ {
+ MessageStore.messageListLoading(true);
+ return true;
+ }
+
+ return false;
+
+ }, this))
+ .on('onComplete', _.bind(function () {
+ __webpack_require__(/*! App/User */ 7).default.reloadMessageList(true, true);
+ }, this))
+ ;
+
+ return !!oJua;
+ };
+
+ module.exports = MessageListMailBoxUserView;
+
+ }());
+
+
+/***/ },
+/* 156 */
+/*!**********************************************!*\
+ !*** ./dev/View/User/MailBox/MessageView.js ***!
+ \**********************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ window = __webpack_require__(/*! window */ 11),
+ _ = __webpack_require__(/*! _ */ 3),
+ $ = __webpack_require__(/*! $ */ 14),
+ ko = __webpack_require__(/*! ko */ 2),
+ key = __webpack_require__(/*! key */ 18),
+
+ Consts = __webpack_require__(/*! Common/Consts */ 17),
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Utils = __webpack_require__(/*! Common/Utils */ 1),
+ Events = __webpack_require__(/*! Common/Events */ 25),
+ Translator = __webpack_require__(/*! Common/Translator */ 6),
+ Audio = __webpack_require__(/*! Common/Audio */ 65),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+
+ Cache = __webpack_require__(/*! Common/Cache */ 19),
+
+ SocialStore = __webpack_require__(/*! Stores/Social */ 34),
+ AppStore = __webpack_require__(/*! Stores/User/App */ 24),
+ SettingsStore = __webpack_require__(/*! Stores/User/Settings */ 28),
+ AccountStore = __webpack_require__(/*! Stores/User/Account */ 31),
+ FolderStore = __webpack_require__(/*! Stores/User/Folder */ 21),
+ MessageStore = __webpack_require__(/*! Stores/User/Message */ 32),
+
+ Local = __webpack_require__(/*! Storage/Client */ 47),
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+ Remote = __webpack_require__(/*! Remote/User/Ajax */ 15),
+
+ Promises = __webpack_require__(/*! Promises/User/Ajax */ 41),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function MessageViewMailBoxUserView()
+ {
+ AbstractView.call(this, 'Right', 'MailMessageView');
+
+ var
+ self = this,
+ sLastEmail = '',
+ createCommandHelper = function (sType) {
+ return Utils.createCommand(self, function () {
+ this.lastReplyAction(sType);
+ this.replyOrforward(sType);
+ }, self.canBeRepliedOrForwarded);
+ }
+ ;
+
+ this.oDom = null;
+ this.oHeaderDom = null;
+ this.oMessageScrollerDom = null;
+
+ this.bodyBackgroundColor = ko.observable('');
+
+ this.pswp = null;
+
+ this.allowComposer = !!Settings.capa(Enums.Capa.Composer);
+ this.allowMessageActions = !!Settings.capa(Enums.Capa.MessageActions);
+ this.allowMessageListActions = !!Settings.capa(Enums.Capa.MessageListActions);
+
+ this.logoImg = Utils.trim(Settings.settingsGet('UserLogoMessage'));
+ this.logoIframe = Utils.trim(Settings.settingsGet('UserIframeMessage'));
+
+ this.mobile = !!Settings.appSettingsGet('mobile');
+
+ this.attachmentsActions = AppStore.attachmentsActions;
+
+ this.message = MessageStore.message;
+ this.messageListChecked = MessageStore.messageListChecked;
+ this.hasCheckedMessages = MessageStore.hasCheckedMessages;
+ this.messageListCheckedOrSelectedUidsWithSubMails = MessageStore.messageListCheckedOrSelectedUidsWithSubMails;
+ this.messageLoadingThrottle = MessageStore.messageLoadingThrottle;
+ this.messagesBodiesDom = MessageStore.messagesBodiesDom;
+ this.useThreads = SettingsStore.useThreads;
+ this.replySameFolder = SettingsStore.replySameFolder;
+ this.layout = SettingsStore.layout;
+ this.usePreviewPane = SettingsStore.usePreviewPane;
+ this.isMessageSelected = MessageStore.isMessageSelected;
+ this.messageActiveDom = MessageStore.messageActiveDom;
+ this.messageError = MessageStore.messageError;
+
+ this.fullScreenMode = MessageStore.messageFullScreenMode;
+
+ this.messageListOfThreadsLoading = ko.observable(false).extend({'rateLimit': 1});
+
+ this.highlightUnselectedAttachments = ko.observable(false).extend({'falseTimeout': 2000});
+
+ this.showAttachmnetControls = ko.observable(false);
+
+ this.allowAttachmnetControls = ko.computed(function () {
+ return 0 < this.attachmentsActions().length &&
+ Settings.capa(Enums.Capa.AttachmentsActions);
+ }, this);
+
+ this.downloadAsZipAllowed = ko.computed(function () {
+ return -1 < Utils.inArray('zip', this.attachmentsActions()) &&
+ this.allowAttachmnetControls();
+ }, this);
+
+ this.downloadAsZipLoading = ko.observable(false);
+ this.downloadAsZipError = ko.observable(false).extend({'falseTimeout': 7000});
+
+ this.saveToOwnCloudAllowed = ko.computed(function () {
+ return -1 < Utils.inArray('owncloud', this.attachmentsActions()) &&
+ this.allowAttachmnetControls();
+ }, this);
+
+ this.saveToOwnCloudLoading = ko.observable(false);
+ this.saveToOwnCloudSuccess = ko.observable(false).extend({'falseTimeout': 2000});
+ this.saveToOwnCloudError = ko.observable(false).extend({'falseTimeout': 7000});
+
+ this.saveToOwnCloudSuccess.subscribe(function (bV) {
+ if (bV)
+ {
+ this.saveToOwnCloudError(false);
+ }
+ }, this);
+
+ this.saveToOwnCloudError.subscribe(function (bV) {
+ if (bV)
+ {
+ this.saveToOwnCloudSuccess(false);
+ }
+ }, this);
+
+ this.saveToDropboxAllowed = ko.computed(function () {
+ return -1 < Utils.inArray('dropbox', this.attachmentsActions()) &&
+ this.allowAttachmnetControls();
+ }, this);
+
+ this.saveToDropboxLoading = ko.observable(false);
+ this.saveToDropboxSuccess = ko.observable(false).extend({'falseTimeout': 2000});
+ this.saveToDropboxError = ko.observable(false).extend({'falseTimeout': 7000});
+
+ this.saveToDropboxSuccess.subscribe(function (bV) {
+ if (bV)
+ {
+ this.saveToDropboxError(false);
+ }
+ }, this);
+
+ this.saveToDropboxError.subscribe(function (bV) {
+ if (bV)
+ {
+ this.saveToDropboxSuccess(false);
+ }
+ }, this);
+
+ this.showAttachmnetControls.subscribe(function (bV) {
+ if (this.message())
+ {
+ _.each(this.message().attachments(), function (oItem) {
+ if (oItem)
+ {
+ oItem.checked(!!bV);
+ }
+ });
+ }
+ }, this);
+
+ this.lastReplyAction_ = ko.observable('');
+ this.lastReplyAction = ko.computed({
+ read: this.lastReplyAction_,
+ write: function (sValue) {
+ sValue = -1 === Utils.inArray(sValue, [
+ Enums.ComposeType.Reply, Enums.ComposeType.ReplyAll, Enums.ComposeType.Forward
+ ]) ? Enums.ComposeType.Reply : sValue;
+ this.lastReplyAction_(sValue);
+ },
+ owner: this
+ });
+
+ this.lastReplyAction(Local.get(Enums.ClientSideKeyName.LastReplyAction) || Enums.ComposeType.Reply);
+ this.lastReplyAction_.subscribe(function (sValue) {
+ Local.set(Enums.ClientSideKeyName.LastReplyAction, sValue);
+ });
+
+ this.showFullInfo = ko.observable(false);
+ this.moreDropdownTrigger = ko.observable(false);
+ this.messageDomFocused = ko.observable(false).extend({'rateLimit': 0});
+
+ this.messageVisibility = ko.computed(function () {
+ return !this.messageLoadingThrottle() && !!this.message();
+ }, this);
+
+ this.message.subscribe(function (oMessage) {
+ if (!oMessage)
+ {
+ MessageStore.selectorMessageSelected(null);
+ }
+ }, this);
+
+ this.canBeRepliedOrForwarded = ko.computed(function () {
+ var bV = this.messageVisibility();
+ return !this.isDraftFolder() && bV;
+ }, this);
+
+ // commands
+ this.closeMessage = Utils.createCommand(this, function () {
+ MessageStore.message(null);
+ });
+
+ this.replyCommand = createCommandHelper(Enums.ComposeType.Reply);
+ this.replyAllCommand = createCommandHelper(Enums.ComposeType.ReplyAll);
+ this.forwardCommand = createCommandHelper(Enums.ComposeType.Forward);
+ this.forwardAsAttachmentCommand = createCommandHelper(Enums.ComposeType.ForwardAsAttachment);
+ this.editAsNewCommand = createCommandHelper(Enums.ComposeType.EditAsNew);
+
+ this.messageVisibilityCommand = Utils.createCommand(this, Utils.emptyFunction, this.messageVisibility);
+
+ this.messageEditCommand = Utils.createCommand(this, function () {
+ this.editMessage();
+ }, this.messageVisibility);
+
+ this.deleteCommand = Utils.createCommand(this, function () {
+ var oMessage = this.message();
+ if (oMessage && this.allowMessageListActions)
+ {
+ this.message(null);
+ __webpack_require__(/*! App/User */ 7).default.deleteMessagesFromFolder(Enums.FolderType.Trash,
+ oMessage.folderFullNameRaw, [oMessage.uid], true);
+ }
+ }, this.messageVisibility);
+
+ this.deleteWithoutMoveCommand = Utils.createCommand(this, function () {
+ var oMessage = this.message();
+ if (oMessage && this.allowMessageListActions)
+ {
+ this.message(null);
+ __webpack_require__(/*! App/User */ 7).default.deleteMessagesFromFolder(Enums.FolderType.Trash,
+ oMessage.folderFullNameRaw, [oMessage.uid], false);
+ }
+ }, this.messageVisibility);
+
+ this.archiveCommand = Utils.createCommand(this, function () {
+ var oMessage = this.message();
+ if (oMessage && this.allowMessageListActions)
+ {
+ this.message(null);
+ __webpack_require__(/*! App/User */ 7).default.deleteMessagesFromFolder(Enums.FolderType.Archive,
+ oMessage.folderFullNameRaw, [oMessage.uid], true);
+ }
+ }, this.messageVisibility);
+
+ this.spamCommand = Utils.createCommand(this, function () {
+ var oMessage = this.message();
+ if (oMessage && this.allowMessageListActions)
+ {
+ this.message(null);
+ __webpack_require__(/*! App/User */ 7).default.deleteMessagesFromFolder(Enums.FolderType.Spam,
+ oMessage.folderFullNameRaw, [oMessage.uid], true);
+ }
+ }, this.messageVisibility);
+
+ this.notSpamCommand = Utils.createCommand(this, function () {
+ var oMessage = this.message();
+ if (oMessage && this.allowMessageListActions)
+ {
+ this.message(null);
+ __webpack_require__(/*! App/User */ 7).default.deleteMessagesFromFolder(Enums.FolderType.NotSpam,
+ oMessage.folderFullNameRaw, [oMessage.uid], true);
+ }
+ }, this.messageVisibility);
+
+ this.dropboxEnabled = SocialStore.dropbox.enabled;
+ this.dropboxApiKey = SocialStore.dropbox.apiKey;
+
+ // viewer
+
+ this.viewBodyTopValue = ko.observable(0);
+
+ this.viewFolder = '';
+ this.viewUid = '';
+ this.viewHash = '';
+ this.viewSubject = ko.observable('');
+ this.viewFromShort = ko.observable('');
+ this.viewFromDkimData = ko.observable(['none', '']);
+ this.viewToShort = ko.observable('');
+ this.viewFrom = ko.observable('');
+ this.viewTo = ko.observable('');
+ this.viewCc = ko.observable('');
+ this.viewBcc = ko.observable('');
+ this.viewReplyTo = ko.observable('');
+ this.viewTimeStamp = ko.observable(0);
+ this.viewSize = ko.observable('');
+ this.viewLineAsCss = ko.observable('');
+ this.viewViewLink = ko.observable('');
+ this.viewDownloadLink = ko.observable('');
+ this.viewUserPic = ko.observable(Consts.DATA_IMAGE_USER_DOT_PIC);
+ this.viewUserPicVisible = ko.observable(false);
+ this.viewIsImportant = ko.observable(false);
+ this.viewIsFlagged = ko.observable(false);
+
+ this.viewFromDkimStatusIconClass = ko.computed(function () {
+
+ var sResult = 'icon-none iconcolor-display-none';
+ // var sResult = 'icon-warning-alt iconcolor-grey';
+ switch (this.viewFromDkimData()[0])
+ {
+ case 'none':
+ break;
+ case 'pass':
+ sResult = 'icon-ok iconcolor-green';
+ // sResult = 'icon-warning-alt iconcolor-green';
+ break;
+ default:
+ sResult = 'icon-warning-alt iconcolor-red';
+ break;
+ }
+
+ return sResult;
+
+ }, this);
+
+ this.viewFromDkimStatusTitle = ko.computed(function () {
+
+ var aStatus = this.viewFromDkimData();
+ if (Utils.isNonEmptyArray(aStatus))
+ {
+ if (aStatus[0] && aStatus[1])
+ {
+ return aStatus[1];
+ }
+ else if (aStatus[0])
+ {
+ return 'DKIM: ' + aStatus[0];
+ }
+ }
+
+ return '';
+
+ }, this);
+
+ this.messageActiveDom.subscribe(function (oDom) {
+ this.bodyBackgroundColor(oDom ? this.detectDomBackgroundColor(oDom): '');
+ }, this);
+
+ this.message.subscribe(function (oMessage) {
+
+ this.messageActiveDom(null);
+
+ if (oMessage)
+ {
+ this.showAttachmnetControls(false);
+
+ if (this.viewHash !== oMessage.hash)
+ {
+ this.scrollMessageToTop();
+ }
+
+ this.viewFolder = oMessage.folderFullNameRaw;
+ this.viewUid = oMessage.uid;
+ this.viewHash = oMessage.hash;
+ this.viewSubject(oMessage.subject());
+ this.viewFromShort(oMessage.fromToLine(true, true));
+ this.viewFromDkimData(oMessage.fromDkimData());
+ this.viewToShort(oMessage.toToLine(true, true));
+ this.viewFrom(oMessage.fromToLine(false));
+ this.viewTo(oMessage.toToLine(false));
+ this.viewCc(oMessage.ccToLine(false));
+ this.viewBcc(oMessage.bccToLine(false));
+ this.viewReplyTo(oMessage.replyToToLine(false));
+ this.viewTimeStamp(oMessage.dateTimeStampInUTC());
+ this.viewSize(oMessage.friendlySize());
+ this.viewLineAsCss(oMessage.lineAsCss());
+ this.viewViewLink(oMessage.viewLink());
+ this.viewDownloadLink(oMessage.downloadLink());
+ this.viewIsImportant(oMessage.isImportant());
+ this.viewIsFlagged(oMessage.flagged());
+
+ sLastEmail = oMessage.fromAsSingleEmail();
+ Cache.getUserPic(sLastEmail, function (sPic, sEmail) {
+ if (sPic !== self.viewUserPic() && sLastEmail === sEmail)
+ {
+ self.viewUserPicVisible(false);
+ self.viewUserPic(Consts.DATA_IMAGE_USER_DOT_PIC);
+ if ('' !== sPic)
+ {
+ self.viewUserPicVisible(true);
+ self.viewUserPic(sPic);
+ }
+ }
+ });
+ }
+ else
+ {
+ this.viewFolder = '';
+ this.viewUid = '';
+ this.viewHash = '';
+
+ this.scrollMessageToTop();
+ }
+
+ }, this);
+
+ this.message.viewTrigger.subscribe(function () {
+ var oMessage = this.message();
+ if (oMessage)
+ {
+ this.viewIsFlagged(oMessage.flagged());
+ }
+ else
+ {
+ this.viewIsFlagged(false);
+ }
+ }, this);
+
+ this.fullScreenMode.subscribe(function (bValue) {
+ Globals.$html.toggleClass('rl-message-fullscreen', bValue);
+ Utils.windowResize();
+ });
+
+ this.messageLoadingThrottle.subscribe(Utils.windowResizeCallback);
+
+ this.messageFocused = ko.computed(function () {
+ return Enums.Focused.MessageView === AppStore.focusedState();
+ });
+
+ this.messageListAndMessageViewLoading = ko.computed(function () {
+ return MessageStore.messageListCompleteLoadingThrottle() || MessageStore.messageLoadingThrottle();
+ });
+
+ this.goUpCommand = Utils.createCommand(this, function () {
+ Events.pub('mailbox.message-list.selector.go-up', [
+ Enums.Layout.NoPreview === this.layout() ? !!this.message() : true
+ ]);
+ }, function () {
+ return !this.messageListAndMessageViewLoading();
+ });
+
+ this.goDownCommand = Utils.createCommand(this, function () {
+ Events.pub('mailbox.message-list.selector.go-down', [
+ Enums.Layout.NoPreview === this.layout() ? !!this.message() : true
+ ]);
+ }, function () {
+ return !this.messageListAndMessageViewLoading();
+ });
+
+ Events.sub('mailbox.message-view.toggle-full-screen', function () {
+ this.toggleFullScreen();
+ }, this);
+
+ this.attachmentPreview = _.bind(this.attachmentPreview, this);
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/User/MailBox/MessageView', 'View/App/MailBox/MessageView', 'MailBoxMessageViewViewModel'], MessageViewMailBoxUserView);
+ _.extend(MessageViewMailBoxUserView.prototype, AbstractView.prototype);
+
+ MessageViewMailBoxUserView.prototype.detectDomBackgroundColor = function (oDom)
+ {
+ var
+ iLimit = 5,
+ sResult = '',
+ aC = null,
+ fFindDom = function (oDom) {
+ var aC = oDom ? oDom.children() : null;
+ return (aC && 1 === aC.length && aC.is('table,div,center')) ? aC : null;
+ },
+ fFindColor = function (oDom) {
+ var sResult = '';
+ if (oDom)
+ {
+ sResult = oDom.css('background-color') || '';
+ if (!oDom.is('table'))
+ {
+ sResult = 'rgba(0, 0, 0, 0)' === sResult || 'transparent' === sResult ? '' : sResult;
+ }
+ }
+
+ return sResult;
+ }
+ ;
+
+ if (oDom && 1 === oDom.length)
+ {
+ aC = oDom;
+ while ('' === sResult)
+ {
+ iLimit--;
+ if (0 >= iLimit)
+ {
+ break;
+ }
+
+ aC = fFindDom(aC);
+ if (aC)
+ {
+ sResult = fFindColor(aC);
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ sResult = 'rgba(0, 0, 0, 0)' === sResult || 'transparent' === sResult ? '' : sResult;
+ }
+
+ return sResult;
+ };
+
+ MessageViewMailBoxUserView.prototype.fullScreen = function ()
+ {
+ this.fullScreenMode(true);
+ Utils.windowResize();
+ };
+
+ MessageViewMailBoxUserView.prototype.unFullScreen = function ()
+ {
+ this.fullScreenMode(false);
+ Utils.windowResize();
+ };
+
+ MessageViewMailBoxUserView.prototype.toggleFullScreen = function ()
+ {
+ Utils.removeSelection();
+
+ this.fullScreenMode(!this.fullScreenMode());
+ Utils.windowResize();
+ };
+
+ /**
+ * @param {string} sType
+ */
+ MessageViewMailBoxUserView.prototype.replyOrforward = function (sType)
+ {
+ if (Settings.capa(Enums.Capa.Composer))
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/Compose */ 29), [sType, MessageStore.message()]);
+ }
+ };
+
+ MessageViewMailBoxUserView.prototype.checkHeaderHeight = function ()
+ {
+ if (this.oHeaderDom)
+ {
+ this.viewBodyTopValue(this.message() ? this.oHeaderDom.height() +
+ 20 /* padding-(top/bottom): 20px */ + 1 /* borded-bottom: 1px */ : 0);
+ }
+ };
+
+ /**
+ * @todo
+ * @param {string} sEmail
+ */
+ // MessageViewMailBoxUserView.prototype.displayMailToPopup = function (sMailToUrl)
+ // {
+ // sMailToUrl = sMailToUrl.replace(/\?.+$/, '');
+ //
+ // var
+ // sResult = '',
+ // aTo = [],
+ // EmailModel = require('Model/Email'),
+ // fParseEmailLine = function (sLine) {
+ // return sLine ? _.compact(_.map([window.decodeURIComponent(sLine)], function (sItem) {
+ // var oEmailModel = new EmailModel();
+ // oEmailModel.mailsoParse(sItem);
+ // return '' !== oEmailModel.email ? oEmailModel : null;
+ // })) : null;
+ // }
+ // ;
+ //
+ // aTo = fParseEmailLine(sMailToUrl);
+ // sResult = aTo && aTo[0] ? aTo[0].email : '';
+ //
+ // return sResult;
+ // };
+
+ /**
+ * @param {Object} oAttachment
+ * @returns {boolean}
+ */
+ MessageViewMailBoxUserView.prototype.attachmentPreview = function (oAttachment)
+ {
+ if (oAttachment && oAttachment.isImage() && !oAttachment.isLinked && this.message() && this.message().attachments())
+ {
+ var
+ oDiv = $(''),
+ iIndex = 0,
+ iListIndex = 0,
+ aDynamicEl = _.compact(_.map(this.message().attachments(), function (oItem) {
+ if (oItem && !oItem.isLinked && oItem.isImage())
+ {
+ if (oItem === oAttachment)
+ {
+ iIndex = iListIndex;
+ }
+
+ iListIndex++;
+
+ return {
+ 'src': oItem.linkPreview(),
+ 'thumb': oItem.linkThumbnail(),
+ 'subHtml': oItem.fileName,
+ 'downloadUrl': oItem.linkPreview()
+ };
+ }
+
+ return null;
+ }))
+ ;
+
+ if (0 < aDynamicEl.length)
+ {
+ oDiv.on('onBeforeOpen.lg', function () {
+ Globals.useKeyboardShortcuts(false);
+ Utils.removeInFocus(true);
+ });
+
+ oDiv.on('onCloseAfter.lg', function () {
+ Globals.useKeyboardShortcuts(true);
+ });
+
+ oDiv.lightGallery({
+ dynamic: true,
+ loadYoutubeThumbnail: false,
+ loadVimeoThumbnail: false,
+ thumbWidth: 80,
+ thumbContHeight: 95,
+ showThumbByDefault: false,
+ mode: 'lg-lollipop', // 'lg-slide',
+ index: iIndex,
+ dynamicEl: aDynamicEl
+ });
+ }
+
+ return false;
+ }
+
+ return true;
+ };
+
+ MessageViewMailBoxUserView.prototype.onBuild = function (oDom)
+ {
+ var
+ self = this,
+ oScript = null,
+ // sErrorMessage = Translator.i18n('PREVIEW_POPUP/IMAGE_ERROR'),
+ fCheckHeaderHeight = _.bind(this.checkHeaderHeight, this)
+ ;
+
+ this.oDom = oDom;
+
+ this.fullScreenMode.subscribe(function (bValue) {
+ if (bValue && self.message())
+ {
+ AppStore.focusedState(Enums.Focused.MessageView);
+ }
+ }, this);
+
+ this.showAttachmnetControls.subscribe(fCheckHeaderHeight);
+ this.fullScreenMode.subscribe(fCheckHeaderHeight);
+ this.showFullInfo.subscribe(fCheckHeaderHeight);
+ this.message.subscribe(fCheckHeaderHeight);
+
+ Events.sub('window.resize', _.throttle(function () {
+ _.delay(fCheckHeaderHeight, 1);
+ _.delay(fCheckHeaderHeight, 200);
+ _.delay(fCheckHeaderHeight, 500);
+ }, 50));
+
+ this.showFullInfo.subscribe(function () {
+ Utils.windowResize();
+ Utils.windowResize(250);
+ });
+
+ if (this.dropboxEnabled() && this.dropboxApiKey() && !window.Dropbox)
+ {
+ oScript = window.document.createElement('script');
+ oScript.type = 'text/javascript';
+ oScript.src = 'https://www.dropbox.com/static/api/2/dropins.js';
+ $(oScript).attr('id', 'dropboxjs').attr('data-app-key', self.dropboxApiKey());
+
+ window.document.body.appendChild(oScript);
+ }
+
+ this.oHeaderDom = $('.messageItemHeader', oDom);
+ this.oHeaderDom = this.oHeaderDom[0] ? this.oHeaderDom : null;
+
+ if (this.mobile)
+ {
+ oDom
+ .on('click', function () {
+ Globals.leftPanelDisabled(true);
+ })
+ ;
+ }
+
+ oDom
+ .on('click', 'a', function (oEvent) {
+ // setup maito protocol
+ return !(!!oEvent && 3 !== oEvent['which'] && Utils.mailToHelper($(this).attr('href'),
+ Settings.capa(Enums.Capa.Composer) ? __webpack_require__(/*! View/Popup/Compose */ 29) : null));
+ })
+ // .on('mouseover', 'a', _.debounce(function (oEvent) {
+ //
+ // if (oEvent)
+ // {
+ // var sMailToUrl = $(this).attr('href');
+ // if (sMailToUrl && 'mailto:' === sMailToUrl.toString().substr(0, 7).toLowerCase())
+ // {
+ // sMailToUrl = sMailToUrl.toString().substr(7);
+ // self.displayMailToPopup(sMailToUrl);
+ // }
+ // }
+ //
+ // return true;
+ //
+ // }, 1000))
+ .on('click', '.attachmentsPlace .attachmentIconParent', function (oEvent) {
+ if (oEvent && oEvent.stopPropagation)
+ {
+ oEvent.stopPropagation();
+ }
+ })
+ .on('click', '.attachmentsPlace .showPreplay', function (oEvent) {
+ if (oEvent && oEvent.stopPropagation)
+ {
+ oEvent.stopPropagation();
+ }
+
+ var oAttachment = ko.dataFor(this);
+ if (oAttachment && Audio.supported)
+ {
+ switch (true)
+ {
+ case Audio.supportedMp3 && oAttachment.isMp3():
+ Audio.playMp3(oAttachment.linkDownload(), oAttachment.fileName);
+ break;
+ case Audio.supportedOgg && oAttachment.isOgg():
+ Audio.playOgg(oAttachment.linkDownload(), oAttachment.fileName);
+ break;
+ case Audio.supportedWav && oAttachment.isWav():
+ Audio.playWav(oAttachment.linkDownload(), oAttachment.fileName);
+ break;
+ }
+ }
+ })
+ .on('click', '.attachmentsPlace .attachmentItem .attachmentNameParent', function () {
+
+ var
+ oAttachment = ko.dataFor(this)
+ ;
+
+ if (oAttachment && oAttachment.download)
+ {
+ __webpack_require__(/*! App/User */ 7).default.download(oAttachment.linkDownload());
+ }
+ })
+ .on('click', '.messageItemHeader .subjectParent .flagParent', function () {
+ var oMessage = self.message();
+ if (oMessage)
+ {
+ __webpack_require__(/*! App/User */ 7).default.messageListAction(oMessage.folderFullNameRaw, oMessage.uid,
+ oMessage.flagged() ? Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, [oMessage]);
+ }
+ })
+ .on('click', '.thread-list .flagParent', function () {
+ var oMessage = ko.dataFor(this);
+ if (oMessage && oMessage.folder && oMessage.uid)
+ {
+ __webpack_require__(/*! App/User */ 7).default.messageListAction(
+ oMessage.folder, oMessage.uid,
+ oMessage.flagged() ? Enums.MessageSetAction.UnsetFlag : Enums.MessageSetAction.SetFlag, [oMessage]);
+ }
+
+ self.threadsDropdownTrigger(true);
+
+ return false;
+ })
+ ;
+
+ AppStore.focusedState.subscribe(function (sValue) {
+ if (Enums.Focused.MessageView !== sValue)
+ {
+ this.scrollMessageToTop();
+ this.scrollMessageToLeft();
+ }
+ }, this);
+
+ Globals.keyScopeReal.subscribe(function (sValue) {
+ this.messageDomFocused(Enums.KeyState.MessageView === sValue && !Utils.inFocus());
+ }, this);
+
+ this.oMessageScrollerDom = oDom.find('.messageItem .content');
+ this.oMessageScrollerDom = this.oMessageScrollerDom && this.oMessageScrollerDom[0] ? this.oMessageScrollerDom : null;
+
+ this.initShortcuts();
+ };
+
+ /**
+ * @return {boolean}
+ */
+ MessageViewMailBoxUserView.prototype.escShortcuts = function ()
+ {
+ if (this.viewModelVisibility() && this.message())
+ {
+ if (this.fullScreenMode())
+ {
+ this.fullScreenMode(false);
+
+ if (Enums.Layout.NoPreview !== this.layout())
+ {
+ AppStore.focusedState(Enums.Focused.MessageList);
+ }
+ }
+ else if (Enums.Layout.NoPreview === this.layout())
+ {
+ this.message(null);
+ }
+ else
+ {
+ AppStore.focusedState(Enums.Focused.MessageList);
+ }
+
+ return false;
+ }
+ };
+
+ MessageViewMailBoxUserView.prototype.initShortcuts = function ()
+ {
+ var
+ self = this
+ ;
+
+ // exit fullscreen, back
+ key('esc, backspace', Enums.KeyState.MessageView, _.bind(this.escShortcuts, this));
+
+ // fullscreen
+ key('enter', Enums.KeyState.MessageView, function () {
+ self.toggleFullScreen();
+ return false;
+ });
+
+ // reply
+ key('r', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ if (MessageStore.message())
+ {
+ self.replyCommand();
+ return false;
+ }
+ });
+
+ // replaAll
+ key('a', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ if (MessageStore.message())
+ {
+ self.replyAllCommand();
+ return false;
+ }
+ });
+
+ // forward
+ key('f', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ if (MessageStore.message())
+ {
+ self.forwardCommand();
+ return false;
+ }
+ });
+
+ // message information
+ // key('i', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ // if (MessageStore.message())
+ // {
+ // self.showFullInfo(!self.showFullInfo());
+ // return false;
+ // }
+ // });
+
+ // toggle message blockquotes
+ key('b', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ if (MessageStore.message() && MessageStore.message().body)
+ {
+ MessageStore.message().body.find('.rlBlockquoteSwitcher').click();
+ return false;
+ }
+ });
+
+ key('ctrl+up, command+up, ctrl+left, command+left', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ self.goUpCommand();
+ return false;
+ });
+
+ key('ctrl+down, command+down, ctrl+right, command+right', [Enums.KeyState.MessageList, Enums.KeyState.MessageView], function () {
+ self.goDownCommand();
+ return false;
+ });
+
+ // print
+ key('ctrl+p, command+p', Enums.KeyState.MessageView, function () {
+ if (self.message())
+ {
+ self.message().printMessage();
+ }
+
+ return false;
+ });
+
+ // delete
+ key('delete, shift+delete', Enums.KeyState.MessageView, function (event, handler) {
+ if (event)
+ {
+ if (handler && 'shift+delete' === handler.shortcut)
+ {
+ self.deleteWithoutMoveCommand();
+ }
+ else
+ {
+ self.deleteCommand();
+ }
+
+ return false;
+ }
+ });
+
+ // change focused state
+ key('tab, shift+tab, left', Enums.KeyState.MessageView, function (event, handler) {
+ if (!self.fullScreenMode() && self.message() && Enums.Layout.NoPreview !== self.layout())
+ {
+ if (event && handler && 'left' === handler.shortcut)
+ {
+ if (self.oMessageScrollerDom && 0 < self.oMessageScrollerDom.scrollLeft())
+ {
+ return true;
+ }
+
+ AppStore.focusedState(Enums.Focused.MessageList);
+ }
+ else
+ {
+ AppStore.focusedState(Enums.Focused.MessageList);
+ }
+ }
+ else if (self.message() && Enums.Layout.NoPreview === self.layout() && event && handler && 'left' === handler.shortcut)
+ {
+ return true;
+ }
+
+ return false;
+ });
+ };
+
+ /**
+ * @return {boolean}
+ */
+ MessageViewMailBoxUserView.prototype.isDraftFolder = function ()
+ {
+ return MessageStore.message() && FolderStore.draftFolder() === MessageStore.message().folderFullNameRaw;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ MessageViewMailBoxUserView.prototype.isSentFolder = function ()
+ {
+ return MessageStore.message() && FolderStore.sentFolder() === MessageStore.message().folderFullNameRaw;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ MessageViewMailBoxUserView.prototype.isSpamFolder = function ()
+ {
+ return MessageStore.message() && FolderStore.spamFolder() === MessageStore.message().folderFullNameRaw;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ MessageViewMailBoxUserView.prototype.isSpamDisabled = function ()
+ {
+ return MessageStore.message() && FolderStore.spamFolder() === Consts.UNUSED_OPTION_VALUE;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ MessageViewMailBoxUserView.prototype.isArchiveFolder = function ()
+ {
+ return MessageStore.message() && FolderStore.archiveFolder() === MessageStore.message().folderFullNameRaw;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ MessageViewMailBoxUserView.prototype.isArchiveDisabled = function ()
+ {
+ return MessageStore.message() && FolderStore.archiveFolder() === Consts.UNUSED_OPTION_VALUE;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ MessageViewMailBoxUserView.prototype.isDraftOrSentFolder = function ()
+ {
+ return this.isDraftFolder() || this.isSentFolder();
+ };
+
+ MessageViewMailBoxUserView.prototype.composeClick = function ()
+ {
+ if (Settings.capa(Enums.Capa.Composer))
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/Compose */ 29));
+ }
+ };
+
+ MessageViewMailBoxUserView.prototype.editMessage = function ()
+ {
+ if (Settings.capa(Enums.Capa.Composer) && MessageStore.message())
+ {
+ kn.showScreenPopup(__webpack_require__(/*! View/Popup/Compose */ 29), [Enums.ComposeType.Draft, MessageStore.message()]);
+ }
+ };
+
+ MessageViewMailBoxUserView.prototype.scrollMessageToTop = function ()
+ {
+ if (this.oMessageScrollerDom)
+ {
+ if (50 < this.oMessageScrollerDom.scrollTop())
+ {
+ this.oMessageScrollerDom
+ .scrollTop(50)
+ .animate({'scrollTop': 0}, 200)
+ ;
+ }
+ else
+ {
+ this.oMessageScrollerDom.scrollTop(0);
+ }
+
+ Utils.windowResize();
+ }
+ };
+
+ MessageViewMailBoxUserView.prototype.scrollMessageToLeft = function ()
+ {
+ if (this.oMessageScrollerDom)
+ {
+ this.oMessageScrollerDom.scrollLeft(0);
+ Utils.windowResize();
+ }
+ };
+
+ MessageViewMailBoxUserView.prototype.getAttachmentsHashes = function ()
+ {
+ return _.compact(_.map(this.message() ? this.message().attachments() : [], function (oItem) {
+ return oItem && !oItem.isLinked && oItem.checked() ? oItem.download : '';
+ }));
+ };
+
+ MessageViewMailBoxUserView.prototype.downloadAsZip = function ()
+ {
+ var self = this, aHashes = this.getAttachmentsHashes();
+ if (0 < aHashes.length)
+ {
+ Promises.attachmentsActions('Zip', aHashes, this.downloadAsZipLoading).then(function (oResult) {
+ if (oResult && oResult.Result && oResult.Result.Files &&
+ oResult.Result.Files[0] && oResult.Result.Files[0].Hash)
+ {
+ __webpack_require__(/*! App/User */ 7).default.download(
+ Links.attachmentDownload(oResult.Result.Files[0].Hash));
+ }
+ else
+ {
+ self.downloadAsZipError(true);
+ }
+ }).fail(function () {
+ self.downloadAsZipError(true);
+ });
+ }
+ else
+ {
+ this.highlightUnselectedAttachments(true);
+ }
+ };
+
+ MessageViewMailBoxUserView.prototype.saveToOwnCloud = function ()
+ {
+ var self = this, aHashes = this.getAttachmentsHashes();
+ if (0 < aHashes.length)
+ {
+ Promises.attachmentsActions('OwnCloud', aHashes, this.saveToOwnCloudLoading).then(function (oResult) {
+ if (oResult && oResult.Result)
+ {
+ self.saveToOwnCloudSuccess(true);
+ }
+ else
+ {
+ self.saveToOwnCloudError(true);
+ }
+ }).fail(function () {
+ self.saveToOwnCloudError(true);
+ });
+ }
+ else
+ {
+ this.highlightUnselectedAttachments(true);
+ }
+ };
+
+ MessageViewMailBoxUserView.prototype.saveToDropbox = function ()
+ {
+ var self = this, aFiles = [], aHashes = this.getAttachmentsHashes();
+ if (0 < aHashes.length)
+ {
+ if (window.Dropbox)
+ {
+ Promises.attachmentsActions('Dropbox', aHashes, this.saveToDropboxLoading).then(function (oResult) {
+ if (oResult && oResult.Result && oResult.Result.Url && oResult.Result.ShortLife && oResult.Result.Files)
+ {
+ if (window.Dropbox && Utils.isArray(oResult.Result.Files))
+ {
+ _.each(oResult.Result.Files, function (oItem) {
+ aFiles.push({
+ 'url': oResult.Result.Url +
+ Links.attachmentDownload(oItem.Hash, oResult.Result.ShortLife),
+ 'filename': oItem.FileName
+ });
+ });
+
+ window.Dropbox.save({
+ 'files': aFiles,
+ 'progress': function () {
+ self.saveToDropboxLoading(true);
+ self.saveToDropboxError(false);
+ self.saveToDropboxSuccess(false);
+ },
+ 'cancel': function () {
+ self.saveToDropboxSuccess(false);
+ self.saveToDropboxError(false);
+ self.saveToDropboxLoading(false);
+ },
+ 'success': function () {
+ self.saveToDropboxSuccess(true);
+ self.saveToDropboxLoading(false);
+ },
+ 'error': function () {
+ self.saveToDropboxError(true);
+ self.saveToDropboxLoading(false);
+ }
+ });
+ }
+ else
+ {
+ self.saveToDropboxError(true);
+ }
+ }
+ }).fail(function () {
+ self.saveToDropboxError(true);
+ });
+ }
+ }
+ else
+ {
+ this.highlightUnselectedAttachments(true);
+ }
+ };
+
+ /**
+ * @param {MessageModel} oMessage
+ */
+ MessageViewMailBoxUserView.prototype.showImages = function (oMessage)
+ {
+ if (oMessage && oMessage.showExternalImages)
+ {
+ oMessage.showExternalImages(true);
+ }
+
+ this.checkHeaderHeight();
+ };
+
+ /**
+ * @return {string}
+ */
+ MessageViewMailBoxUserView.prototype.printableCheckedMessageCount = function ()
+ {
+ var iCnt = this.messageListCheckedOrSelectedUidsWithSubMails().length;
+ return 0 < iCnt ? (100 > iCnt ? iCnt : '99+') : '';
+ };
+
+ /**
+ * @param {MessageModel} oMessage
+ */
+ MessageViewMailBoxUserView.prototype.readReceipt = function (oMessage)
+ {
+ if (oMessage && '' !== oMessage.readReceipt())
+ {
+ Remote.sendReadReceiptMessage(Utils.emptyFunction, oMessage.folderFullNameRaw, oMessage.uid,
+ oMessage.readReceipt(),
+ Translator.i18n('READ_RECEIPT/SUBJECT', {'SUBJECT': oMessage.subject()}),
+ Translator.i18n('READ_RECEIPT/BODY', {'READ-RECEIPT': AccountStore.email()}));
+
+ oMessage.isReadReceipt(true);
+
+ Cache.storeMessageFlagsToCache(oMessage);
+
+ __webpack_require__(/*! App/User */ 7).default.reloadFlagsCurrentMessageListAndMessageFromCache();
+ }
+
+ this.checkHeaderHeight();
+ };
+
+ module.exports = MessageViewMailBoxUserView;
+
+ }());
+
+/***/ },
+/* 157 */
+/*!*************************************************!*\
+ !*** ./dev/View/User/MailBox/SystemDropDown.js ***!
+ \*************************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractSystemDropDownViewModel = __webpack_require__(/*! View/User/AbstractSystemDropDown */ 99)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractSystemDropDownViewModel
+ */
+ function SystemDropDownMailBoxUserView()
+ {
+ AbstractSystemDropDownViewModel.call(this);
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/User/MailBox/SystemDropDown', 'View/App/MailBox/SystemDropDown', 'MailBoxSystemDropDownViewModel'], SystemDropDownMailBoxUserView);
+ _.extend(SystemDropDownMailBoxUserView.prototype, AbstractSystemDropDownViewModel.prototype);
+
+ module.exports = SystemDropDownMailBoxUserView;
+
+ }());
+
+
+/***/ },
+/* 158 */
+/*!****************************************!*\
+ !*** ./dev/View/User/Settings/Menu.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+ key = __webpack_require__(/*! key */ 18),
+
+ Enums = __webpack_require__(/*! Common/Enums */ 4),
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+ Links = __webpack_require__(/*! Common/Links */ 12),
+
+ Cache = __webpack_require__(/*! Common/Cache */ 19),
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @param {?} oScreen
+ *
+ * @constructor
+ * @extends AbstractView
+ */
+ function MenuSettingsUserView(oScreen)
+ {
+ AbstractView.call(this, 'Left', 'SettingsMenu');
+
+ this.leftPanelDisabled = Globals.leftPanelDisabled;
+
+ this.mobile = Settings.appSettingsGet('mobile');
+
+ this.menu = oScreen.menu;
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/User/Settings/Menu', 'View/App/Settings/Menu', 'SettingsMenuViewModel'], MenuSettingsUserView);
+ _.extend(MenuSettingsUserView.prototype, AbstractView.prototype);
+
+ MenuSettingsUserView.prototype.onBuild = function (oDom)
+ {
+ // var self = this;
+ // key('esc', Enums.KeyState.Settings, function () {
+ // self.backToMailBoxClick();
+ // });
+
+ if (this.mobile)
+ {
+ oDom
+ .on('click', '.b-settings-menu .e-item.selectable', function () {
+ Globals.leftPanelDisabled(true);
+ })
+ ;
+ }
+
+ key('up, down', Enums.KeyState.Settings, _.throttle(function (event, handler) {
+
+ var
+ sH = '',
+ iIndex = -1,
+ bUp = handler && 'up' === handler.shortcut,
+ $items = $('.b-settings-menu .e-item', oDom)
+ ;
+
+ if (event && $items.length)
+ {
+ iIndex = $items.index($items.filter('.selected'));
+ if (bUp && iIndex > 0)
+ {
+ iIndex--;
+ }
+ else if (!bUp && iIndex < $items.length - 1)
+ {
+ iIndex++;
+ }
+
+ sH = $items.eq(iIndex).attr('href');
+ if (sH)
+ {
+ kn.setHash(sH, false, true);
+ }
+ }
+
+ }, 200));
+ };
+
+ MenuSettingsUserView.prototype.link = function (sRoute)
+ {
+ return Links.settings(sRoute);
+ };
+
+ MenuSettingsUserView.prototype.backToMailBoxClick = function ()
+ {
+ kn.setHash(Links.inbox(Cache.getFolderInboxName()));
+ };
+
+ module.exports = MenuSettingsUserView;
+
+ }());
+
+/***/ },
+/* 159 */
+/*!****************************************!*\
+ !*** ./dev/View/User/Settings/Pane.js ***!
+ \****************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ Globals = __webpack_require__(/*! Common/Globals */ 8),
+
+ Settings = __webpack_require__(/*! Storage/Settings */ 9),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractView = __webpack_require__(/*! Knoin/AbstractView */ 10)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractView
+ */
+ function PaneSettingsUserView()
+ {
+ AbstractView.call(this, 'Right', 'SettingsPane');
+
+ this.mobile = Settings.appSettingsGet('mobile');
+
+ this.leftPanelDisabled = Globals.leftPanelDisabled;
+
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/User/Settings/Pane', 'View/App/Settings/Pane', 'SettingsPaneViewModel'], PaneSettingsUserView);
+ _.extend(PaneSettingsUserView.prototype, AbstractView.prototype);
+
+ PaneSettingsUserView.prototype.onShow = function ()
+ {
+ __webpack_require__(/*! Stores/User/Message */ 32).message(null);
+ };
+
+ PaneSettingsUserView.prototype.hideLeft = function (oItem, oEvent)
+ {
+ oEvent.preventDefault();
+ oEvent.stopPropagation();
+
+ Globals.leftPanelDisabled(true);
+ };
+
+ PaneSettingsUserView.prototype.showLeft = function (oItem, oEvent)
+ {
+ oEvent.preventDefault();
+ oEvent.stopPropagation();
+
+ Globals.leftPanelDisabled(false);
+ };
+
+ PaneSettingsUserView.prototype.onBuild = function (oDom)
+ {
+ if (this.mobile)
+ {
+ oDom
+ .on('click', function () {
+ Globals.leftPanelDisabled(true);
+ })
+ ;
+ }
+ };
+
+ PaneSettingsUserView.prototype.backToMailBoxClick = function ()
+ {
+ kn.setHash(__webpack_require__(/*! Common/Links */ 12).inbox(
+ __webpack_require__(/*! Common/Cache */ 19).getFolderInboxName()));
+ };
+
+ module.exports = PaneSettingsUserView;
+
+ }());
+
+/***/ },
+/* 160 */
+/*!**************************************************!*\
+ !*** ./dev/View/User/Settings/SystemDropDown.js ***!
+ \**************************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+
+ (function () {
+
+ 'use strict';
+
+ var
+ _ = __webpack_require__(/*! _ */ 3),
+
+ kn = __webpack_require__(/*! Knoin/Knoin */ 5),
+ AbstractSystemDropDownUserView = __webpack_require__(/*! View/User/AbstractSystemDropDown */ 99)
+ ;
+
+ /**
+ * @constructor
+ * @extends AbstractSystemDropDownUserView
+ */
+ function SystemDropDownSettingsUserView()
+ {
+ AbstractSystemDropDownUserView.call(this);
+ kn.constructorEnd(this);
+ }
+
+ kn.extendAsViewModel(['View/User/Settings/SystemDropDown', 'View/App/Settings/SystemDropDown', 'SettingsSystemDropDownViewModel'], SystemDropDownSettingsUserView);
+ _.extend(SystemDropDownSettingsUserView.prototype, AbstractSystemDropDownUserView.prototype);
+
+ module.exports = SystemDropDownSettingsUserView;
+
+ }());
+
+/***/ },
+/* 161 */
+/*!*******************************!*\
+ !*** ./dev/Common/Base64.jsx ***!
+ \*******************************/
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ // Base64 encode / decode
+ // http://www.webtoolkit.info/
+
+ var BASE_64_CHR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
+
+ /* jslint bitwise: true */
+ /* eslint-disable */
+ var Base64 = {
+
+ // public method for urlsafe encoding
+ urlsafe_encode: function urlsafe_encode(input) {
+ return Base64.encode(input).replace(/[+]/g, '-').replace(/[\/]/g, '_').replace(/[=]/g, '.');
+ },
+
+ // public method for encoding
+ encode: function encode(input) {
+
+ var output = '',
+ chr1 = void 0,
+ chr2 = void 0,
+ chr3 = void 0,
+ enc1 = void 0,
+ enc2 = void 0,
+ enc3 = void 0,
+ enc4 = void 0,
+ i = 0;
+
+ input = Base64._utf8_encode(input);
+
+ while (i < input.length) {
+ chr1 = input.charCodeAt(i++);
+ chr2 = input.charCodeAt(i++);
+ chr3 = input.charCodeAt(i++);
+
+ enc1 = chr1 >> 2;
+ enc2 = (chr1 & 3) << 4 | chr2 >> 4;
+ enc3 = (chr2 & 15) << 2 | chr3 >> 6;
+ enc4 = chr3 & 63;
+
+ if (isNaN(chr2)) {
+ enc3 = enc4 = 64;
+ } else if (isNaN(chr3)) {
+ enc4 = 64;
+ }
+
+ output = output + BASE_64_CHR.charAt(enc1) + BASE_64_CHR.charAt(enc2) + BASE_64_CHR.charAt(enc3) + BASE_64_CHR.charAt(enc4);
+ }
+
+ return output;
+ },
+
+ // public method for decoding
+ decode: function decode(input) {
+
+ var output = '',
+ chr1 = void 0,
+ chr2 = void 0,
+ chr3 = void 0,
+ enc1 = void 0,
+ enc2 = void 0,
+ enc3 = void 0,
+ enc4 = void 0,
+ i = 0;
+
+ input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');
+
+ while (i < input.length) {
+ enc1 = BASE_64_CHR.indexOf(input.charAt(i++));
+ enc2 = BASE_64_CHR.indexOf(input.charAt(i++));
+ enc3 = BASE_64_CHR.indexOf(input.charAt(i++));
+ enc4 = BASE_64_CHR.indexOf(input.charAt(i++));
+
+ chr1 = enc1 << 2 | enc2 >> 4;
+ chr2 = (enc2 & 15) << 4 | enc3 >> 2;
+ chr3 = (enc3 & 3) << 6 | enc4;
+
+ output = output + String.fromCharCode(chr1);
+
+ if (enc3 !== 64) {
+ output = output + String.fromCharCode(chr2);
+ }
+
+ if (enc4 !== 64) {
+ output = output + String.fromCharCode(chr3);
+ }
+ }
+
+ return Base64._utf8_decode(output);
+ },
+
+ // private method for UTF-8 encoding
+ _utf8_encode: function _utf8_encode(string) {
+
+ string = string.replace(/\r\n/g, "\n");
+
+ var utftext = '',
+ n = 0,
+ l = string.length,
+ c = 0;
+
+ for (; n < l; n++) {
+
+ c = string.charCodeAt(n);
+
+ if (c < 128) {
+ utftext += String.fromCharCode(c);
+ } else if (c > 127 && c < 2048) {
+ utftext += String.fromCharCode(c >> 6 | 192);
+ utftext += String.fromCharCode(c & 63 | 128);
+ } else {
+ utftext += String.fromCharCode(c >> 12 | 224);
+ utftext += String.fromCharCode(c >> 6 & 63 | 128);
+ utftext += String.fromCharCode(c & 63 | 128);
+ }
+ }
+
+ return utftext;
+ },
+
+ // private method for UTF-8 decoding
+ _utf8_decode: function _utf8_decode(utftext) {
+
+ var string = '',
+ i = 0,
+ c = 0,
+ c2 = 0,
+ c3 = 0;
+
+ while (i < utftext.length) {
+ c = utftext.charCodeAt(i);
+
+ if (c < 128) {
+ string += String.fromCharCode(c);
+ i++;
+ } else if (c > 191 && c < 224) {
+ c2 = utftext.charCodeAt(i + 1);
+ string += String.fromCharCode((c & 31) << 6 | c2 & 63);
+ i += 2;
+ } else {
+ c2 = utftext.charCodeAt(i + 1);
+ c3 = utftext.charCodeAt(i + 2);
+ string += String.fromCharCode((c & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
+ i += 3;
+ }
+ }
+
+ return string;
+ }
+ };
+
+ module.exports = Base64;
+ /* jslint bitwise: false */
+ /* eslint-enable */
+
+/***/ },
+/* 162 */,
+/* 163 */
+/*!***************************************************!*\
+ !*** ./dev/Common/ClientStorageDriver/Cookie.jsx ***!
+ \***************************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.CookieDriver = undefined;
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Consts = __webpack_require__(/*! Common/Consts */ 17);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var CookieDriver = function () {
+ function CookieDriver() {
+ _classCallCheck(this, CookieDriver);
+ }
+
+ /**
+ * @param {string} key
+ * @param {*} data
+ * @return {boolean}
+ */
+
+ CookieDriver.prototype.set = function set(key, data) {
+
+ var result = false,
+ storageResult = null;
+
+ try {
+ var storageValue = _common.$.cookie(_Consts.CLIENT_SIDE_STORAGE_INDEX_NAME);
+ storageResult = null === storageValue ? null : _common.JSON.parse(storageValue);
+ } catch (e) {
+ // eslint-disable-line no-empty
+ }
+
+ (storageResult || (storageResult = {}))[key] = data;
+
+ try {
+ _common.$.cookie(_Consts.CLIENT_SIDE_STORAGE_INDEX_NAME, _common.JSON.stringify(storageResult), {
+ expires: 30
+ });
+
+ result = true;
+ } catch (e) {
+ // eslint-disable-line no-empty
+ }
+
+ return result;
+ };
+
+ /**
+ * @param {string} key
+ * @return {*}
+ */
+
+
+ CookieDriver.prototype.get = function get(key) {
+
+ var result = null;
+
+ try {
+ var storageValue = _common.$.cookie(_Consts.CLIENT_SIDE_STORAGE_INDEX_NAME),
+ storageResult = null === storageValue ? null : _common.JSON.parse(storageValue);
+
+ result = storageResult && !_Utils2.default.isUnd(storageResult[key]) ? storageResult[key] : null;
+ } catch (e) {
+ // eslint-disable-line no-empty
+ }
+
+ return result;
+ };
+
+ /**
+ * @return {boolean}
+ */
+
+
+ CookieDriver.supported = function supported() {
+ return !!(_common.window.navigator && _common.window.navigator.cookieEnabled);
+ };
+
+ return CookieDriver;
+ }();
+
+ exports.CookieDriver = CookieDriver;
+ exports.default = CookieDriver;
+
+/***/ },
+/* 164 */
+/*!*********************************************************!*\
+ !*** ./dev/Common/ClientStorageDriver/LocalStorage.jsx ***!
+ \*********************************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ exports.__esModule = true;
+ exports.default = exports.LocalStorageDriver = undefined;
+
+ var _common = __webpack_require__(/*! common */ 13);
+
+ var _Utils = __webpack_require__(/*! Common/Utils */ 1);
+
+ var _Utils2 = _interopRequireDefault(_Utils);
+
+ var _Consts = __webpack_require__(/*! Common/Consts */ 17);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var LocalStorageDriver = function () {
+ function LocalStorageDriver() {
+ _classCallCheck(this, LocalStorageDriver);
+ }
+
+ /**
+ * @param {string} key
+ * @param {*} data
+ * @return {boolean}
+ */
+
+ LocalStorageDriver.prototype.set = function set(key, data) {
+
+ var result = false,
+ storageResult = null;
+
+ try {
+ var storageValue = _common.window.localStorage[_Consts.CLIENT_SIDE_STORAGE_INDEX_NAME] || null;
+ storageResult = null === storageValue ? null : _common.JSON.parse(storageValue);
+ } catch (e) {
+ // eslint-disable-line no-empty
+ }
+
+ (storageResult || (storageResult = {}))[key] = data;
+
+ try {
+ _common.window.localStorage[_Consts.CLIENT_SIDE_STORAGE_INDEX_NAME] = _common.JSON.stringify(storageResult);
+ result = true;
+ } catch (e) {
+ // eslint-disable-line no-empty
+ }
+
+ return result;
+ };
+
+ /**
+ * @param {string} key
+ * @return {*}
+ */
+
+
+ LocalStorageDriver.prototype.get = function get(key) {
+
+ var result = null;
+
+ try {
+ var storageValue = _common.window.localStorage[_Consts.CLIENT_SIDE_STORAGE_INDEX_NAME] || null,
+ storageResult = null === storageValue ? null : _common.JSON.parse(storageValue);
+
+ result = storageResult && !_Utils2.default.isUnd(storageResult[key]) ? storageResult[key] : null;
+ } catch (e) {
+ // eslint-disable-line no-empty
+ }
+
+ return result;
+ };
+
+ /**
+ * @return {boolean}
+ */
+
+
+ LocalStorageDriver.supported = function supported() {
+ return !!_common.window.localStorage;
+ };
+
+ return LocalStorageDriver;
+ }();
+
+ exports.LocalStorageDriver = LocalStorageDriver;
+ exports.default = LocalStorageDriver;
+
+/***/ },
+/* 165 */,
+/* 166 */,
+/* 167 */,
+/* 168 */,
+/* 169 */,
+/* 170 */
+/*!******************************!*\
+ !*** external "window.$LAB" ***!
+ \******************************/
+/***/ function(module, exports) {
+
+ module.exports = window.$LAB;
+
+/***/ },
+/* 171 */
+/*!*********************************!*\
+ !*** external "window.Tinycon" ***!
+ \*********************************/
+/***/ function(module, exports) {
+
+ module.exports = window.Tinycon;
+
+/***/ },
+/* 172 */
+/*!***********************************!*\
+ !*** external "window.ifvisible" ***!
+ \***********************************/
+/***/ function(module, exports) {
+
+ module.exports = window.ifvisible;
+
+/***/ }
+/******/ ]);
diff --git a/rainloop/rainloop/v/1.10.0.103/static/js/boot.js b/rainloop/rainloop/v/1.10.0.103/static/js/boot.js
new file mode 100644
index 0000000..cf9cee6
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/static/js/boot.js
@@ -0,0 +1,2783 @@
+/******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId])
+/******/ return installedModules[moduleId].exports;
+
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ exports: {},
+/******/ id: moduleId,
+/******/ loaded: false
+/******/ };
+
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ // Flag the module as loaded
+/******/ module.loaded = true;
+
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+
+
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "rainloop/v/0.0.0/static/js/";
+
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ({
+
+/***/ 0:
+/*!**********************!*\
+ !*** ./dev/boot.jsx ***!
+ \**********************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _window = __webpack_require__(/*! window */ 11);
+
+ var _window2 = _interopRequireDefault(_window);
+
+ var _LABSrc = __webpack_require__(/*! labjs/LAB.src.js */ 167);
+
+ var _progress = __webpack_require__(/*! progress.js/src/progress.js */ 169);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ __webpack_require__(/*! json2/json2.js */ 166);
+ __webpack_require__(/*! modernizr/modernizr-custom.js */ 168);
+ __webpack_require__(/*! Common/Booter.jsx */ 162);
+
+ _window2.default.$LAB = _LABSrc.$LAB;
+ _window2.default.progressJs = _progress.progressJs;
+
+/***/ },
+
+/***/ 11:
+/*!*************************!*\
+ !*** external "window" ***!
+ \*************************/
+/***/ function(module, exports) {
+
+ module.exports = window;
+
+/***/ },
+
+/***/ 14:
+/*!********************************!*\
+ !*** external "window.jQuery" ***!
+ \********************************/
+/***/ function(module, exports) {
+
+ module.exports = window.jQuery;
+
+/***/ },
+
+/***/ 162:
+/*!*******************************!*\
+ !*** ./dev/Common/Booter.jsx ***!
+ \*******************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _window = __webpack_require__(/*! window */ 11);
+
+ var _window2 = _interopRequireDefault(_window);
+
+ var _$ = __webpack_require__(/*! $ */ 14);
+
+ var _$2 = _interopRequireDefault(_$);
+
+ var _RainLoop = __webpack_require__(/*! Storage/RainLoop */ 165);
+
+ var _RainLoop2 = _interopRequireDefault(_RainLoop);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ _window2.default.__rlah = function () {
+ return _RainLoop2.default ? _RainLoop2.default.getHash() : null;
+ };
+
+ _window2.default.__rlah_set = function () {
+ if (_RainLoop2.default) {
+ _RainLoop2.default.setHash();
+ }
+ };
+
+ _window2.default.__rlah_clear = function () {
+ if (_RainLoop2.default) {
+ _RainLoop2.default.clearHash();
+ }
+ };
+
+ _window2.default.__includeScr = function (src) {
+ _window2.default.document.write(unescape('%3Csc' + 'ript data-cfasync="false" type="text/jav' + 'ascr' + 'ipt" sr' + 'c="' + src + '"%3E%3C/' + 'scr' + 'ipt%3E'));
+ };
+
+ _window2.default.__includeAppScr = function (src) {
+ _window2.default.__includeScr(src + (_window2.default.__rlah ? _window2.default.__rlah() || '0' : '0') + '/' + _window2.default.Math.random().toString().substr(2) + '/');
+ };
+
+ _window2.default.__includeStyle = function (styles) {
+ _window2.default.document.write(unescape('%3Csty' + 'le%3E' + styles + '"%3E%3C/' + 'sty' + 'le%3E'));
+ };
+
+ _window2.default.__showError = function (additionalError) {
+
+ var oR = _window2.default.document.getElementById('rl-loading'),
+ oL = _window2.default.document.getElementById('rl-loading-error'),
+ oLA = _window2.default.document.getElementById('rl-loading-error-additional');
+
+ if (oR) {
+ oR.style.display = 'none';
+ }
+
+ if (oL) {
+ oL.style.display = 'block';
+ }
+
+ if (oLA && additionalError) {
+ oLA.style.display = 'block';
+ oLA.innerHTML = additionalError;
+ }
+
+ if (_window2.default.rainloopProgressJs) {
+ _window2.default.rainloopProgressJs.set(100);
+ }
+ };
+
+ _window2.default.__showDescription = function (description) {
+
+ var oE = _window2.default.document.getElementById('rl-loading'),
+ oElDesc = _window2.default.document.getElementById('rl-loading-desc');
+
+ if (oElDesc && description) {
+ oElDesc.innerHTML = description;
+ }
+
+ if (oE && oE.style) {
+ oE.style.opacity = 0;
+ _window2.default.setTimeout(function () {
+ oE.style.opacity = 1;
+ }, 300);
+ }
+ };
+
+ _window2.default.__runBoot = function (withError, additionalError) {
+ if (_window2.default.__APP_BOOT && !withError) {
+ _window2.default.__APP_BOOT(function (bV) {
+ if (!bV) {
+ _window2.default.__showError(additionalError);
+ }
+ });
+ } else {
+ _window2.default.__showError(additionalError);
+ }
+ };
+
+ _window2.default.__runApp = function (BaseAppLibsScriptLink, BaseAppMainScriptLink, BaseAppEditorScriptLink) {
+
+ var appData = _window2.default.rainloopAppData;
+
+ if (_window2.default.$LAB && _window2.default.progressJs && appData && appData.TemplatesLink && appData.LangLink) {
+ (function () {
+ var p = _window2.default.progressJs();
+ _window2.default.rainloopProgressJs = p;
+
+ p.setOptions({ theme: 'rainloop' });
+ p.start().set(5);
+
+ _window2.default.$LAB.script(function () {
+ return [{ src: BaseAppLibsScriptLink, type: 'text/javascript', charset: 'utf-8' }];
+ }).wait(function () {
+
+ p.set(20);
+
+ if (appData.IncludeBackground && _$2.default) {
+ (0, _$2.default)('#rl-bg').attr('style', 'background-image: none !important;').backstretch(appData.IncludeBackground.replace('{{USER}}', _window2.default.__rlah ? _window2.default.__rlah() || '0' : '0'), { fade: 100, centeredX: true, centeredY: true }).removeAttr('style');
+ }
+ }).script(function () {
+ return [{ src: appData.TemplatesLink, type: 'text/javascript', charset: 'utf-8' }, { src: appData.LangLink, type: 'text/javascript', charset: 'utf-8' }];
+ }).wait(function () {
+ p.set(30);
+ }).script(function () {
+ return { src: BaseAppMainScriptLink, type: 'text/javascript', charset: 'utf-8' };
+ }).wait(function () {
+ p.set(50);
+ }).script(function () {
+ return appData.PluginsLink ? { src: appData.PluginsLink, type: 'text/javascript', charset: 'utf-8' } : null;
+ }).wait(function () {
+ p.set(70);
+ _window2.default.__runBoot(false);
+ }).script(function () {
+ return { src: BaseAppEditorScriptLink, type: 'text/javascript', charset: 'utf-8' };
+ }).wait(function () {
+ if (_window2.default.CKEDITOR && _window2.default.__initEditor) {
+ _window2.default.__initEditor();
+ _window2.default.__initEditor = null;
+ }
+ });
+ })();
+ } else {
+ _window2.default.__runBoot(true);
+ }
+ };
+
+/***/ },
+
+/***/ 165:
+/*!**********************************!*\
+ !*** ./dev/Storage/RainLoop.jsx ***!
+ \**********************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var _window = __webpack_require__(/*! window */ 11);
+
+ var _window2 = _interopRequireDefault(_window);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var STORAGE_KEY = '__rlA';
+
+ var RainLoopStorage = function () {
+ function RainLoopStorage() {
+ _classCallCheck(this, RainLoopStorage);
+
+ this.s = null;
+ this.t = null;
+
+ this.s = _window2.default.sessionStorage || null;
+ this.t = _window2.default.top || _window2.default;
+ }
+
+ RainLoopStorage.prototype.getHash = function getHash() {
+ var result = null;
+ if (this.s) {
+ result = this.s.getItem(STORAGE_KEY) || null;
+ } else if (this.t && JSON) {
+ var data = this.t.name && '{' === this.t.name.toString().substr(0, 1) ? JSON.parse(this.t.name.toString()) : null;
+ result = data ? data[STORAGE_KEY] || null : null;
+ }
+
+ return result;
+ };
+
+ RainLoopStorage.prototype.setHash = function setHash() {
+ var key = 'AuthAccountHash',
+ appData = _window2.default.rainloopAppData;
+ if (this.s) {
+ this.s.setItem(STORAGE_KEY, appData && appData[key] ? appData[key] : '');
+ } else if (this.t && JSON) {
+ var data = {};
+ data[STORAGE_KEY] = appData && appData[key] ? appData[key] : '';
+
+ this.t.name = JSON.stringify(data);
+ }
+ };
+
+ RainLoopStorage.prototype.clearHash = function clearHash() {
+ if (this.s) {
+ this.s.setItem(STORAGE_KEY, '');
+ } else if (this.t) {
+ this.t.name = '';
+ }
+ };
+
+ return RainLoopStorage;
+ }();
+
+ module.exports = new RainLoopStorage();
+
+/***/ },
+
+/***/ 166:
+/*!********************************!*\
+ !*** ./vendors/json2/json2.js ***!
+ \********************************/
+/***/ function(module, exports) {
+
+ /*
+ json2.js
+ 2015-05-03
+
+ Public Domain.
+
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+ See http://www.JSON.org/js.html
+
+
+ This code should be minified before deployment.
+ See http://javascript.crockford.com/jsmin.html
+
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+ NOT CONTROL.
+
+
+ This file creates a global JSON object containing two methods: stringify
+ and parse. This file is provides the ES5 JSON capability to ES3 systems.
+ If a project might run on IE8 or earlier, then this file should be included.
+ This file does nothing on ES5 systems.
+
+ JSON.stringify(value, replacer, space)
+ value any JavaScript value, usually an object or array.
+
+ replacer an optional parameter that determines how object
+ values are stringified for objects. It can be a
+ function or an array of strings.
+
+ space an optional parameter that specifies the indentation
+ of nested structures. If it is omitted, the text will
+ be packed without extra whitespace. If it is a number,
+ it will specify the number of spaces to indent at each
+ level. If it is a string (such as '\t' or ' '),
+ it contains the characters used to indent at each level.
+
+ This method produces a JSON text from a JavaScript value.
+
+ When an object value is found, if the object contains a toJSON
+ method, its toJSON method will be called and the result will be
+ stringified. A toJSON method does not serialize: it returns the
+ value represented by the name/value pair that should be serialized,
+ or undefined if nothing should be serialized. The toJSON method
+ will be passed the key associated with the value, and this will be
+ bound to the value
+
+ For example, this would serialize Dates as ISO strings.
+
+ Date.prototype.toJSON = function (key) {
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10
+ ? '0' + n
+ : n;
+ }
+
+ return this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z';
+ };
+
+ You can provide an optional replacer method. It will be passed the
+ key and value of each member, with this bound to the containing
+ object. The value that is returned from your method will be
+ serialized. If your method returns undefined, then the member will
+ be excluded from the serialization.
+
+ If the replacer parameter is an array of strings, then it will be
+ used to select the members to be serialized. It filters the results
+ such that only members with keys listed in the replacer array are
+ stringified.
+
+ Values that do not have JSON representations, such as undefined or
+ functions, will not be serialized. Such values in objects will be
+ dropped; in arrays they will be replaced with null. You can use
+ a replacer function to replace those with JSON values.
+ JSON.stringify(undefined) returns undefined.
+
+ The optional space parameter produces a stringification of the
+ value that is filled with line breaks and indentation to make it
+ easier to read.
+
+ If the space parameter is a non-empty string, then that string will
+ be used for indentation. If the space parameter is a number, then
+ the indentation will be that many spaces.
+
+ Example:
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}]);
+ // text is '["e",{"pluribus":"unum"}]'
+
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+ text = JSON.stringify([new Date()], function (key, value) {
+ return this[key] instanceof Date
+ ? 'Date(' + this[key] + ')'
+ : value;
+ });
+ // text is '["Date(---current time---)"]'
+
+
+ JSON.parse(text, reviver)
+ This method parses a JSON text to produce an object or array.
+ It can throw a SyntaxError exception.
+
+ The optional reviver parameter is a function that can filter and
+ transform the results. It receives each of the keys and values,
+ and its return value is used instead of the original value.
+ If it returns what it received, then the structure is not modified.
+ If it returns undefined then the member is deleted.
+
+ Example:
+
+ // Parse the text. Values that look like ISO date strings will
+ // be converted to Date objects.
+
+ myData = JSON.parse(text, function (key, value) {
+ var a;
+ if (typeof value === 'string') {
+ a =
+ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+ if (a) {
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+ +a[5], +a[6]));
+ }
+ }
+ return value;
+ });
+
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+ var d;
+ if (typeof value === 'string' &&
+ value.slice(0, 5) === 'Date(' &&
+ value.slice(-1) === ')') {
+ d = new Date(value.slice(5, -1));
+ if (d) {
+ return d;
+ }
+ }
+ return value;
+ });
+
+
+ This is a reference implementation. You are free to copy, modify, or
+ redistribute.
+ */
+
+ /*jslint
+ eval, for, this
+ */
+
+ /*property
+ JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
+ test, toJSON, toString, valueOf
+ */
+
+
+ // Create a JSON object only if one does not already exist. We create the
+ // methods in a closure to avoid creating global variables.
+
+ if (typeof JSON !== 'object') {
+ JSON = {};
+ }
+
+ (function () {
+ 'use strict';
+
+ var rx_one = /^[\],:{}\s]*$/,
+ rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
+ rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
+ rx_four = /(?:^|:|,)(?:\s*\[)+/g,
+ rx_escapable = /[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
+
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10
+ ? '0' + n
+ : n;
+ }
+
+ function this_value() {
+ return this.valueOf();
+ }
+
+ if (typeof Date.prototype.toJSON !== 'function') {
+
+ Date.prototype.toJSON = function () {
+
+ return isFinite(this.valueOf())
+ ? this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z'
+ : null;
+ };
+
+ Boolean.prototype.toJSON = this_value;
+ Number.prototype.toJSON = this_value;
+ String.prototype.toJSON = this_value;
+ }
+
+ var gap,
+ indent,
+ meta,
+ rep;
+
+
+ function quote(string) {
+
+ // If the string contains no control characters, no quote characters, and no
+ // backslash characters, then we can safely slap some quotes around it.
+ // Otherwise we must also replace the offending characters with safe escape
+ // sequences.
+
+ rx_escapable.lastIndex = 0;
+ return rx_escapable.test(string)
+ ? '"' + string.replace(rx_escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string'
+ ? c
+ : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"'
+ : '"' + string + '"';
+ }
+
+
+ function str(key, holder) {
+
+ // Produce a string from holder[key].
+
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
+
+ // If the value has a toJSON method, call it to obtain a replacement value.
+
+ if (value && typeof value === 'object' &&
+ typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
+
+ // If we were called with a replacer function, then call the replacer to
+ // obtain a replacement value.
+
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
+
+ // What happens next depends on the value's type.
+
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
+
+ case 'number':
+
+ // JSON numbers must be finite. Encode non-finite numbers as null.
+
+ return isFinite(value)
+ ? String(value)
+ : 'null';
+
+ case 'boolean':
+ case 'null':
+
+ // If the value is a boolean or null, convert it to a string. Note:
+ // typeof null does not produce 'null'. The case is included here in
+ // the remote chance that this gets fixed someday.
+
+ return String(value);
+
+ // If the type is 'object', we might be dealing with an object or an array or
+ // null.
+
+ case 'object':
+
+ // Due to a specification blunder in ECMAScript, typeof null is 'object',
+ // so watch out for that case.
+
+ if (!value) {
+ return 'null';
+ }
+
+ // Make an array to hold the partial results of stringifying this object value.
+
+ gap += indent;
+ partial = [];
+
+ // Is the value an array?
+
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+ // The value is an array. Stringify every element. Use null as a placeholder
+ // for non-JSON values.
+
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
+
+ // Join all of the elements together, separated with commas, and wrap them in
+ // brackets.
+
+ v = partial.length === 0
+ ? '[]'
+ : gap
+ ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
+ : '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
+
+ // If the replacer is an array, use it to select the members to be stringified.
+
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ if (typeof rep[i] === 'string') {
+ k = rep[i];
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (
+ gap
+ ? ': '
+ : ':'
+ ) + v);
+ }
+ }
+ }
+ } else {
+
+ // Otherwise, iterate through all of the keys in the object.
+
+ for (k in value) {
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (
+ gap
+ ? ': '
+ : ':'
+ ) + v);
+ }
+ }
+ }
+ }
+
+ // Join all of the member texts together, separated with commas,
+ // and wrap them in braces.
+
+ v = partial.length === 0
+ ? '{}'
+ : gap
+ ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
+ : '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
+ }
+ }
+
+ // If the JSON object does not yet have a stringify method, give it one.
+
+ if (typeof JSON.stringify !== 'function') {
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"': '\\"',
+ '\\': '\\\\'
+ };
+ JSON.stringify = function (value, replacer, space) {
+
+ // The stringify method takes a value and an optional replacer, and an optional
+ // space parameter, and returns a JSON text. The replacer can be a function
+ // that can replace values, or an array of strings that will select the keys.
+ // A default replacer method can be provided. Use of the space parameter can
+ // produce text that is more easily readable.
+
+ var i;
+ gap = '';
+ indent = '';
+
+ // If the space parameter is a number, make an indent string containing that
+ // many spaces.
+
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
+ }
+
+ // If the space parameter is a string, it will be used as the indent string.
+
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
+
+ // If there is a replacer, it must be a function or an array.
+ // Otherwise, throw an error.
+
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('JSON.stringify');
+ }
+
+ // Make a fake root object containing our value under the key of ''.
+ // Return the result of stringifying the value.
+
+ return str('', {'': value});
+ };
+ }
+
+
+ // If the JSON object does not yet have a parse method, give it one.
+
+ if (typeof JSON.parse !== 'function') {
+ JSON.parse = function (text, reviver) {
+
+ // The parse method takes a text and an optional reviver function, and returns
+ // a JavaScript value if the text is a valid JSON text.
+
+ var j;
+
+ function walk(holder, key) {
+
+ // The walk method is used to recursively walk the resulting structure so
+ // that modifications can be made.
+
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
+ }
+ }
+ }
+ }
+ return reviver.call(holder, key, value);
+ }
+
+
+ // Parsing happens in four stages. In the first stage, we replace certain
+ // Unicode characters with escape sequences. JavaScript handles many characters
+ // incorrectly, either silently deleting them, or treating them as line endings.
+
+ text = String(text);
+ rx_dangerous.lastIndex = 0;
+ if (rx_dangerous.test(text)) {
+ text = text.replace(rx_dangerous, function (a) {
+ return '\\u' +
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+
+ // In the second stage, we run the text against regular expressions that look
+ // for non-JSON patterns. We are especially concerned with '()' and 'new'
+ // because they can cause invocation, and '=' because it can cause mutation.
+ // But just to be safe, we want to reject all unexpected forms.
+
+ // We split the second stage into 4 regexp operations in order to work around
+ // crippling inefficiencies in IE's and Safari's regexp engines. First we
+ // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+ // replace all simple value tokens with ']' characters. Third, we delete all
+ // open brackets that follow a colon or comma or that begin the text. Finally,
+ // we look to see that the remaining characters are only whitespace or ']' or
+ // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+ if (
+ rx_one.test(
+ text
+ .replace(rx_two, '@')
+ .replace(rx_three, ']')
+ .replace(rx_four, '')
+ )
+ ) {
+
+ // In the third stage we use the eval function to compile the text into a
+ // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+ // in JavaScript: it can begin a block or an object literal. We wrap the text
+ // in parens to eliminate the ambiguity.
+
+ j = eval('(' + text + ')');
+
+ // In the optional fourth stage, we recursively walk the new structure, passing
+ // each name/value pair to a reviver function for possible transformation.
+
+ return typeof reviver === 'function'
+ ? walk({'': j}, '')
+ : j;
+ }
+
+ // If the text is not JSON parseable, then a SyntaxError is thrown.
+
+ throw new SyntaxError('JSON.parse');
+ };
+ }
+ }());
+
+
+/***/ },
+
+/***/ 167:
+/*!**********************************!*\
+ !*** ./vendors/labjs/LAB.src.js ***!
+ \**********************************/
+/***/ function(module, exports) {
+
+ /*! LAB.js (LABjs :: Loading And Blocking JavaScript)
+ v2.0.3 (c) Kyle Simpson
+ MIT License
+ */
+
+ (function(global){
+ var _$LAB = global.$LAB,
+
+ // constants for the valid keys of the options object
+ _UseLocalXHR = "UseLocalXHR",
+ _AlwaysPreserveOrder = "AlwaysPreserveOrder",
+ _AllowDuplicates = "AllowDuplicates",
+ _CacheBust = "CacheBust",
+ /*!START_DEBUG*/_Debug = "Debug",/*!END_DEBUG*/
+ _BasePath = "BasePath",
+
+ // stateless variables used across all $LAB instances
+ root_page = /^[^?#]*\//.exec(location.href)[0],
+ root_domain = /^\w+\:\/\/\/?[^\/]+/.exec(root_page)[0],
+ append_to = document.head || document.getElementsByTagName("head"),
+
+ // inferences... ick, but still necessary
+ opera_or_gecko = (global.opera && Object.prototype.toString.call(global.opera) == "[object Opera]") || ("MozAppearance" in document.documentElement.style),
+
+ /*!START_DEBUG*/
+ // console.log() and console.error() wrappers
+ log_msg = function(){},
+ log_error = log_msg,
+ /*!END_DEBUG*/
+
+ // feature sniffs (yay!)
+ test_script_elem = document.createElement("script"),
+ explicit_preloading = typeof test_script_elem.preload == "boolean", // http://wiki.whatwg.org/wiki/Script_Execution_Control#Proposal_1_.28Nicholas_Zakas.29
+ real_preloading = explicit_preloading || (test_script_elem.readyState && test_script_elem.readyState == "uninitialized"), // will a script preload with `src` set before DOM append?
+ script_ordered_async = !real_preloading && test_script_elem.async === true, // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
+
+ // XHR preloading (same-domain) and cache-preloading (remote-domain) are the fallbacks (for some browsers)
+ xhr_or_cache_preloading = !real_preloading && !script_ordered_async && !opera_or_gecko
+ ;
+
+ /*!START_DEBUG*/
+ // define console wrapper functions if applicable
+ if (global.console && global.console.log) {
+ if (!global.console.error) global.console.error = global.console.log;
+ log_msg = function(msg) { global.console.log(msg); };
+ log_error = function(msg,err) { global.console.error(msg,err); };
+ }
+ /*!END_DEBUG*/
+
+ // test for function
+ function is_func(func) { return Object.prototype.toString.call(func) == "[object Function]"; }
+
+ // test for array
+ function is_array(arr) { return Object.prototype.toString.call(arr) == "[object Array]"; }
+
+ // make script URL absolute/canonical
+ function canonical_uri(src,base_path) {
+ var absolute_regex = /^\w+\:\/\//;
+
+ // is `src` is protocol-relative (begins with // or ///), prepend protocol
+ if (/^\/\/\/?/.test(src)) {
+ src = location.protocol + src;
+ }
+ // is `src` page-relative? (not an absolute URL, and not a domain-relative path, beginning with /)
+ else if (!absolute_regex.test(src) && src.charAt(0) != "/") {
+ // prepend `base_path`, if any
+ src = (base_path || "") + src;
+ }
+ // make sure to return `src` as absolute
+ return absolute_regex.test(src) ? src : ((src.charAt(0) == "/" ? root_domain : root_page) + src);
+ }
+
+ // merge `source` into `target`
+ function merge_objs(source,target) {
+ for (var k in source) { if (source.hasOwnProperty(k)) {
+ target[k] = source[k]; // TODO: does this need to be recursive for our purposes?
+ }}
+ return target;
+ }
+
+ // does the chain group have any ready-to-execute scripts?
+ function check_chain_group_scripts_ready(chain_group) {
+ var any_scripts_ready = false;
+ for (var i=0; i
0) {
+ for (var i=0; i=0;) {
+ val = queue.shift();
+ $L = $L[val.type].apply(null,val.args);
+ }
+ return $L;
+ },
+
+ // rollback `[global].$LAB` to what it was before this file was loaded, the return this current instance of $LAB
+ noConflict:function(){
+ global.$LAB = _$LAB;
+ return instanceAPI;
+ },
+
+ // create another clean instance of $LAB
+ sandbox:function(){
+ return create_sandbox();
+ }
+ };
+
+ return instanceAPI;
+ }
+
+ // create the main instance of $LAB
+ global.$LAB = create_sandbox();
+
+
+ /* The following "hack" was suggested by Andrea Giammarchi and adapted from: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html
+ NOTE: this hack only operates in FF and then only in versions where document.readyState is not present (FF < 3.6?).
+
+ The hack essentially "patches" the **page** that LABjs is loaded onto so that it has a proper conforming document.readyState, so that if a script which does
+ proper and safe dom-ready detection is loaded onto a page, after dom-ready has passed, it will still be able to detect this state, by inspecting the now hacked
+ document.readyState property. The loaded script in question can then immediately trigger any queued code executions that were waiting for the DOM to be ready.
+ For instance, jQuery 1.4+ has been patched to take advantage of document.readyState, which is enabled by this hack. But 1.3.2 and before are **not** safe or
+ fixed by this hack, and should therefore **not** be lazy-loaded by script loader tools such as LABjs.
+ */
+ (function(addEvent,domLoaded,handler){
+ if (document.readyState == null && document[addEvent]){
+ document.readyState = "loading";
+ document[addEvent](domLoaded,handler = function(){
+ document.removeEventListener(domLoaded,handler,false);
+ document.readyState = "complete";
+ },false);
+ }
+ })("addEventListener","DOMContentLoaded");
+
+ })(this);
+
+/***/ },
+
+/***/ 168:
+/*!***********************************************!*\
+ !*** ./vendors/modernizr/modernizr-custom.js ***!
+ \***********************************************/
+/***/ function(module, exports) {
+
+ /*!
+ * modernizr v3.3.1
+ * Build http://modernizr.com/download?-cssanimations-csstransitions-rgba-setclasses-dontmin
+ *
+ * Copyright (c)
+ * Faruk Ates
+ * Paul Irish
+ * Alex Sexton
+ * Ryan Seddon
+ * Patrick Kettner
+ * Stu Cox
+ * Richard Herrera
+
+ * MIT License
+ */
+
+ /*
+ * Modernizr tests which native CSS3 and HTML5 features are available in the
+ * current UA and makes the results available to you in two ways: as properties on
+ * a global `Modernizr` object, and as classes on the `` element. This
+ * information allows you to progressively enhance your pages with a granular level
+ * of control over the experience.
+ */
+
+ ;(function(window, document, undefined){
+ var classes = [];
+
+
+ var tests = [];
+
+
+ /**
+ *
+ * ModernizrProto is the constructor for Modernizr
+ *
+ * @class
+ * @access public
+ */
+
+ var ModernizrProto = {
+ // The current version, dummy
+ _version: '3.3.1',
+
+ // Any settings that don't work as separate modules
+ // can go in here as configuration.
+ _config: {
+ 'classPrefix': '',
+ 'enableClasses': true,
+ 'enableJSClass': true,
+ 'usePrefixes': true
+ },
+
+ // Queue of tests
+ _q: [],
+
+ // Stub these for people who are listening
+ on: function(test, cb) {
+ // I don't really think people should do this, but we can
+ // safe guard it a bit.
+ // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
+ // This is in case people listen to synchronous tests. I would leave it out,
+ // but the code to *disallow* sync tests in the real version of this
+ // function is actually larger than this.
+ var self = this;
+ setTimeout(function() {
+ cb(self[test]);
+ }, 0);
+ },
+
+ addTest: function(name, fn, options) {
+ tests.push({name: name, fn: fn, options: options});
+ },
+
+ addAsyncTest: function(fn) {
+ tests.push({name: null, fn: fn});
+ }
+ };
+
+
+
+ // Fake some of Object.create so we can force non test results to be non "own" properties.
+ var Modernizr = function() {};
+ Modernizr.prototype = ModernizrProto;
+
+ // Leak modernizr globally when you `require` it rather than force it here.
+ // Overwrite name so constructor name is nicer :D
+ Modernizr = new Modernizr();
+
+
+
+ /**
+ * is returns a boolean if the typeof an obj is exactly type.
+ *
+ * @access private
+ * @function is
+ * @param {*} obj - A thing we want to check the type of
+ * @param {string} type - A string to compare the typeof against
+ * @returns {boolean}
+ */
+
+ function is(obj, type) {
+ return typeof obj === type;
+ }
+ ;
+
+ /**
+ * Run through all tests and detect their support in the current UA.
+ *
+ * @access private
+ */
+
+ function testRunner() {
+ var featureNames;
+ var feature;
+ var aliasIdx;
+ var result;
+ var nameIdx;
+ var featureName;
+ var featureNameSplit;
+
+ for (var featureIdx in tests) {
+ if (tests.hasOwnProperty(featureIdx)) {
+ featureNames = [];
+ feature = tests[featureIdx];
+ // run the test, throw the return value into the Modernizr,
+ // then based on that boolean, define an appropriate className
+ // and push it into an array of classes we'll join later.
+ //
+ // If there is no name, it's an 'async' test that is run,
+ // but not directly added to the object. That should
+ // be done with a post-run addTest call.
+ if (feature.name) {
+ featureNames.push(feature.name.toLowerCase());
+
+ if (feature.options && feature.options.aliases && feature.options.aliases.length) {
+ // Add all the aliases into the names list
+ for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
+ featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
+ }
+ }
+ }
+
+ // Run the test, or use the raw value if it's not a function
+ result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
+
+
+ // Set each of the names on the Modernizr object
+ for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
+ featureName = featureNames[nameIdx];
+ // Support dot properties as sub tests. We don't do checking to make sure
+ // that the implied parent tests have been added. You must call them in
+ // order (either in the test, or make the parent test a dependency).
+ //
+ // Cap it to TWO to make the logic simple and because who needs that kind of subtesting
+ // hashtag famous last words
+ featureNameSplit = featureName.split('.');
+
+ if (featureNameSplit.length === 1) {
+ Modernizr[featureNameSplit[0]] = result;
+ } else {
+ // cast to a Boolean, if not one already
+ /* jshint -W053 */
+ if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
+ Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
+ }
+
+ Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
+ }
+
+ classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
+ }
+ }
+ }
+ }
+ ;
+
+ /**
+ * docElement is a convenience wrapper to grab the root element of the document
+ *
+ * @access private
+ * @returns {HTMLElement|SVGElement} The root element of the document
+ */
+
+ var docElement = document.documentElement;
+
+
+ /**
+ * A convenience helper to check if the document we are running in is an SVG document
+ *
+ * @access private
+ * @returns {boolean}
+ */
+
+ var isSVG = docElement.nodeName.toLowerCase() === 'svg';
+
+
+ /**
+ * setClasses takes an array of class names and adds them to the root element
+ *
+ * @access private
+ * @function setClasses
+ * @param {string[]} classes - Array of class names
+ */
+
+ // Pass in an and array of class names, e.g.:
+ // ['no-webp', 'borderradius', ...]
+ function setClasses(classes) {
+ var className = docElement.className;
+ var classPrefix = Modernizr._config.classPrefix || '';
+
+ if (isSVG) {
+ className = className.baseVal;
+ }
+
+ // Change `no-js` to `js` (independently of the `enableClasses` option)
+ // Handle classPrefix on this too
+ if (Modernizr._config.enableJSClass) {
+ var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)');
+ className = className.replace(reJS, '$1' + classPrefix + 'js$2');
+ }
+
+ if (Modernizr._config.enableClasses) {
+ // Add the new classes
+ className += ' ' + classPrefix + classes.join(' ' + classPrefix);
+ isSVG ? docElement.className.baseVal = className : docElement.className = className;
+ }
+
+ }
+
+ ;
+
+ /**
+ * createElement is a convenience wrapper around document.createElement. Since we
+ * use createElement all over the place, this allows for (slightly) smaller code
+ * as well as abstracting away issues with creating elements in contexts other than
+ * HTML documents (e.g. SVG documents).
+ *
+ * @access private
+ * @function createElement
+ * @returns {HTMLElement|SVGElement} An HTML or SVG element
+ */
+
+ function createElement() {
+ if (typeof document.createElement !== 'function') {
+ // This is the case in IE7, where the type of createElement is "object".
+ // For this reason, we cannot call apply() as Object is not a Function.
+ return document.createElement(arguments[0]);
+ } else if (isSVG) {
+ return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
+ } else {
+ return document.createElement.apply(document, arguments);
+ }
+ }
+
+ ;
+ /*!
+ {
+ "name": "CSS rgba",
+ "caniuse": "css3-colors",
+ "property": "rgba",
+ "tags": ["css"],
+ "notes": [{
+ "name": "CSSTricks Tutorial",
+ "href": "https://css-tricks.com/rgba-browser-support/"
+ }]
+ }
+ !*/
+
+ Modernizr.addTest('rgba', function() {
+ var style = createElement('a').style;
+ style.cssText = 'background-color:rgba(150,255,150,.5)';
+
+ return ('' + style.backgroundColor).indexOf('rgba') > -1;
+ });
+
+
+ /**
+ * If the browsers follow the spec, then they would expose vendor-specific style as:
+ * elem.style.WebkitBorderRadius
+ * instead of something like the following, which would be technically incorrect:
+ * elem.style.webkitBorderRadius
+
+ * Webkit ghosts their properties in lowercase but Opera & Moz do not.
+ * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
+ * erik.eae.net/archives/2008/03/10/21.48.10/
+
+ * More here: github.com/Modernizr/Modernizr/issues/issue/21
+ *
+ * @access private
+ * @returns {string} The string representing the vendor-specific style properties
+ */
+
+ var omPrefixes = 'Moz O ms Webkit';
+
+
+ var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []);
+ ModernizrProto._cssomPrefixes = cssomPrefixes;
+
+
+ /**
+ * List of JavaScript DOM values used for tests
+ *
+ * @memberof Modernizr
+ * @name Modernizr._domPrefixes
+ * @optionName Modernizr._domPrefixes
+ * @optionProp domPrefixes
+ * @access public
+ * @example
+ *
+ * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather
+ * than kebab-case properties, all properties are their Capitalized variant
+ *
+ * ```js
+ * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ];
+ * ```
+ */
+
+ var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []);
+ ModernizrProto._domPrefixes = domPrefixes;
+
+
+
+ /**
+ * contains checks to see if a string contains another string
+ *
+ * @access private
+ * @function contains
+ * @param {string} str - The string we want to check for substrings
+ * @param {string} substr - The substring we want to search the first string for
+ * @returns {boolean}
+ */
+
+ function contains(str, substr) {
+ return !!~('' + str).indexOf(substr);
+ }
+
+ ;
+
+ /**
+ * cssToDOM takes a kebab-case string and converts it to camelCase
+ * e.g. box-sizing -> boxSizing
+ *
+ * @access private
+ * @function cssToDOM
+ * @param {string} name - String name of kebab-case prop we want to convert
+ * @returns {string} The camelCase version of the supplied name
+ */
+
+ function cssToDOM(name) {
+ return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) {
+ return m1 + m2.toUpperCase();
+ }).replace(/^-/, '');
+ }
+ ;
+
+ /**
+ * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill.
+ *
+ * @access private
+ * @function fnBind
+ * @param {function} fn - a function you want to change `this` reference to
+ * @param {object} that - the `this` you want to call the function with
+ * @returns {function} The wrapped version of the supplied function
+ */
+
+ function fnBind(fn, that) {
+ return function() {
+ return fn.apply(that, arguments);
+ };
+ }
+
+ ;
+
+ /**
+ * testDOMProps is a generic DOM property test; if a browser supports
+ * a certain property, it won't return undefined for it.
+ *
+ * @access private
+ * @function testDOMProps
+ * @param {array.} props - An array of properties to test for
+ * @param {object} obj - An object or Element you want to use to test the parameters again
+ * @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check
+ */
+ function testDOMProps(props, obj, elem) {
+ var item;
+
+ for (var i in props) {
+ if (props[i] in obj) {
+
+ // return the property name as a string
+ if (elem === false) {
+ return props[i];
+ }
+
+ item = obj[props[i]];
+
+ // let's bind a function
+ if (is(item, 'function')) {
+ // bind to obj unless overriden
+ return fnBind(item, elem || obj);
+ }
+
+ // return the unbound function or obj or value
+ return item;
+ }
+ }
+ return false;
+ }
+
+ ;
+
+ /**
+ * Create our "modernizr" element that we do most feature tests on.
+ *
+ * @access private
+ */
+
+ var modElem = {
+ elem: createElement('modernizr')
+ };
+
+ // Clean up this element
+ Modernizr._q.push(function() {
+ delete modElem.elem;
+ });
+
+
+
+ var mStyle = {
+ style: modElem.elem.style
+ };
+
+ // kill ref for gc, must happen before mod.elem is removed, so we unshift on to
+ // the front of the queue.
+ Modernizr._q.unshift(function() {
+ delete mStyle.style;
+ });
+
+
+
+ /**
+ * domToCSS takes a camelCase string and converts it to kebab-case
+ * e.g. boxSizing -> box-sizing
+ *
+ * @access private
+ * @function domToCSS
+ * @param {string} name - String name of camelCase prop we want to convert
+ * @returns {string} The kebab-case version of the supplied name
+ */
+
+ function domToCSS(name) {
+ return name.replace(/([A-Z])/g, function(str, m1) {
+ return '-' + m1.toLowerCase();
+ }).replace(/^ms-/, '-ms-');
+ }
+ ;
+
+ /**
+ * getBody returns the body of a document, or an element that can stand in for
+ * the body if a real body does not exist
+ *
+ * @access private
+ * @function getBody
+ * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
+ * artificially created element that stands in for the body
+ */
+
+ function getBody() {
+ // After page load injecting a fake body doesn't work so check if body exists
+ var body = document.body;
+
+ if (!body) {
+ // Can't use the real body create a fake one.
+ body = createElement(isSVG ? 'svg' : 'body');
+ body.fake = true;
+ }
+
+ return body;
+ }
+
+ ;
+
+ /**
+ * injectElementWithStyles injects an element with style element and some CSS rules
+ *
+ * @access private
+ * @function injectElementWithStyles
+ * @param {string} rule - String representing a css rule
+ * @param {function} callback - A function that is used to test the injected element
+ * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
+ * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
+ * @returns {boolean}
+ */
+
+ function injectElementWithStyles(rule, callback, nodes, testnames) {
+ var mod = 'modernizr';
+ var style;
+ var ret;
+ var node;
+ var docOverflow;
+ var div = createElement('div');
+ var body = getBody();
+
+ if (parseInt(nodes, 10)) {
+ // In order not to give false positives we create a node for each test
+ // This also allows the method to scale for unspecified uses
+ while (nodes--) {
+ node = createElement('div');
+ node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
+ div.appendChild(node);
+ }
+ }
+
+ style = createElement('style');
+ style.type = 'text/css';
+ style.id = 's' + mod;
+
+ // IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody.
+ // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
+ (!body.fake ? div : body).appendChild(style);
+ body.appendChild(div);
+
+ if (style.styleSheet) {
+ style.styleSheet.cssText = rule;
+ } else {
+ style.appendChild(document.createTextNode(rule));
+ }
+ div.id = mod;
+
+ if (body.fake) {
+ //avoid crashing IE8, if background image is used
+ body.style.background = '';
+ //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
+ body.style.overflow = 'hidden';
+ docOverflow = docElement.style.overflow;
+ docElement.style.overflow = 'hidden';
+ docElement.appendChild(body);
+ }
+
+ ret = callback(div, rule);
+ // If this is done after page load we don't want to remove the body so check if body exists
+ if (body.fake) {
+ body.parentNode.removeChild(body);
+ docElement.style.overflow = docOverflow;
+ // Trigger layout so kinetic scrolling isn't disabled in iOS6+
+ docElement.offsetHeight;
+ } else {
+ div.parentNode.removeChild(div);
+ }
+
+ return !!ret;
+
+ }
+
+ ;
+
+ /**
+ * nativeTestProps allows for us to use native feature detection functionality if available.
+ * some prefixed form, or false, in the case of an unsupported rule
+ *
+ * @access private
+ * @function nativeTestProps
+ * @param {array} props - An array of property names
+ * @param {string} value - A string representing the value we want to check via @supports
+ * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise
+ */
+
+ // Accepts a list of property names and a single value
+ // Returns `undefined` if native detection not available
+ function nativeTestProps(props, value) {
+ var i = props.length;
+ // Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface
+ if ('CSS' in window && 'supports' in window.CSS) {
+ // Try every prefixed variant of the property
+ while (i--) {
+ if (window.CSS.supports(domToCSS(props[i]), value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ // Otherwise fall back to at-rule (for Opera 12.x)
+ else if ('CSSSupportsRule' in window) {
+ // Build a condition string for every prefixed variant
+ var conditionText = [];
+ while (i--) {
+ conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')');
+ }
+ conditionText = conditionText.join(' or ');
+ return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) {
+ return getComputedStyle(node, null).position == 'absolute';
+ });
+ }
+ return undefined;
+ }
+ ;
+
+ // testProps is a generic CSS / DOM property test.
+
+ // In testing support for a given CSS property, it's legit to test:
+ // `elem.style[styleName] !== undefined`
+ // If the property is supported it will return an empty string,
+ // if unsupported it will return undefined.
+
+ // We'll take advantage of this quick test and skip setting a style
+ // on our modernizr element, but instead just testing undefined vs
+ // empty string.
+
+ // Property names can be provided in either camelCase or kebab-case.
+
+ function testProps(props, prefixed, value, skipValueTest) {
+ skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest;
+
+ // Try native detect first
+ if (!is(value, 'undefined')) {
+ var result = nativeTestProps(props, value);
+ if (!is(result, 'undefined')) {
+ return result;
+ }
+ }
+
+ // Otherwise do it properly
+ var afterInit, i, propsLength, prop, before;
+
+ // If we don't have a style element, that means we're running async or after
+ // the core tests, so we'll need to create our own elements to use
+
+ // inside of an SVG element, in certain browsers, the `style` element is only
+ // defined for valid tags. Therefore, if `modernizr` does not have one, we
+ // fall back to a less used element and hope for the best.
+ var elems = ['modernizr', 'tspan'];
+ while (!mStyle.style) {
+ afterInit = true;
+ mStyle.modElem = createElement(elems.shift());
+ mStyle.style = mStyle.modElem.style;
+ }
+
+ // Delete the objects if we created them.
+ function cleanElems() {
+ if (afterInit) {
+ delete mStyle.style;
+ delete mStyle.modElem;
+ }
+ }
+
+ propsLength = props.length;
+ for (i = 0; i < propsLength; i++) {
+ prop = props[i];
+ before = mStyle.style[prop];
+
+ if (contains(prop, '-')) {
+ prop = cssToDOM(prop);
+ }
+
+ if (mStyle.style[prop] !== undefined) {
+
+ // If value to test has been passed in, do a set-and-check test.
+ // 0 (integer) is a valid property value, so check that `value` isn't
+ // undefined, rather than just checking it's truthy.
+ if (!skipValueTest && !is(value, 'undefined')) {
+
+ // Needs a try catch block because of old IE. This is slow, but will
+ // be avoided in most cases because `skipValueTest` will be used.
+ try {
+ mStyle.style[prop] = value;
+ } catch (e) {}
+
+ // If the property value has changed, we assume the value used is
+ // supported. If `value` is empty string, it'll fail here (because
+ // it hasn't changed), which matches how browsers have implemented
+ // CSS.supports()
+ if (mStyle.style[prop] != before) {
+ cleanElems();
+ return prefixed == 'pfx' ? prop : true;
+ }
+ }
+ // Otherwise just return true, or the property name if this is a
+ // `prefixed()` call
+ else {
+ cleanElems();
+ return prefixed == 'pfx' ? prop : true;
+ }
+ }
+ }
+ cleanElems();
+ return false;
+ }
+
+ ;
+
+ /**
+ * testPropsAll tests a list of DOM properties we want to check against.
+ * We specify literally ALL possible (known and/or likely) properties on
+ * the element including the non-vendor prefixed one, for forward-
+ * compatibility.
+ *
+ * @access private
+ * @function testPropsAll
+ * @param {string} prop - A string of the property to test for
+ * @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip
+ * @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against
+ * @param {string} [value] - A string of a css value
+ * @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set
+ */
+ function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
+
+ var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
+ props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
+
+ // did they call .prefixed('boxSizing') or are we just testing a prop?
+ if (is(prefixed, 'string') || is(prefixed, 'undefined')) {
+ return testProps(props, prefixed, value, skipValueTest);
+
+ // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
+ } else {
+ props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
+ return testDOMProps(props, prefixed, elem);
+ }
+ }
+
+ // Modernizr.testAllProps() investigates whether a given style property,
+ // or any of its vendor-prefixed variants, is recognized
+ //
+ // Note that the property names must be provided in the camelCase variant.
+ // Modernizr.testAllProps('boxSizing')
+ ModernizrProto.testAllProps = testPropsAll;
+
+
+
+ /**
+ * testAllProps determines whether a given CSS property is supported in the browser
+ *
+ * @memberof Modernizr
+ * @name Modernizr.testAllProps
+ * @optionName Modernizr.testAllProps()
+ * @optionProp testAllProps
+ * @access public
+ * @function testAllProps
+ * @param {string} prop - String naming the property to test (either camelCase or kebab-case)
+ * @param {string} [value] - String of the value to test
+ * @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection
+ * @example
+ *
+ * testAllProps determines whether a given CSS property, in some prefixed form,
+ * is supported by the browser.
+ *
+ * ```js
+ * testAllProps('boxSizing') // true
+ * ```
+ *
+ * It can optionally be given a CSS value in string form to test if a property
+ * value is valid
+ *
+ * ```js
+ * testAllProps('display', 'block') // true
+ * testAllProps('display', 'penguin') // false
+ * ```
+ *
+ * A boolean can be passed as a third parameter to skip the value check when
+ * native detection (@supports) isn't available.
+ *
+ * ```js
+ * testAllProps('shapeOutside', 'content-box', true);
+ * ```
+ */
+
+ function testAllProps(prop, value, skipValueTest) {
+ return testPropsAll(prop, undefined, undefined, value, skipValueTest);
+ }
+ ModernizrProto.testAllProps = testAllProps;
+
+ /*!
+ {
+ "name": "CSS Animations",
+ "property": "cssanimations",
+ "caniuse": "css-animation",
+ "polyfills": ["transformie", "csssandpaper"],
+ "tags": ["css"],
+ "warnings": ["Android < 4 will pass this test, but can only animate a single property at a time"],
+ "notes": [{
+ "name" : "Article: 'Dispelling the Android CSS animation myths'",
+ "href": "https://goo.gl/OGw5Gm"
+ }]
+ }
+ !*/
+ /* DOC
+ Detects whether or not elements can be animated using CSS
+ */
+
+ Modernizr.addTest('cssanimations', testAllProps('animationName', 'a', true));
+
+ /*!
+ {
+ "name": "CSS Transitions",
+ "property": "csstransitions",
+ "caniuse": "css-transitions",
+ "tags": ["css"]
+ }
+ !*/
+
+ Modernizr.addTest('csstransitions', testAllProps('transition', 'all', true));
+
+
+ // Run each test
+ testRunner();
+
+ // Remove the "no-js" class if it exists
+ setClasses(classes);
+
+ delete ModernizrProto.addTest;
+ delete ModernizrProto.addAsyncTest;
+
+ // Run the things that are supposed to run after the tests
+ for (var i = 0; i < Modernizr._q.length; i++) {
+ Modernizr._q[i]();
+ }
+
+ // Leak Modernizr namespace
+ window.Modernizr = Modernizr;
+
+
+ ;
+
+ })(window, document);
+
+/***/ },
+
+/***/ 169:
+/*!*********************************************!*\
+ !*** ./vendors/progress.js/src/progress.js ***!
+ \*********************************************/
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * Progress.js v0.1.0
+ * https://github.com/usablica/progress.js
+ * MIT licensed
+ *
+ * Copyright (C) 2013 usabli.ca - Afshin Mehrabani (@afshinmeh)
+ */
+
+ (function (root, factory) {
+ if (true) {
+ // CommonJS
+ factory(exports);
+ } else if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['exports'], factory);
+ } else {
+ // Browser globals
+ factory(root);
+ }
+ } (this, function (exports) {
+ //Default config/variables
+ var VERSION = '0.1.0';
+
+ /**
+ * ProgressJs main class
+ *
+ * @class ProgressJs
+ */
+ function ProgressJs(obj) {
+
+ if (typeof obj.length != 'undefined') {
+ this._targetElement = obj;
+ } else {
+ this._targetElement = [obj];
+ }
+
+ if (typeof window._progressjsId === 'undefined')
+ window._progressjsId = 1;
+
+ if (typeof window._progressjsIntervals === 'undefined')
+ window._progressjsIntervals = {};
+
+ this._options = {
+ //progress bar theme
+ theme: 'blue',
+ //overlay mode makes an overlay layer in the target element
+ overlayMode: false,
+ //to consider CSS3 transitions in events
+ considerTransition: true
+ };
+ }
+
+ /**
+ * Start progress for specific element(s)
+ *
+ * @api private
+ * @method _createContainer
+ */
+ function _startProgress() {
+
+ //call onBeforeStart callback
+ if (typeof this._onBeforeStartCallback != 'undefined') {
+ this._onBeforeStartCallback.call(this);
+ }
+
+ //create the container for progress bar
+ _createContainer.call(this);
+
+ for (var i = 0, elmsLength = this._targetElement.length; i < elmsLength; i++) {
+ _setProgress.call(this, this._targetElement[i]);
+ }
+ }
+
+ /**
+ * Set progress bar for specific element
+ *
+ * @api private
+ * @method _setProgress
+ * @param {Object} targetElement
+ */
+ function _setProgress(targetElement) {
+
+ //if the target element already as `data-progressjs`, ignore the init
+ if (targetElement.hasAttribute("data-progressjs"))
+ return;
+
+ //get target element position
+ var targetElementOffset = _getOffset.call(this, targetElement);
+
+ targetElement.setAttribute("data-progressjs", window._progressjsId);
+
+ var progressElementContainer = document.createElement('div');
+ progressElementContainer.className = 'progressjs-progress progressjs-theme-' + this._options.theme;
+
+
+ //set the position percent elements, it depends on targetElement tag
+ if (targetElement.tagName.toLowerCase() === 'body') {
+ progressElementContainer.style.position = 'fixed';
+ } else {
+ progressElementContainer.style.position = 'absolute';
+ }
+
+ progressElementContainer.setAttribute("data-progressjs", window._progressjsId);
+ var progressElement = document.createElement("div");
+ progressElement.className = "progressjs-inner";
+
+ //create an element for current percent of progress bar
+ var progressPercentElement = document.createElement('div');
+ progressPercentElement.className = "progressjs-percent";
+ progressPercentElement.innerHTML = "1%";
+
+ progressElement.appendChild(progressPercentElement);
+
+ if (this._options.overlayMode && targetElement.tagName.toLowerCase() === 'body') {
+ //if we have `body` for target element and also overlay mode is enable, we should use a different
+ //position for progress bar container element
+ progressElementContainer.style.left = 0;
+ progressElementContainer.style.right = 0;
+ progressElementContainer.style.top = 0;
+ progressElementContainer.style.bottom = 0;
+ } else {
+ //set progress bar container size and offset
+ progressElementContainer.style.left = targetElementOffset.left + 'px';
+ progressElementContainer.style.top = targetElementOffset.top + 'px';
+ //if targetElement is body set to percent so it scales with browser resize
+ if (targetElement.nodeName == 'BODY') {
+ progressElementContainer.style.width = '100%';
+ } else {
+ progressElementContainer.style.width = targetElementOffset.width + 'px';
+ }
+
+ if (this._options.overlayMode) {
+ progressElementContainer.style.height = targetElementOffset.height + 'px';
+ }
+ }
+
+ progressElementContainer.appendChild(progressElement);
+
+ //append the element to container
+ var container = document.querySelector('.progressjs-container');
+ container.appendChild(progressElementContainer);
+
+ _setPercentFor(targetElement, 1);
+
+ //and increase the progressId
+ ++window._progressjsId;
+ }
+
+ /**
+ * Set percent for all elements
+ *
+ * @api private
+ * @method _setPercent
+ * @param {Number} percent
+ */
+ function _setPercent(percent) {
+ for (var i = 0, elmsLength = this._targetElement.length; i < elmsLength; i++) {
+ _setPercentFor.call(this, this._targetElement[i], percent);
+ }
+ }
+
+ /**
+ * Set percent for specific element
+ *
+ * @api private
+ * @method _setPercentFor
+ * @param {Object} targetElement
+ * @param {Number} percent
+ */
+ function _setPercentFor(targetElement, percent) {
+ var self = this;
+
+ //prevent overflow!
+ if (percent >= 100)
+ percent = 100;
+
+ if (targetElement.hasAttribute("data-progressjs")) {
+ //setTimeout for better CSS3 animation applying in some cases
+ setTimeout(function() {
+
+ //call the onprogress callback
+ if (typeof self._onProgressCallback != 'undefined') {
+ self._onProgressCallback.call(self, targetElement, percent);
+ }
+
+ var percentElement = _getPercentElement(targetElement);
+ percentElement.style.width = parseInt(percent) + '%';
+
+ var percentElement = percentElement.querySelector(".progressjs-percent");
+ var existingPercent = parseInt(percentElement.innerHTML.replace('%', ''));
+
+ //start increase/decrease the percent element with animation
+ (function(percentElement, existingPercent, currentPercent) {
+
+ var increasement = true;
+ if (existingPercent > currentPercent) {
+ increasement = false;
+ }
+
+ var intervalIn = 10;
+ function changePercentTimer(percentElement, existingPercent, currentPercent) {
+ //calculate the distance between two percents
+ var distance = Math.abs(existingPercent - currentPercent);
+ if (distance < 3) {
+ intervalIn = 30;
+ } else if (distance < 20) {
+ intervalIn = 20;
+ } else {
+ intervanIn = 1;
+ }
+
+ if ((existingPercent - currentPercent) != 0) {
+ //set the percent
+ percentElement.innerHTML = (increasement ? (++existingPercent) : (--existingPercent)) + '%';
+ setTimeout(function() { changePercentTimer(percentElement, existingPercent, currentPercent); }, intervalIn);
+ }
+ }
+
+ changePercentTimer(percentElement, existingPercent, currentPercent);
+
+ })(percentElement, existingPercent, parseInt(percent));
+
+ }, 50);
+ }
+ }
+
+ /**
+ * Get the progress bar element
+ *
+ * @api private
+ * @method _getPercentElement
+ * @param {Object} targetElement
+ */
+ function _getPercentElement(targetElement) {
+ var progressjsId = parseInt(targetElement.getAttribute('data-progressjs'));
+ return document.querySelector('.progressjs-container > .progressjs-progress[data-progressjs="' + progressjsId + '"] > .progressjs-inner');
+ }
+
+ /**
+ * Auto increase the progress bar every X milliseconds
+ *
+ * @api private
+ * @method _autoIncrease
+ * @param {Number} size
+ * @param {Number} millisecond
+ */
+ function _autoIncrease(size, millisecond) {
+ var self = this;
+
+ var target = this._targetElement[0];
+ if(!target) return;
+ var progressjsId = parseInt(target.getAttribute('data-progressjs'));
+
+ if (typeof window._progressjsIntervals[progressjsId] != 'undefined') {
+ clearInterval(window._progressjsIntervals[progressjsId]);
+ }
+ window._progressjsIntervals[progressjsId] = setInterval(function() {
+ _increasePercent.call(self, size);
+ }, millisecond);
+ }
+
+ /**
+ * Increase the size of progress bar
+ *
+ * @api private
+ * @method _increasePercent
+ * @param {Number} size
+ */
+ function _increasePercent(size) {
+ for (var i = 0, elmsLength = this._targetElement.length; i < elmsLength; i++) {
+ var currentElement = this._targetElement[i];
+ if (currentElement.hasAttribute('data-progressjs')) {
+ var percentElement = _getPercentElement(currentElement);
+ var existingPercent = parseInt(percentElement.style.width.replace('%', ''));
+ if (existingPercent) {
+ _setPercentFor.call(this, currentElement, existingPercent + (size || 1));
+ }
+ }
+ }
+ }
+
+ /**
+ * Close and remove progress bar
+ *
+ * @api private
+ * @method _end
+ */
+ function _end() {
+
+ //call onBeforeEnd callback
+ if (typeof this._onBeforeEndCallback != 'undefined') {
+ if (this._options.considerTransition === true) {
+ //we can safety assume that all layers would be the same, so `this._targetElement[0]` is the same as `this._targetElement[1]`
+ _getPercentElement(this._targetElement[0]).addEventListener(whichTransitionEvent(), this._onBeforeEndCallback, false);
+ } else {
+ this._onBeforeEndCallback.call(this);
+ }
+ }
+
+ var target = this._targetElement[0];
+ if(!target) return;
+ var progressjsId = parseInt(target.getAttribute('data-progressjs'));
+
+ for (var i = 0, elmsLength = this._targetElement.length; i < elmsLength; i++) {
+ var currentElement = this._targetElement[i];
+ var percentElement = _getPercentElement(currentElement);
+
+ if (!percentElement)
+ return;
+
+ var existingPercent = parseInt(percentElement.style.width.replace('%', ''));
+
+ var timeoutSec = 1;
+ if (existingPercent < 100) {
+ _setPercentFor.call(this, currentElement, 100);
+ timeoutSec = 500;
+ }
+
+ //I believe I should handle this situation with eventListener and `transitionend` event but I'm not sure
+ //about compatibility with IEs. Should be fixed in further versions.
+ (function(percentElement, currentElement) {
+ setTimeout(function() {
+ percentElement.parentNode.className += " progressjs-end";
+
+ setTimeout(function() {
+ //remove the percent element from page
+ percentElement.parentNode.parentNode.removeChild(percentElement.parentNode);
+ //and remove the attribute
+ currentElement.removeAttribute("data-progressjs");
+ }, 1000);
+ }, timeoutSec);
+ })(percentElement, currentElement);
+ }
+
+ //clean the setInterval for autoIncrease function
+ if (window._progressjsIntervals[progressjsId]) {
+ //`delete` keyword has some problems in IE
+ try {
+ clearInterval(window._progressjsIntervals[progressjsId]);
+ window._progressjsIntervals[progressjsId] = null;
+ delete window._progressjsIntervals[progressjsId];
+ } catch(ex) { }
+ }
+ }
+
+ /**
+ * Remove progress bar without finishing
+ *
+ * @api private
+ * @method _kill
+ */
+ function _kill() {
+ var target = this._targetElement[0];
+ if(!target) return;
+ var progressjsId = parseInt(target.getAttribute('data-progressjs'));
+
+ for (var i = 0, elmsLength = this._targetElement.length; i < elmsLength; i++) {
+ var currentElement = this._targetElement[i];
+ var percentElement = _getPercentElement(currentElement);
+
+ if (!percentElement)
+ return;
+
+ //I believe I should handle this situation with eventListener and `transitionend` event but I'm not sure
+ //about compatibility with IEs. Should be fixed in further versions.
+ (function(percentElement, currentElement) {
+ percentElement.parentNode.className += " progressjs-end";
+
+ setTimeout(function() {
+ //remove the percent element from page
+ percentElement.parentNode.parentNode.removeChild(percentElement.parentNode);
+ //and remove the attribute
+ currentElement.removeAttribute("data-progressjs");
+ }, 1000);
+ })(percentElement, currentElement);
+ }
+
+ //clean the setInterval for autoIncrease function
+ if (window._progressjsIntervals[progressjsId]) {
+ //`delete` keyword has some problems in IE
+ try {
+ clearInterval(window._progressjsIntervals[progressjsId]);
+ window._progressjsIntervals[progressjsId] = null;
+ delete window._progressjsIntervals[progressjsId];
+ } catch(ex) { }
+ }
+ }
+
+ /**
+ * Create the progress bar container
+ *
+ * @api private
+ * @method _createContainer
+ */
+ function _createContainer() {
+ //first check if we have an container already, we don't need to create it again
+ if (!document.querySelector(".progressjs-container")) {
+ var containerElement = document.createElement("div");
+ containerElement.className = "progressjs-container";
+ document.body.appendChild(containerElement);
+ }
+ }
+
+ /**
+ * Get an element position on the page
+ * Thanks to `meouw`: http://stackoverflow.com/a/442474/375966
+ *
+ * @api private
+ * @method _getOffset
+ * @param {Object} element
+ * @returns Element's position info
+ */
+ function _getOffset(element) {
+ var elementPosition = {};
+
+ if (element.tagName.toLowerCase() === 'body') {
+ //set width
+ elementPosition.width = element.clientWidth;
+ //set height
+ elementPosition.height = element.clientHeight;
+ } else {
+ //set width
+ elementPosition.width = element.offsetWidth;
+ //set height
+ elementPosition.height = element.offsetHeight;
+ }
+
+ //calculate element top and left
+ var _x = 0;
+ var _y = 0;
+ while (element && !isNaN(element.offsetLeft) && !isNaN(element.offsetTop)) {
+ _x += element.offsetLeft;
+ _y += element.offsetTop;
+ element = element.offsetParent;
+ }
+ //set top
+ elementPosition.top = _y;
+ //set left
+ elementPosition.left = _x;
+
+ return elementPosition;
+ }
+
+ /**
+ * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
+ * via: http://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically
+ *
+ * @param obj1
+ * @param obj2
+ * @returns obj3 a new object based on obj1 and obj2
+ */
+ function _mergeOptions(obj1, obj2) {
+ var obj3 = {};
+ for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
+ for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
+ return obj3;
+ }
+
+ var progressJs = function (targetElm) {
+ if (typeof (targetElm) === 'object') {
+ //Ok, create a new instance
+ return new ProgressJs(targetElm);
+
+ } else if (typeof (targetElm) === 'string') {
+ //select the target element with query selector
+ var targetElement = document.querySelectorAll(targetElm);
+
+ if (targetElement) {
+ return new ProgressJs(targetElement);
+ } else {
+ throw new Error('There is no element with given selector.');
+ }
+ } else {
+ return new ProgressJs(document.body);
+ }
+ };
+
+ /**
+ * Get correct transition callback
+ * Thanks @webinista: http://stackoverflow.com/a/9090128/375966
+ *
+ * @returns transition name
+ */
+ function whichTransitionEvent() {
+ var t;
+ var el = document.createElement('fakeelement');
+ var transitions = {
+ 'transition': 'transitionend',
+ 'OTransition': 'oTransitionEnd',
+ 'MozTransition': 'transitionend',
+ 'WebkitTransition': 'webkitTransitionEnd'
+ }
+
+ for (t in transitions) {
+ if (el.style[t] !== undefined) {
+ return transitions[t];
+ }
+ }
+ }
+
+ /**
+ * Current ProgressJs version
+ *
+ * @property version
+ * @type String
+ */
+ progressJs.version = VERSION;
+
+ //Prototype
+ progressJs.fn = ProgressJs.prototype = {
+ clone: function () {
+ return new ProgressJs(this);
+ },
+ setOption: function(option, value) {
+ this._options[option] = value;
+ return this;
+ },
+ setOptions: function(options) {
+ this._options = _mergeOptions(this._options, options);
+ return this;
+ },
+ start: function() {
+ _startProgress.call(this);
+ return this;
+ },
+ set: function(percent) {
+ _setPercent.call(this, percent);
+ return this;
+ },
+ increase: function(size) {
+ _increasePercent.call(this, size);
+ return this;
+ },
+ autoIncrease: function(size, millisecond) {
+ _autoIncrease.call(this, size, millisecond);
+ return this;
+ },
+ end: function() {
+ _end.call(this);
+ return this;
+ },
+ kill: function() {
+ _kill.call(this);
+ return this;
+ },
+ onbeforeend: function(providedCallback) {
+ if (typeof (providedCallback) === 'function') {
+ this._onBeforeEndCallback = providedCallback;
+ } else {
+ throw new Error('Provided callback for onbeforeend was not a function');
+ }
+ return this;
+ },
+ onbeforestart: function(providedCallback) {
+ if (typeof (providedCallback) === 'function') {
+ this._onBeforeStartCallback = providedCallback;
+ } else {
+ throw new Error('Provided callback for onbeforestart was not a function');
+ }
+ return this;
+ },
+ onprogress: function(providedCallback) {
+ if (typeof (providedCallback) === 'function') {
+ this._onProgressCallback = providedCallback;
+ } else {
+ throw new Error('Provided callback for onprogress was not a function');
+ }
+ return this;
+ }
+ };
+
+ exports.progressJs = progressJs;
+ return progressJs;
+ }));
+
+
+/***/ }
+
+/******/ });
\ No newline at end of file
diff --git "a/rainloop/rainloop/v/1.10.0.103/static/js/min/admin - \351\226\270\346\223\203\345\236\261\345\251\200_js" "b/rainloop/rainloop/v/1.10.0.103/static/js/min/admin - \351\226\270\346\223\203\345\236\261\345\251\200_js"
new file mode 100644
index 0000000..7b00e87
--- /dev/null
+++ "b/rainloop/rainloop/v/1.10.0.103/static/js/min/admin - \351\226\270\346\223\203\345\236\261\345\251\200_js"
@@ -0,0 +1,7 @@
+/* RainLoop Webmail (c) RainLoop Team | Licensed under AGPL v3 */
+!function(e){function t(n){if(i[n])return i[n].exports;var o=i[n]={exports:{},id:n,loaded:!1};return e[n].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var i={};return t.m=e,t.c=i,t.p="rainloop/v/0.0.0/static/js/min/",t(0)}([function(e,t,i){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}var o=i(77),s=n(o),r=i(22),a=n(r);(0,s["default"])(a["default"])},function(e,t,i){!function(){"use strict";var t=null,n={},o=i(11),s=i(3),r=i(14),a=i(2),l=i(78),u=i(36),c=i(79),p=i(66),d=i(4),f=i(8);n.trim=r.trim,n.inArray=r.inArray,n.isArray=s.isArray,n.isObject=s.isObject,n.isFunc=s.isFunction,n.isUnd=s.isUndefined,n.isNull=s.isNull,n.emptyFunction=n.noop=function(){},n.silentTryCatch=function(e){try{e()}catch(t){}},n.isNormal=function(e){return!n.isUnd(e)&&!n.isNull(e)},n.windowResize=s.debounce(function(e){n.isUnd(e)?f.$win.resize():o.setTimeout(function(){f.$win.resize()},e)},50),n.windowResizeCallback=function(){n.windowResize()},n.isPosNumeric=function(e,t){return n.isNormal(e)?(n.isUnd(t)?0:!t)?/^[1-9]+[0-9]*$/.test(e.toString()):/^[0-9]*$/.test(e.toString()):!1},n.pInt=function(e,t){var i=n.isNormal(e)&&""!==e?o.parseInt(e,10):t||0;return o.isNaN(i)?t||0:i},n.pString=function(e){return n.isNormal(e)?""+e:""},n.pBool=function(e){return!!e},n.encodeURIComponent=function(e){return o.encodeURIComponent(e)},n.isNonEmptyArray=function(e){return n.isArray(e)&&0s;s++)n=i[s].split("="),t[o.decodeURIComponent(n[0])]=o.decodeURIComponent(n[1]);return t},n.mailToHelper=function(e,t){if(e&&"mailto:"===e.toString().substr(0,7).toLowerCase()){if(!t)return!0;e=e.toString().substr(7);var r=[],a=null,l=null,u={},c=i(30),p=e.replace(/\?.+$/,""),f=e.replace(/^[^\?]*\?/,""),h=function(e){return e?s.compact(s.map(o.decodeURIComponent(e).split(/[,]/),function(e){var t=new c;return t.mailsoParse(e),""!==t.email?t:null})):null};return r=h(p),u=n.simpleQueryParser(f),n.isUnd(u.cc)||(a=h(o.decodeURIComponent(u.cc))),n.isUnd(u.bcc)||(l=h(o.decodeURIComponent(u.bcc))),i(5).showScreenPopup(t,[d.ComposeType.Empty,null,r,a,l,n.isUnd(u.subject)?null:n.pString(o.decodeURIComponent(u.subject)),n.isUnd(u.body)?null:n.plainToHtml(n.pString(o.decodeURIComponent(u.body)))]),!0}return!1},n.rsaObject=function(e){return c&&e&&(null===t||t&&t.__sPublicKey!==e)&&o.crypto&&o.crypto.getRandomValues?(t=new c,t.setPublicKey(e),t.__sPublicKey=e):t=!1,t},n.rsaEncode=function(e,t){if(o.crypto&&o.crypto.getRandomValues&&t){var i=!1,s=n.rsaObject(t);if(s&&(i=s.encrypt(n.fakeMd5()+":"+e+":"+n.fakeMd5()),!1!==i&&n.isNormal(i)))return"rsa:xxx:"+i}return e},n.rsaEncode.supported=(o.crypto&&o.crypto.getRandomValues,!1),n.encodeHtml=function(e){return n.isNormal(e)?s.escape(e.toString()):""},n.splitPlainText=function(e,t){var i="",o="",s=e,r=0,a=0;for(t=n.isUnd(t)?100:t;s.length>t;)o=s.substring(0,t),r=o.lastIndexOf(" "),a=o.lastIndexOf("\n"),-1!==a&&(r=a),-1===r&&(r=t),i+=o.substring(0,r)+"\n",s=s.substring(r+1);return i+s},n.timeOutAction=function(){var e={};return function(t,i,s){n.isUnd(e[t])&&(e[t]=0),o.clearTimeout(e[t]),e[t]=o.setTimeout(i,s)}}(),n.timeOutActionSecond=function(){var e={};return function(t,i,n){e[t]||(e[t]=o.setTimeout(function(){i(),e[t]=0},n))}}(),n.hos=function(e,t){return e&&o.Object&&o.Object.hasOwnProperty?o.Object.hasOwnProperty.call(e,t):!1},n.inFocus=function(){return o.document.activeElement?(n.isUnd(o.document.activeElement.__inFocusCache)&&(o.document.activeElement.__inFocusCache=r(o.document.activeElement).is("input,textarea,iframe,.cke_editable")),!!o.document.activeElement.__inFocusCache):!1},n.removeInFocus=function(e){if(o.document&&o.document.activeElement&&o.document.activeElement.blur){var t=r(o.document.activeElement);if(t.is("input,textarea"))o.document.activeElement.blur();else if(e)try{o.document.activeElement.blur()}catch(i){}}},n.removeSelection=function(){if(o&&o.getSelection){var e=o.getSelection();e&&e.removeAllRanges&&e.removeAllRanges()}else o.document&&o.document.selection&&o.document.selection.empty&&o.document.selection.empty()},n.replySubjectAdd=function(e,t){e=n.trim(e.toUpperCase()),t=n.trim(t.replace(/[\s]+/g," "));var i=!1,o=[],r="RE"===e,a="FWD"===e,l=!a;return""!==t&&s.each(t.split(":"),function(e){var t=n.trim(e);i||!/^(RE|FWD)$/i.test(t)&&!/^(RE|FWD)[\[\(][\d]+[\]\)]$/i.test(t)?(o.push(e),i=!0):(r||(r=!!/^RE/i.test(t)),a||(a=!!/^FWD/i.test(t)))}),l?r=!1:a=!1,n.trim((l?"Re: ":"Fwd: ")+(r?"Re: ":"")+(a?"Fwd: ":"")+n.trim(o.join(":")))},n.roundNumber=function(e,t){return o.Math.round(e*o.Math.pow(10,t))/o.Math.pow(10,t)},n.friendlySize=function(e){return e=n.pInt(e),e>=1073741824?n.roundNumber(e/1073741824,1)+"GB":e>=1048576?n.roundNumber(e/1048576,1)+"MB":e>=1024?n.roundNumber(e/1024,0)+"KB":e+"B"},n.log=function(e){o.console&&o.console.log&&o.console.log(e)},n.delegateRun=function(e,t,i,o){e&&e[t]&&(o=n.pInt(o),0>=o?e[t].apply(e,n.isArray(i)?i:[]):s.delay(function(){e[t].apply(e,n.isArray(i)?i:[])},o))},n.kill_CtrlA_CtrlS=function(e){if(e=e||o.event,e&&e.ctrlKey&&!e.shiftKey&&!e.altKey){var t=e.target||e.srcElement,i=e.keyCode||e.which;if(i===d.EventKeyCode.S)return void e.preventDefault();if(i===d.EventKeyCode.A){if(t&&("true"==""+t.contentEditable||t.tagName&&t.tagName.match(/INPUT|TEXTAREA/i)))return;o.getSelection?o.getSelection().removeAllRanges():o.document.selection&&o.document.selection.clear&&o.document.selection.clear(),e.preventDefault()}}},n.createCommand=function(e,t,i){var o=n.emptyFunction,s=function(){return o&&o.canExecute&&o.canExecute()&&t.apply(e,Array.prototype.slice.call(arguments)),!1};return o=t?s:n.emptyFunction,o.enabled=a.observable(!0),i=n.isUnd(i)?!0:i,n.isFunc(i)?o.canExecute=a.computed(function(){return o.enabled()&&i.call(e)}):o.canExecute=a.computed(function(){return o.enabled()&&!!i}),o},n.convertThemeName=s.memoize(function(e){return"@custom"===e.substr(-7)&&(e=n.trim(e.substring(0,e.length-7))),n.trim(e.replace(/[^a-zA-Z0-9]+/g," ").replace(/([A-Z])/g," $1").replace(/[\s]+/g," "))}),n.quoteName=function(e){return e.replace(/["]/g,'\\"')},n.microtime=function(){return(new o.Date).getTime()},n.timestamp=function(){return o.Math.round(n.microtime()/1e3)},n.convertLangName=function(e,t){return i(6).i18n("LANGS_NAMES"+(!0===t?"_EN":"")+"/LANG_"+e.toUpperCase().replace(/[^a-zA-Z0-9]+/g,"_"),null,e)},n.fakeMd5=function(e){var t="",i="0123456789abcdefghijklmnopqrstuvwxyz";for(e=n.isUnd(e)?32:n.pInt(e);t.length ').appendTo("#rl-hidden")},n.defautOptionsAfterRender=function(e,t){t&&!n.isUnd(t.disabled)&&e&&r(e).toggleClass("disabled",t.disabled).prop("disabled",t.disabled)},n.windowPopupKnockout=function(e,t,s,l){var u=null,c=o.open(""),p="__OpenerApplyBindingsUid"+n.fakeMd5()+"__",d=r("#"+t);o[p]=function(){if(c&&c.document.body&&d&&d[0]){var t=r(c.document.body);r("#rl-content",t).html(d.html()),r("html",c.document).addClass("external "+r("html").attr("class")),i(6).i18nToNodes(t),e&&r("#rl-content",t)[0]&&a.applyBindings(e,r("#rl-content",t)[0]),o[p]=null,l(c)}},c.document.open(),c.document.write(''+n.encodeHtml(s)+'
'),c.document.close(),u=c.document.createElement("script"),u.type="text/javascript",u.innerHTML="if(window&&window.opener&&window.opener['"+p+"']){window.opener['"+p+"']();window.opener['"+p+"']=null}",c.document.getElementsByTagName("head")[0].appendChild(u)},n.settingsSaveHelperFunction=function(e,t,i,o){return i=i||null,o=n.isUnd(o)?1e3:n.pInt(o),function(n,r,a,l,u){t.call(i,r&&r.Result?d.SaveSettingsStep.TrueResult:d.SaveSettingsStep.FalseResult),e&&e.call(i,n,r,a,l,u),s.delay(function(){t.call(i,d.SaveSettingsStep.Idle)},o)}},n.settingsSaveHelperSimpleFunction=function(e,t){return n.settingsSaveHelperFunction(null,e,t,1e3)},n.settingsSaveHelperSubscribeFunction=function(e,t,i,o){return function(s){if(e){switch(i){default:s=n.pString(s);break;case"bool":case"boolean":s=s?"1":"0";break;case"int":case"integer":case"number":s=n.pInt(s);break;case"trim":s=n.trim(s)}var r={};r[t]=s,e.saveAdminConfig?e.saveAdminConfig(o||null,r):e.saveSettings&&e.saveSettings(o||null,r)}}},n.htmlToPlain=function(e){var t=0,i=0,o=0,a=0,l=0,u="",c=function(e){return e=n.trim(e),e="> "+e.replace(/\n/gm,"\n> "),e.replace(/(^|\n)([> ]+)/gm,function(){return arguments&&2]*>([\s\S\r\n]*)<\/div>/gim,p),e="\n"+r.trim(e)+"\n"),e}return""},d=function(){return arguments&&1 ").replace(/[\r]/gm,""):""},h=function(){return arguments&&1]*><\/p>/gi,"").replace(/]*>([\s\S\r\n\t]*)<\/pre>/gim,d).replace(/[\s]+/gm," ").replace(/((?:href|data)\s?=\s?)("[^"]+?"|'[^']+?')/gim,h).replace(/ ]*>/gim,"\n").replace(/<\/h[\d]>/gi,"\n").replace(/<\/p>/gi,"\n\n").replace(/ ]*>/gim,"\n").replace(/<\/ul>/gi,"\n").replace(/]*>/gim," * ").replace(/<\/li>/gi,"\n").replace(/<\/td>/gi,"\n").replace(/<\/tr>/gi,"\n").replace(/ ]*>/gim,"\n_______________________________\n\n").replace(/]*>([\s\S\r\n]*)<\/div>/gim,p).replace(/
]*>/gim,"\n__bq__start__\n").replace(/<\/blockquote>/gim,"\n__bq__end__\n").replace(/]*>([\s\S\r\n]*?)<\/a>/gim,g).replace(/<\/div>/gi,"\n").replace(/ /gi," ").replace(/"/gi,'"').replace(/<[^>]*>/gm,""),u=f.$div.html(u).text(),u=u.replace(/\n[ \t]+/gm,"\n").replace(/[\n]{3,}/gm,"\n\n").replace(/>/gi,">").replace(/</gi,"<").replace(/&/gi,"&"),u=n.splitPlainText(n.trim(u)),t=0,l=800;l>0&&(l--,i=u.indexOf("__bq__start__",t),i>-1);)o=u.indexOf("__bq__start__",i+5),a=u.indexOf("__bq__end__",i+5),(-1===o||o>a)&&a>i?(u=u.substring(0,i)+c(u.substring(i+13,a))+u.substring(a+11),t=0):t=o>-1&&a>o?o-1:0;return u=u.replace(/__bq__start__/gm,"").replace(/__bq__end__/gm,"")},n.plainToHtml=function(e,t){e=e.toString().replace(/\r/g,""),t=n.isUnd(t)?!1:!!t;var i=!1,o=!0,s=!0,r=[],a="",l=0,u=e.split("\n");do{for(o=!1,r=[],l=0;l"===a.substr(0,1),s&&!i?(o=!0,i=!0,r.push("~~~blockquote~~~"),r.push(a.substr(1))):!s&&i?""!==a?(i=!1,r.push("~~~/blockquote~~~"),r.push(a)):r.push(a):s&&i?r.push(a.substr(1)):r.push(a);i&&(i=!1,r.push("~~~/blockquote~~~")),u=r}while(o);return e=u.join("\n"),e=e.replace(/&/g,"&").replace(/>/g,">").replace(/").replace(/[\s]*~~~\/blockquote~~~/g," ").replace(/\u200C([\s\S]*)\u200C/g,"$1").replace(/\n/g,"
"),t?n.findEmailAndLinks(e):e},o.rainloop_Utils_htmlToPlain=n.htmlToPlain,o.rainloop_Utils_plainToHtml=n.plainToHtml,n.findEmailAndLinks=function(e){return e=l.link(e,{newWindow:!0,stripPrefix:!1,urls:!0,email:!0,twitter:!1,replaceFn:function(e,t){return!(e&&t&&"url"===t.getType()&&t.matchedText&&0!==t.matchedText.indexOf("http"))}})},n.resizeAndCrop=function(e,t,i){var n=new o.Image;n.onload=function(){var e=[0,0],n=o.document.createElement("canvas"),s=n.getContext("2d");n.width=t,n.height=t,e=this.width>this.height?[this.width-this.height,0]:[0,this.height-this.width],s.fillStyle="#fff",s.fillRect(0,0,t,t),s.drawImage(this,e[0]/2,e[1]/2,this.width-e[0],this.height-e[1],0,0,t,t),i(n.toDataURL("image/jpeg"))},n.src=e},n.folderListOptionsBuilder=function(e,t,i,s,r,a,l,u,c,p){var f=null,h=!1,g=0,m=0,b=" ",v=[];for(p=n.isUnd(p)?!1:!!p,c=n.isNormal(c)?c:0
g;g++)v.push({id:s[g][0],name:s[g][1],system:!1,seporator:!1,disabled:!1});for(h=!0,g=0,m=e.length;m>g;g++)f=e[g],(l?l.call(null,f):!0)&&(h&&0g;g++)f=t[g],!f.subScribed()&&f.existen&&!p||!f.selectable&&!f.hasSubScribedSubfolders()||(l?l.call(null,f):!0)&&(d.FolderType.User!==f.type()&&c&&!f.hasSubScribedSubfolders()||(h&&01||u>0&&l>u){for(l>u?(c(u),i=u,s=u):((3>=l||l>=u-2)&&(r+=2),c(l),i=l,s=l);r>0;)if(i-=1,s+=1,i>0&&(c(i,!1),r--),u>=s)c(s,!0),r--;else if(0>=i)break;3===i?c(2,!1):i>3&&c(o.Math.round((i-1)/2),!1,"..."),u-2===s?c(u-1,!0):u-2>s&&c(o.Math.round((u+s)/2),!0,"..."),i>1&&c(1,!1),u>s&&c(u,!0)}return a}},n.selectElement=function(e){var t,i;o.getSelection?(t=o.getSelection(),t.removeAllRanges(),i=o.document.createRange(),i.selectNodeContents(e),t.addRange(i)):o.document.selection&&(i=o.document.body.createTextRange(),i.moveToElementText(e),i.select())},n.detectDropdownVisibility=s.debounce(function(){f.dropdownVisibility(!!s.find(f.aBootstrapDropdowns,function(e){return e.hasClass("open")}))},50),n.triggerAutocompleteInputChange=function(e){var t=function(){r(".checkAutocomplete").trigger("change")};(n.isUnd(e)?1:!e)?t():s.delay(t,100)},n.setHeadViewport=function(e){var t=[];s.each(e,function(e,i){t.push(""+e+"="+i)}),r("#rl-head-viewport").attr("content",t.join(", "))},n.getFileExtension=function(e){e=n.trim(e).toLowerCase();var t=e.split(".").pop();return t===e?"":t},n.configurationScriptTagCache={},n.getConfigurationFromScriptTag=function(e){var t={};n.configurationScriptTagCache[e]||(n.configurationScriptTagCache[e]=r('script[type="application/json"][data-configuration="'+e+'"]'));try{t=u.parse(n.configurationScriptTagCache[e].text())}catch(i){}return t},n.mimeContentType=function(e){var t="",i="application/octet-stream";return e=n.trim(e).toLowerCase(),"winmail.dat"===e?"application/ms-tnef":(t=n.getFileExtension(e),t&&0'),i.after(s),i.remove()),s&&s[0]&&(s.attr("data-href",a).attr("data-theme",e[0]),s[0].styleSheet&&!n.isUnd(s[0].styleSheet.cssText)?s[0].styleSheet.cssText=e[1]:s.text(e[1])),t(d.SaveSettingsStep.TrueResult))}).always(function(){n.__themeTimer=o.setTimeout(function(){t(d.SaveSettingsStep.Idle)},1e3),n.__themeAjax=null}))},n.substr=o.String.substr,"b"!=="ab".substr(-1)&&(n.substr=function(e,t,i){return 0>t&&(t=e.length+t),e.substr(t,i)}),e.exports=n}()},function(e,t,i){!function(t){"use strict";var n=i(11),o=i(3),s=i(14),r=i(36),a=i(54),l=function(e){t.utils.domNodeDisposal.addDisposeCallback(e,function(){e&&e.__opentip&&e.__opentip.deactivate()})};t.bindingHandlers.updateWidth={init:function(e,i){var o=s(n),r=s(e),a=i(),l=function(){a(r.width()),n.setTimeout(function(){a(r.width())},500)};o.on("resize",l),l(),t.utils.domNodeDisposal.addDisposeCallback(e,function(){o.off("resize",l)})}},t.bindingHandlers.editor={init:function(e,n){var o=null,s=n(),r=function(){s&&s.__editor&&s.__editor.setHtmlOrPlain(s())},a=function(){s&&s.__editor&&s(s.__editor.getDataWithHtmlMark())},l=function(){s.__editor=o,r()},u=i(45);t.isObservable(s)&&u&&(o=new u(e,a,l,a),s.__fetchEditorValue=a,s.subscribe(r))}},t.bindingHandlers.json={init:function(e,i){s(e).text(r.stringify(t.unwrap(i())))},update:function(e,i){s(e).text(r.stringify(t.unwrap(i())))}},t.bindingHandlers.scrollerShadows={init:function(e){var i=8,r=s(e),a=s(n),l=r.find("[data-scroller-shadows-content]")[0]||null,u=o.throttle(function(){r.toggleClass("scroller-shadow-top",i0&&(c+=o.pInt(a[2]),u=r.$win.height()-c,u>l&&(l=u),s(e).css({height:l,"min-height":l}))}},t.bindingHandlers.appendDom={update:function(e,i){s(e).hide().empty().append(t.unwrap(i())).show()}},t.bindingHandlers.draggable={init:function(e,o,r){var a=i(8),l=i(1);if(!a.bMobileDevice){var u=100,c=3,p=r(),d=p&&p.droppableSelector?p.droppableSelector:"",f={distance:20,handle:".dragHandle",cursorAt:{top:22,left:3},refreshPositions:!0,scroll:!0};d&&(f.drag=function(e){s(d).each(function(){var t=null,i=null,o=s(this),r=o.offset(),a=r.top+o.height();n.clearInterval(o.data("timerScroll")),o.data("timerScroll",!1),e.pageX>=r.left&&e.pageX<=r.left+o.width()&&(e.pageY>=a-u&&e.pageY<=a&&(t=function(){o.scrollTop(o.scrollTop()+c),l.windowResize()},o.data("timerScroll",n.setInterval(t,10)),t()),e.pageY>=r.top&&e.pageY<=r.top+u&&(i=function(){o.scrollTop(o.scrollTop()-c),l.windowResize()},o.data("timerScroll",n.setInterval(i,10)),i()))})},f.stop=function(){s(d).each(function(){n.clearInterval(s(this).data("timerScroll")),s(this).data("timerScroll",!1)})}),f.helper=function(e){return o()(e&&e.target?t.dataFor(e.target):null)},s(e).draggable(f).on("mousedown.koDraggable",function(){l.removeInFocus()}),t.utils.domNodeDisposal.addDisposeCallback(e,function(){s(e).off("mousedown.koDraggable").draggable("destroy")})}}},t.bindingHandlers.droppable={init:function(e,n,o){var r=i(8);if(!r.bMobileDevice){var a=n(),l=o(),u=l&&l.droppableOver?l.droppableOver:null,c=l&&l.droppableOut?l.droppableOut:null,p={tolerance:"pointer",hoverClass:"droppableHover"};a&&(p.drop=function(e,t){a(e,t)},u&&(p.over=function(e,t){u(e,t)}),c&&(p.out=function(e,t){c(e,t)}),s(e).droppable(p),t.utils.domNodeDisposal.addDisposeCallback(e,function(){s(e).droppable("destroy")}))}}},t.bindingHandlers.nano={init:function(e){var t=i(8);t.bDisableNanoScroll||s(e).addClass("nano").nanoScroller({iOSNativeScrolling:!1,preventPageScrolling:!0})}},t.bindingHandlers.saveTrigger={init:function(e){var t=s(e);t.data("save-trigger-type",t.is("input[type=text],input[type=email],input[type=password],select,textarea")?"input":"custom"),"custom"===t.data("save-trigger-type")?t.append(' ').addClass("settings-saved-trigger"):t.addClass("settings-saved-trigger-input")},update:function(e,i){var n=t.unwrap(i()),o=s(e);if("custom"===o.data("save-trigger-type"))switch(n.toString()){case"1":o.find(".animated,.error").hide().removeClass("visible").end().find(".success").show().addClass("visible");break;case"0":o.find(".animated,.success").hide().removeClass("visible").end().find(".error").show().addClass("visible");break;case"-2":o.find(".error,.success").hide().removeClass("visible").end().find(".animated").show().addClass("visible");break;default:o.find(".animated").hide().end().find(".error,.success").removeClass("visible")}else switch(n.toString()){case"1":o.addClass("success").removeClass("error");break;case"0":o.addClass("error").removeClass("success");break;case"-2":break;default:o.removeClass("error success")}}},t.bindingHandlers.emailsTags={init:function(e,t,n){var r=i(1),a=i(30),l=s(e),u=t(),c=n(),p=c.autoCompleteSource||null,d=function(e){u&&u.focused&&u.focused(!!e)};l.inputosaurus({parseOnBlur:!0,allowDragAndDrop:!0,focusCallback:d,inputDelimiters:[",",";","\n"],autoCompleteSource:p,parseHook:function(e){return o.map(e,function(e){var t=r.trim(e),i=null;return""!==t?(i=new a,i.mailsoParse(t),[i.toLine(!1),i]):[t,null]})},change:o.bind(function(e){l.data("EmailsTagsValue",e.target.value),u(e.target.value)},this)}),u&&u.focused&&u.focused.subscribe&&u.focused.subscribe(function(e){l.inputosaurus(e?"focus":"blur")})},update:function(e,i){var n=s(e),o=i(),r=t.unwrap(o);n.data("EmailsTagsValue")!==r&&(n.val(r),n.data("EmailsTagsValue",r),n.inputosaurus("refresh"))}},t.bindingHandlers.command={init:function(e,i,n,o){var r=s(e),a=i();if(!a||!a.enabled||!a.canExecute)throw new Error("You are not using command function");r.addClass("command"),t.bindingHandlers[r.is("form")?"submit":"click"].init.apply(o,arguments)},update:function(e,t){var i=!0,n=s(e),o=t();i=o.enabled(),n.toggleClass("command-not-enabled",!i),i&&(i=o.canExecute(),n.toggleClass("command-can-not-be-execute",!i)),n.toggleClass("command-disabled disable disabled",!i).toggleClass("no-disabled",!!i),(n.is("input")||n.is("button"))&&n.prop("disabled",!i)}},t.extenders.trimmer=function(e){var n=i(1),o=t.computed({read:e,write:function(t){e(n.trim(t.toString()))},owner:this});return o(e()),o},t.extenders.posInterer=function(e,n){var o=i(1),s=t.computed({read:e,write:function(t){var i=o.pInt(t.toString(),n);0>=i&&(i=n),i===e()&&""+i!=""+t&&e(i+1),e(i)}});return s(e()),s},t.extenders.limitedList=function(e,n){var o=i(1),s=t.computed({read:e,write:function(i){var s=t.unwrap(e),r=t.unwrap(n);o.isNonEmptyArray(r)?-1 ").addClass("rl-view-model").addClass("RL-"+r.viewModelTemplate()).hide(),d.appendTo(p),r.viewModelDom=d,e.__dom=d,"Popups"===a&&(r.cancelCommand=r.closeCommand=c.createCommand(r,function(){i.hideScreenPopup(e)}),r.modalVisibility.subscribe(function(e){var t=this;e?(this.viewModelDom.show(),this.storeAndSetKeyScope(),l.popupVisibilityNames.push(this.viewModelName),r.viewModelDom.css("z-index",3e3+l.popupVisibilityNames().length+10),this.onShowTrigger&&this.onShowTrigger(!this.onShowTrigger()),c.delegateRun(this,"onShowWithDelay",[],500)):(c.delegateRun(this,"onHide"),c.delegateRun(this,"onHideWithDelay",[],500),this.onHideTrigger&&this.onHideTrigger(!this.onHideTrigger()),this.restoreKeyScope(),n.each(this.viewModelNames,function(e){u.runHook("view-model-on-hide",[e,t])}),l.popupVisibilityNames.remove(this.viewModelName),r.viewModelDom.css("z-index",2e3),n.delay(function(){t.viewModelDom.hide()},300))},r)),n.each(e.__names,function(e){u.runHook("view-model-pre-build",[e,r,d])}),s.applyBindingAccessorsToNode(d[0],{translatorInit:!0,template:function(){return{name:r.viewModelTemplate()}}},r),c.delegateRun(r,"onBuild",[d]),r&&"Popups"===a&&r.registerPopupKeyDown(),n.each(e.__names,function(e){u.runHook("view-model-post-build",[e,r,d])})):c.log("Cannot find view model position: "+a)}return e?e.__vm:null},t.prototype.hideScreenPopup=function(e){e&&e.__vm&&e.__dom&&e.__vm.modalVisibility(!1)},t.prototype.showScreenPopup=function(e,t){e&&(this.buildViewModel(e),e.__vm&&e.__dom&&(c.delegateRun(e.__vm,"onBeforeShow",t||[]),e.__vm.modalVisibility(!0),c.delegateRun(e.__vm,"onShow",t||[]),n.each(e.__names,function(i){u.runHook("view-model-on-show",[i,e.__vm,t||[]])})))},t.prototype.isPopupVisible=function(e){return e&&e.__vm?e.__vm.modalVisibility():!1},t.prototype.screenOnRoute=function(e,t){var i=this,o=null,s=!1,r=null;""===c.pString(e)&&(e=this.sDefaultScreenName),""!==e&&(o=this.screen(e),o||(o=this.screen(this.sDefaultScreenName),o&&(t=e+"/"+t,e=this.sDefaultScreenName)),o&&o.__started&&(s=this.oCurrentScreen&&o===this.oCurrentScreen,o.__builded||(o.__builded=!0,c.isNonEmptyArray(o.viewModels())&&n.each(o.viewModels(),function(e){this.buildViewModel(e,o)},this),c.delegateRun(o,"onBuild")),n.defer(function(){i.oCurrentScreen&&!s&&(c.delegateRun(i.oCurrentScreen,"onHide"),c.delegateRun(i.oCurrentScreen,"onHideWithDelay",[],500),i.oCurrentScreen.onHideTrigger&&i.oCurrentScreen.onHideTrigger(!i.oCurrentScreen.onHideTrigger()),c.isNonEmptyArray(i.oCurrentScreen.viewModels())&&n.each(i.oCurrentScreen.viewModels(),function(e){e.__vm&&e.__dom&&"Popups"!==e.__vm.viewModelPosition()&&(e.__dom.hide(),e.__vm.viewModelVisibility(!1),c.delegateRun(e.__vm,"onHide"),c.delegateRun(e.__vm,"onHideWithDelay",[],500),e.__vm.onHideTrigger&&e.__vm.onHideTrigger(!e.__vm.onHideTrigger()))})),i.oCurrentScreen=o,i.oCurrentScreen&&!s&&(c.delegateRun(i.oCurrentScreen,"onShow"),i.oCurrentScreen.onShowTrigger&&i.oCurrentScreen.onShowTrigger(!i.oCurrentScreen.onShowTrigger()),u.runHook("screen-on-show",[i.oCurrentScreen.screenName(),i.oCurrentScreen]),c.isNonEmptyArray(i.oCurrentScreen.viewModels())&&n.each(i.oCurrentScreen.viewModels(),function(e){e.__vm&&e.__dom&&"Popups"!==e.__vm.viewModelPosition()&&(c.delegateRun(e.__vm,"onBeforeShow"),e.__dom.show(),e.__vm.viewModelVisibility(!0),c.delegateRun(e.__vm,"onShow"),e.__vm.onShowTrigger&&e.__vm.onShowTrigger(!e.__vm.onShowTrigger()),c.delegateRun(e.__vm,"onShowWithDelay",[],200),n.each(e.__names,function(t){u.runHook("view-model-on-show",[t,e.__vm])}))},i)),r=o.__cross?o.__cross():null,r&&r.parse(t)})))},t.prototype.startScreens=function(e){o("#rl-content").css({visibility:"hidden"}),n.each(e,function(e){if(e){var t=new e,i=t?t.screenName():"";t&&""!==i&&(""===this.sDefaultScreenName&&(this.sDefaultScreenName=i),this.oScreens[i]=t)}},this),n.each(this.oScreens,function(e){e&&!e.__started&&e.__start&&(e.__started=!0,e.__start(),u.runHook("screen-pre-start",[e.screenName(),e]),c.delegateRun(e,"onStart"),u.runHook("screen-post-start",[e.screenName(),e]))},this);var t=a.create();t.addRoute(/^([a-zA-Z0-9\-]*)\/?(.*)$/,n.bind(this.screenOnRoute,this)),r.initialized.add(t.parse,t),r.changed.add(t.parse,t),r.init(),o("#rl-content").css({visibility:"visible"}),n.delay(function(){l.$html.removeClass("rl-started-trigger").addClass("rl-started")},100),n.delay(function(){l.$html.addClass("rl-started-delay")},200)},t.prototype.setHash=function(e,t,i){e="#"===e.substr(0,1)?e.substr(1):e,e="/"===e.substr(0,1)?e.substr(1):e,i=c.isUnd(i)?!1:!!i,(c.isUnd(t)?1:!t)?(r.changed.active=!0,r[i?"replaceHash":"setHash"](e),r.setHash(e)):(r.changed.active=!1,r[i?"replaceHash":"setHash"](e),r.changed.active=!0)},e.exports=new t}()},function(e,t,i){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var s=i(13),r=i(2),a=n(r),l=i(4),u=i(1),c=n(u),p=i(8),d=n(p),f=function(){function e(){o(this,e),this.data={},this.notificationI18N={},this.data=s.window.rainloopI18N||{},this.trigger=a["default"].observable(!1),this.i18n=s._.bind(this.i18n,this),this.init()}return e.prototype.i18n=function(e,t,i){var n="",o=this.data[e];if(s._.isUndefined(o)&&(o=s._.isUndefined(i)?e:i),!s._.isUndefined(t)&&!s._.isNull(t))for(n in t)s._.has(t,n)&&(o=o.replace("%"+n+"%",t[n]));return o},e.prototype.i18nToNode=function(e){var t=(0,s.$)(e),i=t.data("i18n");if(i)if("["===i.substr(0,1))switch(i.substr(0,6)){case"[html]":t.html(this.i18n(i.substr(6)));break;case"[place":t.attr("placeholder",this.i18n(i.substr(13)));break;case"[title":t.attr("title",this.i18n(i.substr(7)))}else t.text(this.i18n(i))},e.prototype.i18nToNodes=function(e){var t=this,i=arguments.length<=1||void 0===arguments[1]?!1:arguments[1];s._.defer(function(){(0,s.$)("[data-i18n]",e).each(function(e,i){t.i18nToNode(i)}),i&&d["default"].bAnimationSupported&&(0,s.$)(".i18n-animation[data-i18n]",e).letterfx({fx:"fall fade",backwards:!1,timing:50,fx_duration:"50ms",letter_end:"restore",element_end:"restore"})})},e.prototype.reloadData=function(){s.window.rainloopI18N&&(this.data=s.window.rainloopI18N||{},this.i18nToNodes(s.window.document,!0),i(26).reload(),this.trigger(!this.trigger())),s.window.rainloopI18N=null},e.prototype.initNotificationLanguage=function(){var e=this,t=[[l.Notification.InvalidToken,"NOTIFICATIONS/INVALID_TOKEN"],[l.Notification.InvalidToken,"NOTIFICATIONS/INVALID_TOKEN"],[l.Notification.AuthError,"NOTIFICATIONS/AUTH_ERROR"],[l.Notification.AccessError,"NOTIFICATIONS/ACCESS_ERROR"],[l.Notification.ConnectionError,"NOTIFICATIONS/CONNECTION_ERROR"],[l.Notification.CaptchaError,"NOTIFICATIONS/CAPTCHA_ERROR"],[l.Notification.SocialFacebookLoginAccessDisable,"NOTIFICATIONS/SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE"],[l.Notification.SocialTwitterLoginAccessDisable,"NOTIFICATIONS/SOCIAL_TWITTER_LOGIN_ACCESS_DISABLE"],[l.Notification.SocialGoogleLoginAccessDisable,"NOTIFICATIONS/SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE"],[l.Notification.DomainNotAllowed,"NOTIFICATIONS/DOMAIN_NOT_ALLOWED"],[l.Notification.AccountNotAllowed,"NOTIFICATIONS/ACCOUNT_NOT_ALLOWED"],[l.Notification.AccountTwoFactorAuthRequired,"NOTIFICATIONS/ACCOUNT_TWO_FACTOR_AUTH_REQUIRED"],[l.Notification.AccountTwoFactorAuthError,"NOTIFICATIONS/ACCOUNT_TWO_FACTOR_AUTH_ERROR"],[l.Notification.CouldNotSaveNewPassword,"NOTIFICATIONS/COULD_NOT_SAVE_NEW_PASSWORD"],[l.Notification.CurrentPasswordIncorrect,"NOTIFICATIONS/CURRENT_PASSWORD_INCORRECT"],[l.Notification.NewPasswordShort,"NOTIFICATIONS/NEW_PASSWORD_SHORT"],[l.Notification.NewPasswordWeak,"NOTIFICATIONS/NEW_PASSWORD_WEAK"],[l.Notification.NewPasswordForbidden,"NOTIFICATIONS/NEW_PASSWORD_FORBIDDENT"],[l.Notification.ContactsSyncError,"NOTIFICATIONS/CONTACTS_SYNC_ERROR"],[l.Notification.CantGetMessageList,"NOTIFICATIONS/CANT_GET_MESSAGE_LIST"],[l.Notification.CantGetMessage,"NOTIFICATIONS/CANT_GET_MESSAGE"],[l.Notification.CantDeleteMessage,"NOTIFICATIONS/CANT_DELETE_MESSAGE"],[l.Notification.CantMoveMessage,"NOTIFICATIONS/CANT_MOVE_MESSAGE"],[l.Notification.CantCopyMessage,"NOTIFICATIONS/CANT_MOVE_MESSAGE"],[l.Notification.CantSaveMessage,"NOTIFICATIONS/CANT_SAVE_MESSAGE"],[l.Notification.CantSendMessage,"NOTIFICATIONS/CANT_SEND_MESSAGE"],[l.Notification.InvalidRecipients,"NOTIFICATIONS/INVALID_RECIPIENTS"],[l.Notification.CantSaveFilters,"NOTIFICATIONS/CANT_SAVE_FILTERS"],[l.Notification.CantGetFilters,"NOTIFICATIONS/CANT_GET_FILTERS"],[l.Notification.FiltersAreNotCorrect,"NOTIFICATIONS/FILTERS_ARE_NOT_CORRECT"],[l.Notification.CantCreateFolder,"NOTIFICATIONS/CANT_CREATE_FOLDER"],[l.Notification.CantRenameFolder,"NOTIFICATIONS/CANT_RENAME_FOLDER"],[l.Notification.CantDeleteFolder,"NOTIFICATIONS/CANT_DELETE_FOLDER"],[l.Notification.CantDeleteNonEmptyFolder,"NOTIFICATIONS/CANT_DELETE_NON_EMPTY_FOLDER"],[l.Notification.CantSubscribeFolder,"NOTIFICATIONS/CANT_SUBSCRIBE_FOLDER"],[l.Notification.CantUnsubscribeFolder,"NOTIFICATIONS/CANT_UNSUBSCRIBE_FOLDER"],[l.Notification.CantSaveSettings,"NOTIFICATIONS/CANT_SAVE_SETTINGS"],[l.Notification.CantSavePluginSettings,"NOTIFICATIONS/CANT_SAVE_PLUGIN_SETTINGS"],[l.Notification.DomainAlreadyExists,"NOTIFICATIONS/DOMAIN_ALREADY_EXISTS"],[l.Notification.CantInstallPackage,"NOTIFICATIONS/CANT_INSTALL_PACKAGE"],[l.Notification.CantDeletePackage,"NOTIFICATIONS/CANT_DELETE_PACKAGE"],[l.Notification.InvalidPluginPackage,"NOTIFICATIONS/INVALID_PLUGIN_PACKAGE"],[l.Notification.UnsupportedPluginPackage,"NOTIFICATIONS/UNSUPPORTED_PLUGIN_PACKAGE"],[l.Notification.LicensingServerIsUnavailable,"NOTIFICATIONS/LICENSING_SERVER_IS_UNAVAILABLE"],[l.Notification.LicensingExpired,"NOTIFICATIONS/LICENSING_EXPIRED"],[l.Notification.LicensingBanned,"NOTIFICATIONS/LICENSING_BANNED"],[l.Notification.DemoSendMessageError,"NOTIFICATIONS/DEMO_SEND_MESSAGE_ERROR"],[l.Notification.DemoAccountError,"NOTIFICATIONS/DEMO_ACCOUNT_ERROR"],[l.Notification.AccountAlreadyExists,"NOTIFICATIONS/ACCOUNT_ALREADY_EXISTS"],[l.Notification.AccountDoesNotExist,"NOTIFICATIONS/ACCOUNT_DOES_NOT_EXIST"],[l.Notification.MailServerError,"NOTIFICATIONS/MAIL_SERVER_ERROR"],[l.Notification.InvalidInputArgument,"NOTIFICATIONS/INVALID_INPUT_ARGUMENT"],[l.Notification.UnknownNotification,"NOTIFICATIONS/UNKNOWN_ERROR"],[l.Notification.UnknownError,"NOTIFICATIONS/UNKNOWN_ERROR"]];this.notificationI18N=this.notificationI18N||{},t.forEach(function(t){e.notificationI18N[t[0]]=e.i18n(t[1])})},e.prototype.initOnStartOrLangChange=function(e,t){var i=arguments.length<=2||void 0===arguments[2]?null:arguments[2];e&&e.call(t),i?this.trigger.subscribe(function(){e&&e.call(t),i.call(t)}):e&&this.trigger.subscribe(e,t)},e.prototype.getNotification=function(e){var t=arguments.length<=1||void 0===arguments[1]?"":arguments[1],i=arguments.length<=2||void 0===arguments[2]?null:arguments[2];return e=s.window.parseInt(e,10)||0,l.Notification.ClientViewError===e&&t?t:(i=i?s.window.parseInt(i,10)||0:0,s._.isUndefined(this.notificationI18N[e])?i&&s._.isUndefined(this.notificationI18N[i])?this.notificationI18N[i]:"":this.notificationI18N[e])},e.prototype.getNotificationFromResponse=function(e){var t=arguments.length<=1||void 0===arguments[1]?l.Notification.UnknownNotification:arguments[1];return e&&e.ErrorCode?this.getNotification(c["default"].pInt(e.ErrorCode),e.ErrorMessage||""):this.getNotification(t)},e.prototype.getUploadErrorDescByCode=function(e){var t="";switch(s.window.parseInt(e,10)||0){case l.UploadErrorCode.FileIsTooBig:t=this.i18n("UPLOAD/ERROR_FILE_IS_TOO_BIG");break;case l.UploadErrorCode.FilePartiallyUploaded:t=this.i18n("UPLOAD/ERROR_FILE_PARTIALLY_UPLOADED");break;case l.UploadErrorCode.FileNoUploaded:t=this.i18n("UPLOAD/ERROR_NO_FILE_UPLOADED");break;case l.UploadErrorCode.MissingTempFolder:t=this.i18n("UPLOAD/ERROR_MISSING_TEMP_FOLDER");break;case l.UploadErrorCode.FileOnSaveingError:t=this.i18n("UPLOAD/ERROR_ON_SAVING_FILE");break;case l.UploadErrorCode.FileType:t=this.i18n("UPLOAD/ERROR_FILE_TYPE");break;default:t=this.i18n("UPLOAD/ERROR_UNKNOWN")}return t},e.prototype.reload=function(e,t,n,o){var r=this,a=c["default"].microtime();d["default"].$html.addClass("rl-changing-language"),s.$.ajax({url:i(12).langLink(t,e),dataType:"script",cache:!0}).fail(o||c["default"].emptyFunction).done(function(){s._.delay(function(){r.reloadData(),(n||c["default"].emptyFunction)();var e=-1 "),t.$win.__sizes=[0,0],t.startMicrotime=(new n.Date).getTime(),t.community=!0,t.dropdownVisibility=r.observable(!1).extend({rateLimit:0}),t.useKeyboardShortcuts=r.observable(!0),t.iAjaxErrorCount=0,t.iTokenErrorCount=0,t.iMessageBodyCacheCount=0,t.bUnload=!1,t.sUserAgent="navigator"in n&&"userAgent"in n.navigator&&n.navigator.userAgent.toLowerCase()||"",t.bIE=t.sUserAgent.indexOf("msie")>-1,t.bChrome=t.sUserAgent.indexOf("chrome")>-1,t.bSafari=!t.bChrome&&t.sUserAgent.indexOf("safari")>-1,t.bMobileDevice=/android/i.test(t.sUserAgent)||/iphone/i.test(t.sUserAgent)||/ipod/i.test(t.sUserAgent)||/ipad/i.test(t.sUserAgent)||/blackberry/i.test(t.sUserAgent),t.bDisableNanoScroll=t.bMobileDevice,t.bAllowPdfPreview=!t.bMobileDevice,t.bAnimationSupported=!t.bMobileDevice&&t.$html.hasClass("csstransitions")&&t.$html.hasClass("cssanimations"),t.bXMLHttpRequestSupported=!!n.XMLHttpRequest,t.__APP__=null,t.oHtmlEditorDefaultConfig={title:!1,stylesSet:!1,customConfig:"",contentsCss:"",toolbarGroups:[{name:"spec"},{name:"styles"},{name:"basicstyles",groups:["basicstyles","cleanup","bidi"]},{name:"colors"},t.bMobileDevice?{}:{name:"paragraph",groups:["list","indent","blocks","align"]},{name:"links"},{name:"insert"},{name:"document",groups:["mode","document","doctools"]},{name:"others"}],removePlugins:"liststyle",removeButtons:"Format,Undo,Redo,Cut,Copy,Paste,Anchor,Strike,Subscript,Superscript,Image,SelectAll,Source",removeDialogTabs:"link:advanced;link:target;image:advanced;images:advanced",extraPlugins:"plain,signature",allowedContent:!0,extraAllowedContent:!0,fillEmptyBlocks:!1,ignoreEmptyParagraph:!0,disableNativeSpellChecker:!1,font_defaultLabel:"Arial",fontSize_defaultLabel:"13",fontSize_sizes:"10/10px;12/12px;13/13px;14/14px;16/16px;18/18px;20/20px;24/24px;28/28px;36/36px;48/48px"},t.oHtmlEditorLangsMap={bg_bg:"bg",de_de:"de",el_gr:"el",es_es:"es",fr_fr:"fr",hu_hu:"hu",is_is:"is",it_it:"it",ja_jp:"ja",ko_kr:"ko",lt_lt:"lt",lv_lv:"lv",nl_nl:"nl",bg_no:"no",pl_pl:"pl",pt_pt:"pt",pt_br:"pt-br",ro_ro:"ro",ru_ru:"ru",sk_sk:"sk",sl_si:"sl",sv_se:"sv",tr_tr:"tr",uk_ua:"ru",zh_tw:"zh",zh_cn:"zh-cn"},t.bAllowPdfPreview&&n.navigator&&n.navigator.mimeTypes&&(t.bAllowPdfPreview=!!o.find(n.navigator.mimeTypes,function(e){return e&&"application/pdf"===e.type}),t.bAllowPdfPreview||(t.bAllowPdfPreview="undefined"!=typeof n.navigator.mimeTypes["application/pdf"])),t.aBootstrapDropdowns=[],t.aViewModels={settings:[],"settings-removed":[],"settings-disabled":[]},t.leftPanelDisabled=r.observable(!1),t.leftPanelType=r.observable(""),t.leftPanelWidth=r.observable(0),t.popupVisibilityNames=r.observableArray([]),t.popupVisibility=r.computed(function(){return 00?"~"+r:"")}return t>1&&(o=o.replace(/[\/]+$/,""),o+="/p"+t),""!==i&&(o=o.replace(/[\/]+$/,""),o+="/"+s.window.encodeURI(i)),o},e.prototype.phpInfo=function(){return this.sServer+"Info"},e.prototype.langLink=function(e,t){return this.sServer+"/Lang/0/"+(t?"Admin":"App")+"/"+s.window.encodeURI(e)+"/"+this.sVersion+"/"},e.prototype.exportContactsVcf=function(){return this.sServer+"/Raw/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/ContactsVcf/"},e.prototype.exportContactsCsv=function(){return this.sServer+"/Raw/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/ContactsCsv/"},e.prototype.emptyContactPic=function(){return this.sStaticPrefix+"css/images/empty-contact.png"},e.prototype.sound=function(e){return this.sStaticPrefix+"sounds/"+e},e.prototype.themePreviewLink=function(e){var t=this.sVersionPrefix;return"@custom"===e.substr(-7)&&(e=a["default"].trim(e.substring(0,e.length-7)),t=this.sWebPrefix),t+"themes/"+s.window.encodeURI(e)+"/images/preview.png"},e.prototype.notificationMailIcon=function(){return this.sStaticPrefix+"css/images/icom-message-notification.png"},e.prototype.openPgpJs=function(){return this.sStaticPrefix+"js/min/openpgp.min.js"},e.prototype.openPgpWorkerJs=function(){return this.sStaticPrefix+"js/min/openpgp.worker.min.js"},e.prototype.openPgpWorkerPath=function(){return this.sStaticPrefix+"js/min/"},e.prototype.socialGoogle=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0];return this.sServer+"SocialGoogle"+(""!==this.sAuthSuffix?"/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/":"")+(e?"&xauth=1":"")},e.prototype.socialTwitter=function(){return this.sServer+"SocialTwitter"+(""!==this.sAuthSuffix?"/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/":"")},e.prototype.socialFacebook=function(){return this.sServer+"SocialFacebook"+(""!==this.sAuthSuffix?"/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/":"")},e}();e.exports=new c},function(e,t,i){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}t.__esModule=!0,t.key=t.moment=t.Q=t._=t.JSON=t.$=t.window=void 0;var o=i(11),s=n(o),r=i(14),a=n(r),l=i(36),u=n(l),c=i(3),p=n(c),d=i(48),f=n(d),h=i(82),g=n(h),m=i(18),b=n(m);t.window=s["default"],t.$=a["default"],t.JSON=u["default"],t._=p["default"],t.Q=f["default"],t.moment=g["default"],t.key=b["default"]},function(e,t){e.exports=window.jQuery},,function(e,t,i){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0,t.componentExportHelper=t.AbstractComponent=void 0;var s=i(13),r=i(2),a=n(r),l=i(1),u=n(l),c=function(){function e(){o(this,e),this.disposable=[]}return e.prototype.dispose=function(){this.disposable.forEach(function(e){e&&e.dispose&&e.dispose()})},e}(),p=function(e){var t=arguments.length<=1||void 0===arguments[1]?"":arguments[1];return{template:t?{element:t}:" ",viewModel:{createViewModel:function(t,n){return t=t||{},t.element=null,n&&n.element&&(t.component=n,t.element=(0,s.$)(n.element),i(6).i18nToNodes(t.element),!u["default"].isUnd(t.inline)&&a["default"].unwrap(t.inline)&&t.element.css("display","inline-block")),new e(t)}}}};t.AbstractComponent=c,t.componentExportHelper=p},function(e,t){"use strict";t.__esModule=!0;t.MESSAGES_PER_PAGE=20,
+t.MESSAGES_PER_PAGE_VALUES=[10,20,30,50,100],t.CONTACTS_PER_PAGE=50,t.DEFAULT_AJAX_TIMEOUT=3e4,t.SEARCH_AJAX_TIMEOUT=3e5,t.SEND_MESSAGE_AJAX_TIMEOUT=3e5,t.SAVE_MESSAGE_AJAX_TIMEOUT=2e5,t.CONTACTS_SYNC_AJAX_TIMEOUT=2e5,t.UNUSED_OPTION_VALUE="__UNUSE__",t.CLIENT_SIDE_STORAGE_INDEX_NAME="rlcsc",t.IMAP_DEFAULT_PORT=143,t.IMAP_DEFAULT_SECURE_PORT=993,t.SMTP_DEFAULT_PORT=25,t.SMTP_DEFAULT_SECURE_PORT=465,t.SIEVE_DEFAULT_PORT=4190,t.MESSAGE_BODY_CACHE_LIMIT=15,t.AJAX_ERROR_LIMIT=7,t.TOKEN_ERROR_LIMIT=10,t.RAINLOOP_TRIAL_KEY="RAINLOOP-TRIAL-KEY",t.DATA_IMAGE_USER_DOT_PIC="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAuCAYAAABXuSs3AAAHHklEQVRoQ7VZW08bVxCeXRuwIbTGXIwNtBBaqjwgVUiR8lDlbza9qe1DpVZ9aNQ/0KpPeaJK07SpcuEeCEmUAObm21bfrL9lONjexSYrWfbunj37zXdmvpkz9oIgCKTD0Wg0xPd94TDP83Q0zvWa50vzklSrdanVanqf4/D84GBGr+F+Op3S8fqoJxLOdnZgTvsO/nYhenHA+UC7CWF1uXwkb9++ldPTUwVerVbVqFQqpR8YPjQ0JCMjI5LNDijoRgP3PQVu5+5Eor2XGLg7IV4GkIdHJ/LmzRs5ODiIwNbrdR0O0GCcq4Xz4eFhmZyclP7+tDQaIik/BG5XKQn4SwG3zJTLZXn9+rUclI8UHD5YVoDDN8bSzXhONwL48fFxGR4eilzFZT1uFRIB5yT8BqCdnR3Z3d0VP9Un6XRawYJpggVrZBv38ME4XKtUKnLt2jUplUoy1PR/l3U7T6sVSAQcgMAkj8PDQ9ne3pajoyMRL7zeKsYZWHgWYDGmv78/mmdwcFA+mJlSgziHDWrERrsjEXDXegTi1tZW+DLxI2bxIrqFNYTXyDyCFweMAHCwb8e4RnTNuOsqe3t7sra21pTD0Kct666E8XlcZyzw9/RUUXK5nK5oUinUQI6TQ3cynO/v78vq6qrKXCNwlTiJJpyNGc3nZHp6uqV2dwrQWOCtZBDAV1ZWwsQk7f0wiQn5kffbAu/0/KWBYzIC1+XukfGx0RGZmppKlC2tIV0Bh4aDcZW7HhkfH8urLLZL7T2pihvlkMNnz56FiadHxicL41IsFpN41bkxsYxbRdFo9jwB8KdPn14J8KnSpBQKhQs63nPmbCVRcBUAR2Lq1VVmpksyMTFxAXjcEsQybiegESionjx5osCZOeNe1O4+EhCAX7bQSgQcxRHTMgAgcz5+/Dis/hL4uHU3/B4YGNASGHIKxuEql0k+l05AeIAF1vPnz5VxFFmdDlaJrMtZITJeSsXCOTlMunKxjLtMYOKNjQ158eJFuAuKkUOb5sEwgff19SkJUBVkThZUbnXZrtCKBQ6gbnWIkjZpyne3ejAWoGnA7Icz6irvBLgbOMicCM6TkxPx/LAkbXfgWcsazuE2kFRsKD5Z+CiqDumKncpZvieWcS6dDVD8xiYCNflpJdwcdwJOf9airLmVQ7DPzMxIYWLsXGXoVqLt5k0M3K3JUVPDZdbWNzsCp48TPFdvdnZWUz32nDha7bJ63kgAJPzSdRks9/Kf9xMJAQ1gq2NpaUmy2Yz4zar4nQC3xb99AQwCcGzLAAwuhG8YiWvcOKts+r4GOe5nMhm5efOm9lUA3E3vSZJRrKvE0fnPv//Jy5cvo5cTHIPQbSjhOoqq69evS19f6lxDKK4+sVhigZPtKJqbrQeqxd5+WR4+fKgqgT0k2XX3nhiPgETWXFhYkFzuPZ2yVq1GTSOXpE47/VjgNnD4m4GG7/LhsTx69EiwD4Vr2MwIIxgbAH18fKx1yfz8vEogNvGtWnCuhLZa9UTAreVWFsHy/b/+Vrbdl7E5REMQD2jDoUbByty+/ZnU64GkU2HzyJLhktU1cLv8nARgkYS2d3ajAgwG8qU2oLmDZ92CMaOjo7K4uCiZgbDWaRWgnZhPxLhrMUCvr69riwKZk1LHF7XqrWAO9hJxH6ozNzcnCx/PqztZg9mf6SQMscCtm2C5ke4BGMlHWTUp36036AJajDVrFMzBrhhWslQsSrFYiOqVpMriNYIgqFRq2j3FAb/zffT6zuxFXxsNzs3NTXn16lW4gYiW96w1FyedF+83xG/2FNGCRpU4NjamMsn+OZ9xE5RXqdaDdPpib6RWCzuwKF9RxqI2AVNQBwQYJoK0wdBejnqtEikP3pfP51XjUTESl12FqJEKxsEorARYDD44ONTeID7YpsEnrRvQfWAI2e8WfDaTUSIwJ0iBCmFOtOUAHvVMPp/TPwvYFVYFIuP8l+DBgwdaa2Miqwa0GgYwfeMltovbDfh6c1vIgMYcliSsKv4IWFr6VDHxvldvBAH+1sA+cnl5WYOPmmr9ir+1l9I0Cgz0yjhXjfJJ0JROnmezWbl165ayr/5fqwcBNr7IfhjMqKcvESSM4eRcCasQ3bDNObmKPLdGUGpZsN24cUNLBm9zazu4d++e6qpNBFaTuUS26U5dpuR1CxyA7J9ddrMRqlz4pwLLYawymPd++/2PADt2ugcGwq9gCCdhQ96C6xWwa6j1ceuq+I0EhW0i8MAIVJfeL3d/DVD8EKi12P6/2S2jV/EccVB54O/ejz/9HGCpoBBMta5rXMXLu53D1XAwjhXwvvv+h4BAXVe4bOu3O3ChxF08LiZFG3fel199G9CH3fLyqv24NcB44MRhpdK788U3CpyKwsCw590xmfSpzsBt0Fqc3ud3vtZigxWcVZCklVpSiN0w3q5E/h9TGMIUuA3+EQAAAABJRU5ErkJggg==",t.DATA_IMAGE_TRANSP_PIC="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2NkAAIAAAoAAggA9GkAAAAASUVORK5CYII="},function(e,t){e.exports=window.key},,function(e,t,i){!function(){"use strict";function t(){o.call(this),this.oRequests={}}var n=i(3),o=i(55);n.extend(t.prototype,o.prototype),t.prototype.adminLogin=function(e,t,i){this.defaultRequest(e,"AdminLogin",{Login:t,Password:i})},t.prototype.adminLogout=function(e){this.defaultRequest(e,"AdminLogout")},t.prototype.saveAdminConfig=function(e,t){this.defaultRequest(e,"AdminSettingsUpdate",t)},t.prototype.domainList=function(e){this.defaultRequest(e,"AdminDomainList")},t.prototype.pluginList=function(e){this.defaultRequest(e,"AdminPluginList")},t.prototype.packagesList=function(e){this.defaultRequest(e,"AdminPackagesList")},t.prototype.coreData=function(e){this.defaultRequest(e,"AdminCoreData")},t.prototype.updateCoreData=function(e){this.defaultRequest(e,"AdminUpdateCoreData",{},9e4)},t.prototype.packageInstall=function(e,t){this.defaultRequest(e,"AdminPackageInstall",{Id:t.id,Type:t.type,File:t.file},6e4)},t.prototype.packageDelete=function(e,t){this.defaultRequest(e,"AdminPackageDelete",{Id:t.id})},t.prototype.domain=function(e,t){this.defaultRequest(e,"AdminDomainLoad",{Name:t})},t.prototype.plugin=function(e,t){this.defaultRequest(e,"AdminPluginLoad",{Name:t})},t.prototype.domainDelete=function(e,t){this.defaultRequest(e,"AdminDomainDelete",{Name:t})},t.prototype.domainDisable=function(e,t,i){return this.defaultRequest(e,"AdminDomainDisable",{Name:t,Disabled:i?"1":"0"})},t.prototype.pluginSettingsUpdate=function(e,t){return this.defaultRequest(e,"AdminPluginSettingsUpdate",t)},t.prototype.licensing=function(e,t){return this.defaultRequest(e,"AdminLicensing",{Force:t?"1":"0"})},t.prototype.licensingActivate=function(e,t,i){return this.defaultRequest(e,"AdminLicensingActivate",{Domain:t,Key:i})},t.prototype.pluginDisable=function(e,t,i){return this.defaultRequest(e,"AdminPluginDisable",{Name:t,Disabled:i?"1":"0"})},t.prototype.createOrUpdateDomain=function(e,t,i,n,o,s,r,a,l,u,c,p,d,f,h,g,m,b,v){this.defaultRequest(e,"AdminDomainSave",{Create:t?"1":"0",Name:i,IncHost:n,IncPort:o,IncSecure:s,IncShortLogin:r?"1":"0",UseSieve:a?"1":"0",SieveAllowRaw:l?"1":"0",SieveHost:u,SievePort:c,SieveSecure:p,OutHost:d,OutPort:f,OutSecure:h,OutShortLogin:g?"1":"0",OutAuth:m?"1":"0",OutUsePhpMail:b?"1":"0",WhiteList:v})},t.prototype.testConnectionForDomain=function(e,t,i,n,o,s,r,a,l,u,c,p,d,f){this.defaultRequest(e,"AdminDomainTest",{Name:t,IncHost:i,IncPort:n,IncSecure:o,UseSieve:s?"1":"0",SieveHost:r,SievePort:a,SieveSecure:l,OutHost:u,OutPort:c,OutSecure:p,OutAuth:d?"1":"0",OutUsePhpMail:f?"1":"0"})},t.prototype.testContacts=function(e,t){this.defaultRequest(e,"AdminContactsTest",t)},t.prototype.saveNewAdminPassword=function(e,t){this.defaultRequest(e,"AdminPasswordUpdate",t)},t.prototype.adminPing=function(e){this.defaultRequest(e,"AdminPing")},e.exports=new t}()},,function(e,t,i){"use strict";function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t["default"]=e,t}function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0;var l=i(13),u=i(2),c=o(u),p=i(83),d=o(p),f=i(4),h=n(f),g=i(1),m=o(g),b=i(12),v=o(b),S=i(6),y=o(S),w=i(9),A=o(w),_=i(35),C=o(_),T=i(57),E=o(T),N=i(59),P=o(N),R=i(139),I=o(R),O=i(58),x=o(O),D=i(89),L=o(D),k=i(20),M=o(k),F=i(5),U=o(F),H=i(64),G=function(e){function t(){return s(this,t),r(this,e.call(this,M["default"]))}return a(t,e),t.prototype.remote=function(){return M["default"]},t.prototype.reloadDomainList=function(){E["default"].domains.loading(!0),M["default"].domainList(function(e,t){E["default"].domains.loading(!1),h.StorageResultType.Success===e&&t&&t.Result&&E["default"].domains(l._.map(t.Result,function(e,t){return{name:t,disabled:c["default"].observable(!e),deleteAccess:c["default"].observable(!1)}}))})},t.prototype.reloadPluginList=function(){P["default"].plugins.loading(!0),M["default"].pluginList(function(e,t){P["default"].plugins.loading(!1),h.StorageResultType.Success===e&&t&&t.Result&&P["default"].plugins(l._.map(t.Result,function(e){return{name:e.Name,disabled:c["default"].observable(!e.Enabled),configured:c["default"].observable(!!e.Configured)}}))})},t.prototype.reloadPackagesList=function(){x["default"].packages.loading(!0),x["default"].packagesReal(!0),M["default"].packagesList(function(e,t){x["default"].packages.loading(!1),h.StorageResultType.Success===e&&t&&t.Result?!function(){x["default"].packagesReal(!!t.Result.Real),x["default"].packagesMainUpdatable(!!t.Result.MainUpdatable);var e=[],i={};l._.each(x["default"].packages(),function(e){e&&e.loading()&&(i[e.file]=e)}),m["default"].isArray(t.Result.List)&&(e=l._.compact(l._.map(t.Result.List,function(e){return e?(e.loading=c["default"].observable(!m["default"].isUnd(i[e.file])),"core"!==e.type||e.canBeInstalled?e:null):null}))),x["default"].packages(e)}():x["default"].packagesReal(!1)})},t.prototype.updateCoreData=function(){L["default"].coreUpdating(!0),M["default"].updateCoreData(function(e,t){L["default"].coreUpdating(!1),L["default"].coreVersion(""),L["default"].coreRemoteVersion(""),L["default"].coreRemoteRelease(""),L["default"].coreVersionCompare(-2),h.StorageResultType.Success===e&&t&&t.Result?(L["default"].coreReal(!0),l.window.location.reload()):L["default"].coreReal(!1)})},t.prototype.reloadCoreData=function(){L["default"].coreChecking(!0),L["default"].coreReal(!0),M["default"].coreData(function(e,t){L["default"].coreChecking(!1),h.StorageResultType.Success===e&&t&&t.Result?(L["default"].coreReal(!!t.Result.Real),L["default"].coreChannel(t.Result.Channel||"stable"),L["default"].coreType(t.Result.Type||"stable"),L["default"].coreUpdatable(!!t.Result.Updatable),L["default"].coreAccess(!!t.Result.Access),L["default"].coreWarning(!!t.Result.Warning),L["default"].coreVersion(t.Result.Version||""),L["default"].coreRemoteVersion(t.Result.RemoteVersion||""),L["default"].coreRemoteRelease(t.Result.RemoteRelease||""),L["default"].coreVersionCompare(m["default"].pInt(t.Result.VersionCompare))):(L["default"].coreReal(!1),L["default"].coreChannel("stable"),L["default"].coreType("stable"),L["default"].coreWarning(!1),L["default"].coreVersion(""),L["default"].coreRemoteVersion(""),L["default"].coreRemoteRelease(""),L["default"].coreVersionCompare(-2))})},t.prototype.reloadLicensing=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0];I["default"].licensingProcess(!0),I["default"].licenseError(""),M["default"].licensing(function(e,t){I["default"].licensingProcess(!1),h.StorageResultType.Success===e&&t&&t.Result&&m["default"].isNormal(t.Result.Expired)?(I["default"].licenseValid(!0),I["default"].licenseExpired(m["default"].pInt(t.Result.Expired)),I["default"].licenseError(""),I["default"].licensing(!0),C["default"].prem(!0)):t&&t.ErrorCode&&-1=t.diff(e,"hours"):return e.fromNow();case t.format("L")===e.format("L"):return a["default"].i18n("MESSAGE_LIST/TODAY_AT",{TIME:e.format("LT")});case t.clone().subtract("days",1).format("L")===e.format("L"):return a["default"].i18n("MESSAGE_LIST/YESTERDAY_AT",{TIME:e.format("LT")});case t.year()===e.year():return e.format("D MMM.")}return e?e.format("LL"):""},e.prototype.format=function(e,t){var i=null,n="",o=this.momentNowUnix();if(e=e>0?e:0===e?o:0,e=e>o?o:e,i=e>0?s.moment.unix(e):null,i&&1970===i.year()&&(i=null),i)switch(t){case"FROMNOW":n=i.fromNow();break;case"SHORT":n=this.formatCustomShortDate(i);break;case"FULL":n=i.format("LLL");break;default:n=i.format(t)}return n},e.prototype.momentToNode=function(e){var t="",i=0,n=(0,s.$)(e);i=n.data("moment-time"),i&&(t=n.data("moment-format"),t&&n.text(this.format(i,t)),t=n.data("moment-format-title"),t&&n.attr("title",this.format(i,t)))},e.prototype.momentToNodes=function(e){var t=this;s._.defer(function(){(0,s.$)(".moment",e).each(function(e,i){t.momentToNode(i)})})},e.prototype.reload=function(){this.momentToNodes(s.window.document)},e}();e.exports=new l},,,,function(e,t,i){!function(){"use strict";function t(e,t,i,n){this.email=e||"",this.name=t||"",this.dkimStatus=i||"none",this.dkimValue=n||"",this.clearDuplicateName()}var n=i(1);t.newInstanceFromJson=function(e){var i=new t;return i.initByJson(e)?i:null},t.splitHelper=function(e,t){t=t||";",e=e.replace(/[\r\n]+/g,"; ").replace(/[\s]+/g," ");for(var i=0,n=e.length,o=!1,s="",r="";n>i;i++){switch(s=e.charAt(i)){case"@":o=!0;break;case" ":o&&(o=!1,r+=t)}r+=s}return r.split(t)},t.prototype.name="",t.prototype.email="",t.prototype.dkimStatus="none",t.prototype.dkimValue="",t.prototype.clear=function(){this.email="",this.name="",this.dkimStatus="none",this.dkimValue=""},t.prototype.validate=function(){return""!==this.name||""!==this.email},t.prototype.hash=function(e){return"#"+(e?"":this.name)+"#"+this.email+"#"},t.prototype.clearDuplicateName=function(){this.name===this.email&&(this.name="")},t.prototype.search=function(e){return-1<(this.name+" "+this.email).toLowerCase().indexOf(e.toLowerCase())},t.prototype.parse=function(e){this.clear(),e=n.trim(e);var t=/(?:"([^"]+)")? ?[<]?(.*?@[^>,]+)>?,? ?/g,i=t.exec(e);i?(this.name=i[1]||"",this.email=i[2]||"",this.clearDuplicateName()):/^[^@]+@[^@]+$/.test(e)&&(this.name="",this.email=e)},t.prototype.initByJson=function(e){var t=!1;return e&&"Object/Email"===e["@Object"]&&(this.name=n.trim(e.Name),this.email=n.trim(e.Email),this.dkimStatus=n.trim(e.DkimStatus||""),this.dkimValue=n.trim(e.DkimValue||""),t=""!==this.email,this.clearDuplicateName()),t},t.prototype.toLine=function(e,t,i){var o="";return""!==this.email&&(t=n.isUnd(t)?!1:!!t,i=n.isUnd(i)?!1:!!i,e&&""!==this.name?o=t?'")+'" target="_blank" tabindex="-1">'+n.encodeHtml(this.name)+" ":i?n.encodeHtml(this.name):this.name:(o=this.email,""!==this.name?t?o=n.encodeHtml('"'+this.name+'" <')+'")+'" target="_blank" tabindex="-1">'+n.encodeHtml(o)+" "+n.encodeHtml(">"):(o='"'+this.name+'" <'+o+">",i&&(o=n.encodeHtml(o))):t&&(o=''+n.encodeHtml(this.email)+" "))),o},t.prototype.mailsoParse=function(e){if(e=n.trim(e),""===e)return!1;for(var t=function(e,t,i){e+="";var n=e.length;return 0>t&&(t+=n),n="undefined"==typeof i?n:0>i?i+n:i+t,t>=e.length||0>t||t>n?!1:e.slice(t,n)},i=function(e,t,i,n){return 0>i&&(i+=e.length),n=void 0!==n?n:e.length,0>n&&(n=n+e.length-i),e.slice(0,i)+t.substr(0,n)+t.slice(n)+e.slice(i+n)},o="",s="",r="",a=!1,l=!1,u=!1,c=null,p=0,d=0,f=0;f0&&0===o.length&&(o=t(e,0,f)),l=!0,p=f);break;case">":l&&(d=f,s=t(e,p+1,d-p-1),e=i(e,"",p,d-p+1),d=0,f=0,p=0,l=!1);break;case"(":a||l||u||(u=!0,p=f);break;case")":u&&(d=f,r=t(e,p+1,d-p-1),e=i(e,"",p,d-p+1),d=0,f=0,p=0,u=!1);break;case"\\":f++}f++}return 0===s.length&&(c=e.match(/[^@\s]+@\S+/i),c&&c[0]?s=c[0]:o=e),s.length>0&&0===o.length&&0===r.length&&(o=e.replace(s,"")),s=n.trim(s).replace(/^[<]+/,"").replace(/[>]+$/,""),o=n.trim(o).replace(/^["']+/,"").replace(/["']+$/,""),r=n.trim(r).replace(/^[(]+/,"").replace(/[)]+$/,""),o=o.replace(/\\\\(.)/g,"$1"),r=r.replace(/\\\\(.)/g,"$1"),this.name=o,this.email=s,this.clearDuplicateName(),!0},e.exports=t}()},,,,function(e,t,i){!function(){"use strict";function t(){this.google={},this.twitter={},this.facebook={},this.dropbox={},this.google.enabled=n.observable(!1),this.google.clientID=n.observable(""),this.google.clientSecret=n.observable(""),this.google.apiKey=n.observable(""),this.google.loading=n.observable(!1),this.google.userName=n.observable(""),this.google.loggined=n.computed(function(){return""!==this.google.userName()},this),this.google.capa={},this.google.capa.auth=n.observable(!1),this.google.capa.authFast=n.observable(!1),this.google.capa.drive=n.observable(!1),this.google.capa.preview=n.observable(!1),this.google.require={},this.google.require.clientSettings=n.computed(function(){return this.google.enabled()&&(this.google.capa.auth()||this.google.capa.drive())},this),this.google.require.apiKeySettings=n.computed(function(){return this.google.enabled()&&this.google.capa.drive()},this),this.facebook.enabled=n.observable(!1),this.facebook.appID=n.observable(""),this.facebook.appSecret=n.observable(""),this.facebook.loading=n.observable(!1),this.facebook.userName=n.observable(""),this.facebook.supported=n.observable(!1),this.facebook.loggined=n.computed(function(){return""!==this.facebook.userName()},this),this.twitter.enabled=n.observable(!1),this.twitter.consumerKey=n.observable(""),this.twitter.consumerSecret=n.observable(""),this.twitter.loading=n.observable(!1),this.twitter.userName=n.observable(""),this.twitter.loggined=n.computed(function(){return""!==this.twitter.userName()},this),this.dropbox.enabled=n.observable(!1),this.dropbox.apiKey=n.observable("")}var n=i(2);t.prototype.google={},t.prototype.twitter={},t.prototype.facebook={},t.prototype.dropbox={},t.prototype.populate=function(){var e=i(9);this.google.enabled(!!e.settingsGet("AllowGoogleSocial")),this.google.clientID(e.settingsGet("GoogleClientID")),this.google.clientSecret(e.settingsGet("GoogleClientSecret")),this.google.apiKey(e.settingsGet("GoogleApiKey")),this.google.capa.auth(!!e.settingsGet("AllowGoogleSocialAuth")),this.google.capa.authFast(!!e.settingsGet("AllowGoogleSocialAuthFast")),this.google.capa.drive(!!e.settingsGet("AllowGoogleSocialDrive")),this.google.capa.preview(!!e.settingsGet("AllowGoogleSocialPreview")),this.facebook.enabled(!!e.settingsGet("AllowFacebookSocial")),this.facebook.appID(e.settingsGet("FacebookAppID")),this.facebook.appSecret(e.settingsGet("FacebookAppSecret")),this.facebook.supported(!!e.settingsGet("SupportedFacebookSocial")),this.twitter.enabled=n.observable(!!e.settingsGet("AllowTwitterSocial")),this.twitter.consumerKey=n.observable(e.settingsGet("TwitterConsumerKey")),this.twitter.consumerSecret=n.observable(e.settingsGet("TwitterConsumerSecret")),this.dropbox.enabled(!!e.settingsGet("AllowDropboxSocial")),this.dropbox.apiKey(e.settingsGet("DropboxApiKey"))},e.exports=new t}()},function(e,t,i){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function s(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function r(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var a=i(2),l=n(a),u=i(9),c=n(u),p=i(76),d=function(e){function t(){o(this,t);var i=s(this,e.call(this));return i.determineUserLanguage=l["default"].observable(!1),i.determineUserDomain=l["default"].observable(!1),i.weakPassword=l["default"].observable(!1),i.useLocalProxyForExternalImages=l["default"].observable(!1),i}return r(t,e),t.prototype.populate=function(){e.prototype.populate.call(this),this.determineUserLanguage(!!c["default"].settingsGet("DetermineUserLanguage")),this.determineUserDomain(!!c["default"].settingsGet("DetermineUserDomain")),this.weakPassword(!!c["default"].settingsGet("WeakPassword")),this.useLocalProxyForExternalImages(!!c["default"].settingsGet("UseLocalProxyForExternalImages"))},t}(p.AbstractAppStore);e.exports=new d},function(e,t){e.exports=window.JSON},function(e,t,i){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function s(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function r(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0,t["default"]=t.AbstractInput=void 0;var a=i(2),l=n(a),u=i(1),c=n(u),p=i(4),d=i(16),f=function(e){function t(i){o(this,t);var n=s(this,e.call(this));return n.value=i.value||"",n.size=i.size||0,n.label=i.label||"",n.preLabel=i.preLabel||"",n.enable=c["default"].isUnd(i.enable)?!0:i.enable,n.trigger=i.trigger&&i.trigger.subscribe?i.trigger:null,n.placeholder=i.placeholder||"",n.labeled=!c["default"].isUnd(i.label),n.preLabeled=!c["default"].isUnd(i.preLabel),n.triggered=!c["default"].isUnd(i.trigger)&&!!n.trigger,n.classForTrigger=l["default"].observable(""),n.className=l["default"].computed(function(){var e=l["default"].unwrap(n.size),t=n.trigger?" "+c["default"].trim("settings-saved-trigger-input "+n.classForTrigger()):"";return(e>0?"span"+e:"")+t},n),!c["default"].isUnd(i.width)&&i.element&&i.element.find("input,select,textarea").css("width",i.width),n.disposable.push(n.className),n.trigger&&(n.setTriggerState(n.trigger()),n.disposable.push(n.trigger.subscribe(n.setTriggerState,n))),n}return r(t,e),t.prototype.setTriggerState=function(e){switch(c["default"].pInt(e)){case p.SaveSettingsStep.TrueResult:this.classForTrigger("success");break;case p.SaveSettingsStep.FalseResult:this.classForTrigger("error");break;default:this.classForTrigger("")}},t}(d.AbstractComponent);t.AbstractInput=f,t["default"]=f},function(e,t,i){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function s(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var r=i(16),a=i(46),l=function(e){function t(){return n(this,t),o(this,e.apply(this,arguments))}return s(t,e),t}(a.AbstracCheckbox);e.exports=(0,r.componentExportHelper)(l,"CheckboxComponent")},function(e,t,i){!function(){"use strict";function t(e,t){this.sScreenName=e,this.aViewModels=s.isArray(t)?t:[]}var n=i(3),o=i(49),s=i(1);t.prototype.oCross=null,t.prototype.sScreenName="",t.prototype.aViewModels=[],t.prototype.viewModels=function(){return this.aViewModels},t.prototype.screenName=function(){return this.sScreenName},t.prototype.routes=function(){return null},t.prototype.__cross=function(){return this.oCross},t.prototype.__start=function(){var e=this.routes(),t=null,i=null;s.isNonEmptyArray(e)&&(i=n.bind(this.onRoute||s.emptyFunction,this),t=o.create(),n.each(e,function(e){t.addRoute(e[0],i).rules=e[1]}),this.oCross=t)},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){this.languages=n.observableArray([]),this.languagesAdmin=n.observableArray([]),this.language=n.observable("").extend({limitedList:this.languages}),this.languageAdmin=n.observable("").extend({limitedList:this.languagesAdmin}),this.userLanguage=n.observable(""),this.userLanguageAdmin=n.observable("")}var n=i(2),o=i(1),s=i(9);t.prototype.populate=function(){var e=s.appSettingsGet("languages"),t=s.appSettingsGet("languagesAdmin");this.languages(o.isArray(e)?e:[]),this.languagesAdmin(o.isArray(t)?t:[]),this.language(s.settingsGet("Language")),this.languageAdmin(s.settingsGet("LanguageAdmin")),this.userLanguage(s.settingsGet("UserLanguage")),this.userLanguageAdmin(s.settingsGet("UserLanguageAdmin"))},e.exports=new t}()},,function(e,t,i){!function(){"use strict";function t(){this.themes=n.observableArray([]),this.themeBackgroundName=n.observable(""),this.themeBackgroundHash=n.observable(""),this.theme=n.observable("").extend({limitedList:this.themes})}var n=i(2),o=i(1),s=i(9);t.prototype.populate=function(){var e=s.appSettingsGet("themes");this.themes(o.isArray(e)?e:[]),this.theme(s.settingsGet("Theme")),this.themeBackgroundName(s.settingsGet("UserBackgroundName")),this.themeBackgroundHash(s.settingsGet("UserBackgroundHash"))},e.exports=new t}()},function(e,t,i){!function(){"use strict";function t(){c.call(this,"Popups","PopupsAsk"),this.askDesc=o.observable(""),this.yesButton=o.observable(""),this.noButton=o.observable(""),this.yesFocus=o.observable(!1),this.noFocus=o.observable(!1),this.fYesAction=null,this.fNoAction=null,this.bFocusYesOnShow=!0,this.bDisabeCloseOnEsc=!0,this.sDefaultKeyScope=r.KeyState.PopupAsk,u.constructorEnd(this)}var n=i(3),o=i(2),s=i(18),r=i(4),a=i(1),l=i(6),u=i(5),c=i(10);u.extendAsViewModel(["View/Popup/Ask","PopupsAskViewModel"],t),n.extend(t.prototype,c.prototype),t.prototype.clearPopup=function(){this.askDesc(""),this.yesButton(l.i18n("POPUPS_ASK/BUTTON_YES")),this.noButton(l.i18n("POPUPS_ASK/BUTTON_NO")),this.yesFocus(!1),this.noFocus(!1),this.fYesAction=null,this.fNoAction=null},t.prototype.yesClick=function(){this.cancelCommand(),a.isFunc(this.fYesAction)&&this.fYesAction.call(null)},t.prototype.noClick=function(){this.cancelCommand(),a.isFunc(this.fNoAction)&&this.fNoAction.call(null)},t.prototype.onShow=function(e,t,i,n,o,s){this.clearPopup(),this.fYesAction=t||null,this.fNoAction=i||null,this.askDesc(e||""),n&&this.yesButton(n),n&&this.yesButton(o),this.bFocusYesOnShow=a.isUnd(s)?!0:!!s},t.prototype.onShowWithDelay=function(){this.bFocusYesOnShow&&this.yesFocus(!0)},t.prototype.onBuild=function(){s("tab, shift+tab, right, left",r.KeyState.PopupAsk,n.bind(function(){return this.yesFocus()?this.noFocus(!0):this.yesFocus(!0),!1},this)),s("esc",r.KeyState.PopupAsk,n.bind(function(){return this.noClick(),!1},this))},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){a.call(this,"Popups","PopupsLanguages");var e=this;this.fLang=null,this.userLanguage=o.observable(""),this.langs=o.observableArray([]),this.languages=o.computed(function(){var t=e.userLanguage();return n.map(e.langs(),function(e){return{key:e,user:e===t,selected:o.observable(!1),fullName:s.convertLangName(e)}})}),this.langs.subscribe(function(){this.setLanguageSelection()},this),r.constructorEnd(this)}var n=i(3),o=i(2),s=i(1),r=i(5),a=i(10);r.extendAsViewModel(["View/Popup/Languages","PopupsLanguagesViewModel"],t),n.extend(t.prototype,a.prototype),t.prototype.languageTooltipName=function(e){var t=s.convertLangName(e,!0);return s.convertLangName(e,!1)===t?"":t},t.prototype.setLanguageSelection=function(){var e=this.fLang?o.unwrap(this.fLang):"";n.each(this.languages(),function(t){t.selected(t.key===e)})},t.prototype.onBeforeShow=function(){this.fLang=null,this.userLanguage(""),this.langs([])},t.prototype.onShow=function(e,t,i){this.fLang=e,this.userLanguage(i||""),this.langs(t)},t.prototype.changeLanguage=function(e){this.fLang&&this.fLang(e),this.cancelCommand()},e.exports=t}()},function(e,t,i){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0,t["default"]=t.HtmlEditor=void 0;var s=i(13),r=i(8),a=n(r),l=i(9),u=n(l),c=function(){function e(t){var i=arguments.length<=1||void 0===arguments[1]?null:arguments[1],n=arguments.length<=2||void 0===arguments[2]?null:arguments[2],r=arguments.length<=3||void 0===arguments[3]?null:arguments[3];o(this,e),this.editor=null,this.$element=null,this.blurTimer=0,this.onBlur=null,this.onReady=null,this.onModeChange=null,this.__inited=null,this.onBlur=i,this.onReady=n,this.onModeChange=r,this.$element=(0,s.$)(t),this.resize=s._.throttle(s._.bind(this.resize,this),100),this.__inited=!1,this.init()}return e.prototype.blurTrigger=function(){var e=this;this.onBlur&&(s.window.clearTimeout(this.blurTimer),this.blurTimer=s.window.setTimeout(function(){
+e.onBlur()},200))},e.prototype.focusTrigger=function(){this.onBlur&&s.window.clearTimeout(this.blurTimer)},e.prototype.isHtml=function(){return this.editor?"wysiwyg"===this.editor.mode:!1},e.prototype.setSignature=function(e,t,i){this.editor&&this.editor.execCommand("insertSignature",{isHtml:t,insertBefore:i,signature:e})},e.prototype.checkDirty=function(){return this.editor?this.editor.checkDirty():!1},e.prototype.resetDirty=function(){this.editor&&this.editor.resetDirty()},e.prototype.clearSignatureSigns=function(e){return e.replace(/(\u200C|\u0002)/g,"")},e.prototype.getData=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0],t=arguments.length<=1||void 0===arguments[1]?!1:arguments[1],i="";if(this.editor){try{i="plain"===this.editor.mode&&this.editor.plugins.plain&&this.editor.__plain?this.editor.__plain.getRawData():e?''+this.editor.getData()+"
":this.editor.getData()}catch(n){}t&&(i=this.clearSignatureSigns(i))}return i},e.prototype.getDataWithHtmlMark=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0],t=arguments.length<=1||void 0===arguments[1]?!1:arguments[1];return(this.isHtml()?":HTML:":"")+this.getData(e,t)},e.prototype.modeToggle=function(e,t){if(this.editor){try{e?"plain"===this.editor.mode&&this.editor.setMode("wysiwyg"):"wysiwyg"===this.editor.mode&&this.editor.setMode("plain")}catch(i){}t&&this.resize()}},e.prototype.setHtmlOrPlain=function(e,t){":HTML:"===e.substr(0,6)?this.setHtml(e.substr(6),t):this.setPlain(e,t)},e.prototype.setHtml=function(e,t){if(this.editor&&this.__inited){this.modeToggle(!0),e=e.replace(/]*><\/p>/gi,"");try{this.editor.setData(e)}catch(i){}t&&this.focus()}},e.prototype.replaceHtml=function(e,t){if(this.editor&&this.__inited&&"wysiwyg"===this.editor.mode)try{this.editor.setData(this.editor.getData().replace(e,t))}catch(i){}},e.prototype.setPlain=function(e,t){if(this.editor&&this.__inited){if(this.modeToggle(!1),"plain"===this.editor.mode&&this.editor.plugins.plain&&this.editor.__plain)this.editor.__plain.setRawData(e);else try{this.editor.setData(e)}catch(i){}t&&this.focus()}},e.prototype.init=function(){var e=this;if(this.$element&&this.$element[0]&&!this.editor){var t=function(){var t=a["default"].oHtmlEditorDefaultConfig,i=u["default"].settingsGet("Language"),n=!!u["default"].appSettingsGet("allowHtmlEditorSourceButton"),o=!!u["default"].appSettingsGet("allowHtmlEditorBitiButtons");!n&&o||t.toolbarGroups.__cfgInited||(t.toolbarGroups.__cfgInited=!0,n&&(t.removeButtons=t.removeButtons.replace(",Source","")),o||(t.removePlugins+=(t.removePlugins?",":"")+"bidi")),t.enterMode=s.window.CKEDITOR.ENTER_BR,t.shiftEnterMode=s.window.CKEDITOR.ENTER_P,t.language=a["default"].oHtmlEditorLangsMap[i]||"en",s.window.CKEDITOR.env&&(s.window.CKEDITOR.env.isCompatible=!0),e.editor=s.window.CKEDITOR.appendTo(e.$element[0],t),e.editor.on("key",function(e){return e&&e.data&&9===e.data.keyCode?!1:void 0}),e.editor.on("blur",function(){e.blurTrigger()}),e.editor.on("mode",function(){e.blurTrigger(),e.onModeChange&&e.onModeChange("plain"!==e.editor.mode)}),e.editor.on("focus",function(){e.focusTrigger()}),s.window.FileReader&&e.editor.on("drop",function(t){if(0 ')},r.readAsDataURL(i),t.data.dataTransfer.setData("text/html",o)}}}),e.editor.on("instanceReady",function(){e.editor.removeMenuItem&&(e.editor.removeMenuItem("cut"),e.editor.removeMenuItem("copy"),e.editor.removeMenuItem("paste")),e.__resizable=!0,e.__inited=!0,e.resize(),e.onReady&&e.onReady()})};s.window.CKEDITOR?t():s.window.__initEditor=t}},e.prototype.focus=function(){if(this.editor)try{this.editor.focus()}catch(e){}},e.prototype.hasFocus=function(){if(this.editor)try{return!!this.editor.focusManager.hasFocus}catch(e){}return!1},e.prototype.blur=function(){if(this.editor)try{this.editor.focusManager.blur(!0)}catch(e){}},e.prototype.resize=function(){if(this.editor&&this.__resizable)try{this.editor.resize(this.$element.width(),this.$element.innerHeight())}catch(e){}},e.prototype.setReadOnly=function(e){if(this.editor)try{this.editor.setReadOnly(!!e)}catch(t){}},e.prototype.clear=function(e){this.setHtml("",e)},e}();t.HtmlEditor=c,t["default"]=c,e.exports=c},function(e,t,i){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function s(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function r(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0,t["default"]=t.AbstracCheckbox=void 0;var a=i(2),l=n(a),u=i(1),c=n(u),p=i(16),d=function(e){function t(){var i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];o(this,t);var n=s(this,e.call(this));return n.value=i.value,!c["default"].isUnd(n.value)&&n.value.subscribe||(n.value=l["default"].observable(c["default"].isUnd(n.value)?!1:!!n.value)),n.enable=i.enable,!c["default"].isUnd(n.enable)&&n.enable.subscribe||(n.enable=l["default"].observable(c["default"].isUnd(n.enable)?!0:!!n.enable)),n.disable=i.disable,!c["default"].isUnd(n.disable)&&n.disable.subscribe||(n.disable=l["default"].observable(c["default"].isUnd(n.disable)?!1:!!n.disable)),n.label=i.label||"",n.inline=c["default"].isUnd(i.inline)?!1:i.inline,n.readOnly=c["default"].isUnd(i.readOnly)?!1:!!i.readOnly,n.inverted=c["default"].isUnd(i.inverted)?!1:!!i.inverted,n.labeled=!c["default"].isUnd(i.label),n.labelAnimated=!!i.labelAnimated,n}return r(t,e),t.prototype.click=function(){this.readOnly||!this.enable()||this.disable()||this.value(!this.value())},t}(p.AbstractComponent);t.AbstracCheckbox=d,t["default"]=d},,function(e,t){e.exports=window.Q},function(e,t){e.exports=window.crossroads},function(e,t,i){!function(){"use strict";function t(){this.additionalAccounts=n.observable(!1),this.identities=n.observable(!1),this.gravatar=n.observable(!1),this.attachmentThumbnails=n.observable(!1),this.sieve=n.observable(!1),this.filters=n.observable(!1),this.themes=n.observable(!0),this.userBackground=n.observable(!1),this.openPGP=n.observable(!1),this.twoFactorAuth=n.observable(!1),this.twoFactorAuthForce=n.observable(!1),this.templates=n.observable(!1)}var n=i(2),o=i(4),s=i(9);t.prototype.populate=function(){this.additionalAccounts(s.capa(o.Capa.AdditionalAccounts)),this.identities(s.capa(o.Capa.Identities)),this.gravatar(s.capa(o.Capa.Gravatar)),this.attachmentThumbnails(s.capa(o.Capa.AttachmentThumbnails)),this.sieve(s.capa(o.Capa.Sieve)),this.filters(s.capa(o.Capa.Filters)),this.themes(s.capa(o.Capa.Themes)),this.userBackground(s.capa(o.Capa.UserBackground)),this.openPGP(s.capa(o.Capa.OpenPGP)),this.twoFactorAuth(s.capa(o.Capa.TwoFactor)),this.twoFactorAuthForce(s.capa(o.Capa.TwoFactorForce)),this.templates(s.capa(o.Capa.Templates))},e.exports=new t}()},,,,function(e,t,i){!function(){"use strict";var t=i(11),n=t.Opentip;n.styles.rainloop={"extends":"standard",fixed:!0,target:!0,delay:.2,hideDelay:0,hideEffect:"fade",hideEffectDuration:.2,showEffect:"fade",showEffectDuration:.2,showOn:"mouseover click",removeElementsOnHide:!0,background:"#fff",shadow:!1,borderColor:"#999",borderRadius:2,borderWidth:1},n.styles.rainloopTip={"extends":"rainloop",delay:.4,group:"rainloopTips"},n.styles.rainloopErrorTip={"extends":"rainloop",className:"rainloopErrorTip"},e.exports=n}()},function(e,t,i){!function(){"use strict";function t(){this.oRequests={}}var n=i(11),o=i(3),s=i(14),r=i(17),a=i(4),l=i(8),u=i(1),c=i(23),p=i(12),d=i(9);t.prototype.oRequests={},t.prototype.defaultResponse=function(e,t,i,n,s,p){var d=function(){a.StorageResultType.Success!==i&&l.bUnload&&(i=a.StorageResultType.Unload),a.StorageResultType.Success===i&&n&&!n.Result?(n&&-1(new n.Date).getTime()-h),m&&l.oRequests[m]&&(l.oRequests[m].__aborted&&(o="abort"),l.oRequests[m]=null),l.defaultResponse(e,m,o,i,s,t)}),m&&0
").addClass("rl-settings-view-model").hide(),d.appendTo(p),i.viewModelDom=d,i.__rlSettingsData=c.__rlSettingsData,c.__dom=d,c.__builded=!0,c.__vm=i,s.applyBindingAccessorsToNode(d[0],{translatorInit:!0,template:function(){return{name:c.__rlSettingsData.Template}}},i),a.delegateRun(i,"onBuild",[d])):a.log("Cannot find sub settings view model position: SettingsSubScreen")),i&&n.defer(function(){t.oCurrentSubScreen&&(a.delegateRun(t.oCurrentSubScreen,"onHide"),t.oCurrentSubScreen.viewModelDom.hide()),t.oCurrentSubScreen=i,t.oCurrentSubScreen&&(a.delegateRun(t.oCurrentSubScreen,"onBeforeShow"),t.oCurrentSubScreen.viewModelDom.show(),a.delegateRun(t.oCurrentSubScreen,"onShow"),a.delegateRun(t.oCurrentSubScreen,"onShowWithDelay",[],200),n.each(t.menu(),function(e){e.selected(i&&i.__rlSettingsData&&e.route===i.__rlSettingsData.Route)}),o("#rl-content .b-settings .b-content .content").scrollTop(0)),a.windowResize()})):u.setHash(l.settings(),!1,!0)},t.prototype.onHide=function(){this.oCurrentSubScreen&&this.oCurrentSubScreen.viewModelDom&&(a.delegateRun(this.oCurrentSubScreen,"onHide"),this.oCurrentSubScreen.viewModelDom.hide())},t.prototype.onBuild=function(){n.each(r.aViewModels.settings,function(e){e&&e.__rlSettingsData&&!n.find(r.aViewModels["settings-removed"],function(t){return t&&t===e})&&this.menu.push({route:e.__rlSettingsData.Route,label:e.__rlSettingsData.Label,selected:s.observable(!1),disabled:!!n.find(r.aViewModels["settings-disabled"],function(t){return t&&t===e})})},this),this.oViewModelPlace=o("#rl-content #rl-settings-subscreen")},t.prototype.routes=function(){var e=n.find(r.aViewModels.settings,function(e){return e&&e.__rlSettingsData&&e.__rlSettingsData.IsDefault}),t=e?e.__rlSettingsData.Route:"general",i={subname:/^(.*)$/,normalize_:function(e,i){return i.subname=a.isUnd(i.subname)?t:a.pString(i.subname),[i.subname]}};return[["{subname}/",i],["{subname}",i],["",i]]},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){this.domains=n.observableArray([]),this.domains.loading=n.observable(!1).extend({throttle:100})}var n=i(2);e.exports=new t}()},function(e,t,i){!function(){"use strict";function t(){this.packages=n.observableArray([]),this.packages.loading=n.observable(!1).extend({throttle:100}),this.packagesReal=n.observable(!0),this.packagesMainUpdatable=n.observable(!0)}var n=i(2);e.exports=new t}()},function(e,t,i){!function(){"use strict";function t(){this.plugins=n.observableArray([]),this.plugins.loading=n.observable(!1).extend({throttle:100}),this.plugins.error=n.observable("")}var n=i(2);e.exports=new t}()},,,,,function(e,t,i){"use strict";function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t["default"]=e,t}function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0,t["default"]=t.AbstractApp=void 0;var l=i(13),u=i(8),c=o(u),p=i(4),d=n(p),f=i(1),h=o(f),g=i(12),m=o(g),b=i(25),v=o(b),S=i(6),y=o(S),w=i(9),A=o(w),_=i(75),C=function(e){function t(i){s(this,t);var n=r(this,e.call(this));return n.googlePreviewSupportedCache=null,n.isLocalAutocomplete=!0,n.iframe=null,n.iframe=(0,l.$)('').appendTo("body"),c["default"].$win.on("error",function(e){e&&e.originalEvent&&e.originalEvent.message&&-1===h["default"].inArray(e.originalEvent.message,["Script error.","Uncaught Error: Error calling method on NPObject."])&&i.jsError(h["default"].emptyFunction,e.originalEvent.message,e.originalEvent.filename,e.originalEvent.lineno,l.window.location&&l.window.location.toString?l.window.location.toString():"",c["default"].$html.attr("class"),h["default"].microtime()-c["default"].startMicrotime)}),c["default"].$win.on("resize",function(){v["default"].pub("window.resize")}),v["default"].sub("window.resize",l._.throttle(function(){var e=c["default"].$win.height(),t=c["default"].$win.height();c["default"].$win.__sizes[0]===e&&c["default"].$win.__sizes[1]===t||(c["default"].$win.__sizes[0]=e,c["default"].$win.__sizes[1]=t,v["default"].pub("window.resize.real"))},50)),c["default"].$doc.on("keydown",function(e){e&&e.ctrlKey&&c["default"].$html.addClass("rl-ctrl-key-pressed")}).on("keyup",function(e){e&&!e.ctrlKey&&c["default"].$html.removeClass("rl-ctrl-key-pressed")}),c["default"].$doc.on("mousemove keypress click",l._.debounce(function(){v["default"].pub("rl.auto-logout-refresh")},5e3)),(0,l.key)("esc, enter",d.KeyState.All,l._.bind(function(){h["default"].detectDropdownVisibility()},n)),n}return a(t,e),t.prototype.remote=function(){return null},t.prototype.data=function(){return null},t.prototype.getApplicationConfiguration=function(e,t){return this.applicationConfiguration[e]||t},t.prototype.download=function(e){if(c["default"].sUserAgent&&(c["default"].sUserAgent.indexOf("chrome")>-1||c["default"].sUserAgent.indexOf("chrome")>-1)){var t=l.window.document.createElement("a");if(t.href=e,l.window.document&&l.window.document.createEvent){var i=l.window.document.createEvent.MouseEvents;if(i&&i.initEvent&&t.dispatchEvent)return i.initEvent("click",!0,!0),t.dispatchEvent(i),!0}}return c["default"].bMobileDevice?(l.window.open(e,"_self"),l.window.focus()):this.iframe.attr("src",e),!0},t.prototype.googlePreviewSupported=function(){return null===this.googlePreviewSupportedCache&&(this.googlePreviewSupportedCache=!!A["default"].settingsGet("AllowGoogleSocial")&&!!A["default"].settingsGet("AllowGoogleSocialPreview")),this.googlePreviewSupportedCache},t.prototype.setWindowTitle=function(e){e=h["default"].isNormal(e)&&0<\/b><\/x-script>/i,""):"",a?(i.element.text(""),i.element.replaceWith((0,r.$)(a).text(i.component.templateNodes[0]&&i.component.templateNodes[0].nodeValue?i.component.templateNodes[0].nodeValue:""))):i.element.remove()}return s}return s(t,e),t}(a.AbstractComponent);e.exports=(0,a.componentExportHelper)(l,"ScriptComponent")},function(e,t,i){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function s(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function r(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var a=i(1),l=n(a),u=i(6),c=n(u),p=i(16),d=i(37),f=function(e){function t(i){o(this,t);var n=s(this,e.call(this,i));return n.options=i.options||"",n.optionsText=i.optionsText||null,n.optionsValue=i.optionsValue||null,n.optionsCaption=i.optionsCaption||null,n.optionsCaption&&(n.optionsCaption=c["default"].i18n(n.optionsCaption)),n.defautOptionsAfterRender=l["default"].defautOptionsAfterRender,n}return r(t,e),t}(d.AbstractInput);e.exports=(0,p.componentExportHelper)(f,"SelectComponent")},function(e,t,i){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function s(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function r(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var a=i(1),l=n(a),u=i(16),c=i(37),p=function(e){function t(i){o(this,t);var n=s(this,e.call(this,i));return n.rows=i.rows||5,n.spellcheck=l["default"].isUnd(i.spellcheck)?!1:!!i.spellcheck,n}return r(t,e),t}(c.AbstractInput);e.exports=(0,u.componentExportHelper)(p,"TextAreaComponent")},function(e,t){"use strict";function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var n=function(){function e(){i(this,e)}return e.prototype.bootstart=function(){},e}();t.AbstractBoot=n,t["default"]=n},function(e,t,i){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0,t["default"]=t.AbstractAppStore=void 0;var s=i(2),r=n(s),a=i(8),l=n(a),u=i(9),c=n(u),p=function(){function e(){o(this,e),this.allowLanguagesOnSettings=r["default"].observable(!0),this.allowLanguagesOnLogin=r["default"].observable(!0),this.interfaceAnimation=r["default"].observable(!0),this.interfaceAnimation.subscribe(function(e){var t=l["default"].bMobileDevice||!e;l["default"].$html.toggleClass("rl-anim",!t).toggleClass("no-rl-anim",t)}),this.interfaceAnimation.valueHasMutated(),this.prem=r["default"].observable(!1),this.community=r["default"].observable(!0)}return e.prototype.populate=function(){this.allowLanguagesOnLogin(!!c["default"].settingsGet("AllowLanguagesOnLogin")),this.allowLanguagesOnSettings(!!c["default"].settingsGet("AllowLanguagesOnSettings")),this.interfaceAnimation(!!c["default"].settingsGet("InterfaceAnimation")),this.prem(!!c["default"].settingsGet("PremType")),this.community(!!c["default"].settingsGet("Community"))},e}();t.AbstractAppStore=p,t["default"]=p},function(e,t,i){"use strict";t.__esModule=!0,t["default"]=function(e){var t=i(11),n=i(3),o=i(14),s=i(8),r=i(23),a=i(1),l=i(4),u=i(6),c=i(30);s.__APP__=e,s.$win.keydown(a.kill_CtrlA_CtrlS).unload(function(){s.bUnload=!0}),s.$html.addClass(s.bMobileDevice?"mobile":"no-mobile").on("click.dropdown.data-api",function(){a.detectDropdownVisibility()}),t.rl=t.rl||{},t.rl.i18n=n.bind(u.i18n,u),t.rl.addHook=n.bind(r.addHook,r),t.rl.settingsGet=n.bind(r.mainSettingsGet,r),t.rl.createCommand=a.createCommand,t.rl.addSettingsViewModel=n.bind(r.addSettingsViewModel,r),t.rl.pluginRemoteRequest=n.bind(r.remoteRequest,r),t.rl.pluginSettingsGet=n.bind(r.settingsGet,r),t.rl.EmailModel=c,t.rl.Enums=l,t.__APP_BOOT=function(i){o(n.delay(function(){o("#rl-check").is(":visible")||s.$html.addClass("no-css"),o("#rl-check").remove(),t.rainloopTEMPLATES&&t.rainloopTEMPLATES[0]?(o("#rl-templates").html(t.rainloopTEMPLATES[0]),n.delay(function(){e.bootstart(),s.$html.removeClass("no-js rl-booted-trigger").addClass("rl-booted")},10)):i(!1),t.__APP_BOOT=null},10))}}},function(e,t){e.exports=window.Autolinker},function(e,t){e.exports=window.JSEncrypt},,function(e,t){e.exports=window.hasher},function(e,t){e.exports=window.moment},function(e,t){e.exports=window.rainloopProgressJs},function(e,t){e.exports=window.ssm},,,,,function(e,t,i){!function(){"use strict";function t(){this.coreReal=n.observable(!0),this.coreChannel=n.observable("stable"),this.coreType=n.observable("stable"),this.coreUpdatable=n.observable(!0),this.coreAccess=n.observable(!0),this.coreWarning=n.observable(!1),this.coreChecking=n.observable(!1).extend({throttle:100}),this.coreUpdating=n.observable(!1).extend({throttle:100}),this.coreVersion=n.observable(""),this.coreRemoteVersion=n.observable(""),this.coreRemoteRelease=n.observable(""),this.coreVersionCompare=n.observable(-2)}var n=i(2);e.exports=new t}()},,,,function(e,t,i){!function(){"use strict";function t(){f.call(this,"Popups","PopupsDomain"),this.edit=o.observable(!1),this.saving=o.observable(!1),this.savingError=o.observable(""),this.page=o.observable("main"),this.sieveSettings=o.observable(!1),this.testing=o.observable(!1),this.testingDone=o.observable(!1),this.testingImapError=o.observable(!1),this.testingSieveError=o.observable(!1),this.testingSmtpError=o.observable(!1),this.testingImapErrorDesc=o.observable(""),this.testingSieveErrorDesc=o.observable(""),this.testingSmtpErrorDesc=o.observable(""),this.testingImapError.subscribe(function(e){e||this.testingImapErrorDesc("")},this),this.testingSieveError.subscribe(function(e){e||this.testingSieveErrorDesc("")},this),this.testingSmtpError.subscribe(function(e){e||this.testingSmtpErrorDesc("")},this),this.imapServerFocus=o.observable(!1),this.sieveServerFocus=o.observable(!1),this.smtpServerFocus=o.observable(!1),this.name=o.observable(""),this.name.focused=o.observable(!1),this.imapServer=o.observable(""),this.imapPort=o.observable(""+r.IMAP_DEFAULT_PORT),this.imapSecure=o.observable(s.ServerSecure.None),this.imapShortLogin=o.observable(!1),this.useSieve=o.observable(!1),this.sieveAllowRaw=o.observable(!1),this.sieveServer=o.observable(""),this.sievePort=o.observable(""+r.SIEVE_DEFAULT_PORT),this.sieveSecure=o.observable(s.ServerSecure.None),this.smtpServer=o.observable(""),this.smtpPort=o.observable(""+r.SMTP_DEFAULT_PORT),this.smtpSecure=o.observable(s.ServerSecure.None),this.smtpShortLogin=o.observable(!1),this.smtpAuth=o.observable(!0),this.smtpPhpMail=o.observable(!1),this.whiteList=o.observable(""),this.enableSmartPorts=o.observable(!1),this.allowSieve=o.computed(function(){return c.filters()&&c.sieve()},this),this.headerText=o.computed(function(){var e=this.name();return this.edit()?u.i18n("POPUPS_DOMAIN/TITLE_EDIT_DOMAIN",{NAME:e}):""===e?u.i18n("POPUPS_DOMAIN/TITLE_ADD_DOMAIN"):u.i18n("POPUPS_DOMAIN/TITLE_ADD_DOMAIN_WITH_NAME",{NAME:e})},this),this.domainDesc=o.computed(function(){var e=this.name();return!this.edit()&&e?u.i18n("POPUPS_DOMAIN/NEW_DOMAIN_DESC",{NAME:"*@"+e}):""},this),this.domainIsComputed=o.computed(function(){var e=this.smtpPhpMail(),t=this.allowSieve(),i=this.useSieve();return""!==this.name()&&""!==this.imapServer()&&""!==this.imapPort()&&(t&&i?""!==this.sieveServer()&&""!==this.sievePort():!0)&&(""!==this.smtpServer()&&""!==this.smtpPort()||e)},this),this.canBeTested=o.computed(function(){return!this.testing()&&this.domainIsComputed()},this),this.canBeSaved=o.computed(function(){return!this.saving()&&this.domainIsComputed()},this),this.createOrAddCommand=l.createCommand(this,function(){this.saving(!0),p.createOrUpdateDomain(n.bind(this.onDomainCreateOrSaveResponse,this),!this.edit(),this.name(),this.imapServer(),l.pInt(this.imapPort()),this.imapSecure(),this.imapShortLogin(),this.useSieve(),this.sieveAllowRaw(),this.sieveServer(),l.pInt(this.sievePort()),this.sieveSecure(),this.smtpServer(),l.pInt(this.smtpPort()),this.smtpSecure(),this.smtpShortLogin(),this.smtpAuth(),this.smtpPhpMail(),this.whiteList())},this.canBeSaved),this.testConnectionCommand=l.createCommand(this,function(){this.page("main"),this.testingDone(!1),this.testingImapError(!1),this.testingSieveError(!1),this.testingSmtpError(!1),this.testing(!0),p.testConnectionForDomain(n.bind(this.onTestConnectionResponse,this),this.name(),this.imapServer(),l.pInt(this.imapPort()),this.imapSecure(),this.useSieve(),this.sieveServer(),l.pInt(this.sievePort()),this.sieveSecure(),this.smtpServer(),l.pInt(this.smtpPort()),this.smtpSecure(),this.smtpAuth(),this.smtpPhpMail())},this.canBeTested),this.whiteListCommand=l.createCommand(this,function(){this.page("white-list")}),this.backCommand=l.createCommand(this,function(){this.page("main")}),this.sieveCommand=l.createCommand(this,function(){this.sieveSettings(!this.sieveSettings()),this.clearTesting()}),this.page.subscribe(function(){this.sieveSettings(!1)},this),this.imapServerFocus.subscribe(function(e){e&&""!==this.name()&&""===this.imapServer()&&this.imapServer(this.name().replace(/[.]?[*][.]?/g,""))},this),this.sieveServerFocus.subscribe(function(e){e&&""!==this.imapServer()&&""===this.sieveServer()&&this.sieveServer(this.imapServer())},this),this.smtpServerFocus.subscribe(function(e){e&&""!==this.imapServer()&&""===this.smtpServer()&&this.smtpServer(this.imapServer().replace(/imap/gi,"smtp"))},this),this.imapSecure.subscribe(function(e){if(this.enableSmartPorts()){var t=l.pInt(this.imapPort());switch(e=l.pString(e)){case"0":993===t&&this.imapPort("143");break;case"1":143===t&&this.imapPort("993")}}},this),this.smtpSecure.subscribe(function(e){if(this.enableSmartPorts()){var t=l.pInt(this.smtpPort());switch(e=l.pString(e)){case"0":465!==t&&587!==t||this.smtpPort("25");break;case"1":25!==t&&587!==t||this.smtpPort("465");break;case"2":25!==t&&465!==t||this.smtpPort("587")}}},this),d.constructorEnd(this)}var n=i(3),o=i(2),s=i(4),r=i(17),a=i(8),l=i(1),u=i(6),c=i(50),p=i(20),d=i(5),f=i(10);d.extendAsViewModel(["View/Popup/Domain","PopupsDomainViewModel"],t),n.extend(t.prototype,f.prototype),t.prototype.onTestConnectionResponse=function(e,t){if(this.testing(!1),s.StorageResultType.Success===e&&t.Result){var i=!1,n=!1;this.testingDone(!0),this.testingImapError(!0!==t.Result.Imap),this.testingSieveError(!0!==t.Result.Sieve),this.testingSmtpError(!0!==t.Result.Smtp),this.testingImapError()&&t.Result.Imap&&(i=!0,this.testingImapErrorDesc(""),this.testingImapErrorDesc(t.Result.Imap)),this.testingSieveError()&&t.Result.Sieve&&(n=!0,this.testingSieveErrorDesc(""),this.testingSieveErrorDesc(t.Result.Sieve)),this.testingSmtpError()&&t.Result.Smtp&&(this.testingSmtpErrorDesc(""),this.testingSmtpErrorDesc(t.Result.Smtp)),this.sieveSettings()?!n&&i&&this.sieveSettings(!1):n&&!i&&this.sieveSettings(!0)}else this.testingImapError(!0),this.testingSieveError(!0),this.testingSmtpError(!0),this.sieveSettings(!1)},t.prototype.onDomainCreateOrSaveResponse=function(e,t){this.saving(!1),s.StorageResultType.Success===e&&t?t.Result?(i(22)["default"].reloadDomainList(),this.closeCommand()):s.Notification.DomainAlreadyExists===t.ErrorCode&&this.savingError(u.i18n("ERRORS/DOMAIN_ALREADY_EXISTS")):this.savingError(u.i18n("ERRORS/UNKNOWN_ERROR"))},t.prototype.clearTesting=function(){this.testing(!1),this.testingDone(!1),this.testingImapError(!1),this.testingSieveError(!1),this.testingSmtpError(!1)},t.prototype.onHide=function(){this.page("main"),this.sieveSettings(!1)},t.prototype.onShow=function(e){this.saving(!1),this.page("main"),this.sieveSettings(!1),this.clearTesting(),this.clearForm(),e&&(this.enableSmartPorts(!1),this.edit(!0),this.name(l.trim(e.Name)),this.imapServer(l.trim(e.IncHost)),this.imapPort(""+l.pInt(e.IncPort)),this.imapSecure(l.trim(e.IncSecure)),this.imapShortLogin(!!e.IncShortLogin),this.useSieve(!!e.UseSieve),this.sieveAllowRaw(!!e.SieveAllowRaw),this.sieveServer(l.trim(e.SieveHost)),this.sievePort(""+l.pInt(e.SievePort)),this.sieveSecure(l.trim(e.SieveSecure)),this.smtpServer(l.trim(e.OutHost)),this.smtpPort(""+l.pInt(e.OutPort)),this.smtpSecure(l.trim(e.OutSecure)),this.smtpShortLogin(!!e.OutShortLogin),this.smtpAuth(!!e.OutAuth),this.smtpPhpMail(!!e.OutUsePhpMail),this.whiteList(l.trim(e.WhiteList)),this.enableSmartPorts(!0))},t.prototype.onShowWithDelay=function(){""!==this.name()||a.bMobile||this.name.focused(!0)},t.prototype.clearForm=function(){this.edit(!1),this.page("main"),this.sieveSettings(!1),this.enableSmartPorts(!1),this.savingError(""),this.name(""),this.name.focused(!1),this.imapServer(""),this.imapPort(""+r.IMAP_DEFAULT_PORT),this.imapSecure(s.ServerSecure.None),this.imapShortLogin(!1),this.useSieve(!1),this.sieveAllowRaw(!1),this.sieveServer(""),this.sievePort(""+r.SIEVE_DEFAULT_PORT),this.sieveSecure(s.ServerSecure.None),this.smtpServer(""),this.smtpPort(""+r.SMTP_DEFAULT_PORT),this.smtpSecure(s.ServerSecure.None),this.smtpShortLogin(!1),this.smtpAuth(!0),this.smtpPhpMail(!1),this.whiteList(""),this.enableSmartPorts(!0)},e.exports=t}()},,,,,,,,,,,,,,,,,,,,function(e,t,i){!function(){"use strict";function t(){o.call(this,"login",[i(140)])}var n=i(3),o=i(39);n.extend(t.prototype,o.prototype),t.prototype.onShow=function(){i(22)["default"].setWindowTitle("")},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){r.call(this,[i(141),i(142)])}var n=i(3),o=i(5),s=i(23),r=i(56);n.extend(t.prototype,r.prototype),t.prototype.setupSettings=function(e){o.addSettingsViewModel(i(122),"AdminSettingsGeneral","TABS_LABELS/LABEL_GENERAL_NAME","general",!0),o.addSettingsViewModel(i(123),"AdminSettingsLogin","TABS_LABELS/LABEL_LOGIN_NAME","login"),o.addSettingsViewModel(i(119),"AdminSettingsBranding","TABS_LABELS/LABEL_BRANDING_NAME","branding"),o.addSettingsViewModel(i(120),"AdminSettingsContacts","TABS_LABELS/LABEL_CONTACTS_NAME","contacts"),o.addSettingsViewModel(i(121),"AdminSettingsDomains","TABS_LABELS/LABEL_DOMAINS_NAME","domains"),o.addSettingsViewModel(i(126),"AdminSettingsSecurity","TABS_LABELS/LABEL_SECURITY_NAME","security"),o.addSettingsViewModel(i(127),"AdminSettingsSocial","TABS_LABELS/LABEL_INTEGRATION_NAME","integrations"),o.addSettingsViewModel(i(125),"AdminSettingsPlugins","TABS_LABELS/LABEL_PLUGINS_NAME","plugins"),o.addSettingsViewModel(i(124),"AdminSettingsPackages","TABS_LABELS/LABEL_PACKAGES_NAME","packages"),o.addSettingsViewModel(i(118),"AdminSettingsAbout","TABS_LABELS/LABEL_ABOUT_NAME","about"),s.runSettingsViewModelHooks(!0),e&&e()},t.prototype.onShow=function(){i(22)["default"].setWindowTitle("")},e.exports=t}()},,,,function(e,t,i){!function(){"use strict";function t(){this.version=n.observable(s.appSettingsGet("version")),this.access=n.observable(!!s.settingsGet("CoreAccess")),this.errorDesc=n.observable(""),this.coreReal=r.coreReal,this.coreChannel=r.coreChannel,this.coreType=r.coreType,this.coreUpdatable=r.coreUpdatable,this.coreAccess=r.coreAccess,this.coreChecking=r.coreChecking,this.coreUpdating=r.coreUpdating,this.coreWarning=r.coreWarning,this.coreVersion=r.coreVersion,this.coreRemoteVersion=r.coreRemoteVersion,this.coreRemoteRelease=r.coreRemoteRelease,this.coreVersionCompare=r.coreVersionCompare,this.community=!0,this.coreRemoteVersionHtmlDesc=n.computed(function(){return o.trigger(),o.i18n("TAB_ABOUT/HTML_NEW_VERSION",{VERSION:this.coreRemoteVersion()})},this),this.statusType=n.computed(function(){var e="",t=this.coreVersionCompare(),i=this.coreChecking(),n=this.coreUpdating(),o=this.coreReal();return i?e="checking":n?e="updating":o&&0===t?e="up-to-date":o&&-1===t?e="available":o||(e="error",this.errorDesc("Cannot access the repository at the moment.")),e},this)}var n=i(2),o=i(6),s=i(9),r=i(89);i(35);t.prototype.onBuild=function(){this.access()&&!this.community&&i(22)["default"].reloadCoreData()},t.prototype.updateCoreData=function(){this.coreUpdating()||this.community||i(22)["default"].updateCoreData()},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){var e=i(4),t=i(9),n=i(35);this.capa=n.prem,this.title=o.observable(t.settingsGet("Title")),this.title.trigger=o.observable(e.SaveSettingsStep.Idle),this.loadingDesc=o.observable(t.settingsGet("LoadingDescription")),this.loadingDesc.trigger=o.observable(e.SaveSettingsStep.Idle),this.faviconUrl=o.observable(t.settingsGet("FaviconUrl")),this.faviconUrl.trigger=o.observable(e.SaveSettingsStep.Idle),this.loginLogo=o.observable(t.settingsGet("LoginLogo")||""),this.loginLogo.trigger=o.observable(e.SaveSettingsStep.Idle),this.loginBackground=o.observable(t.settingsGet("LoginBackground")||""),this.loginBackground.trigger=o.observable(e.SaveSettingsStep.Idle),this.userLogo=o.observable(t.settingsGet("UserLogo")||""),this.userLogo.trigger=o.observable(e.SaveSettingsStep.Idle),this.userLogoMessage=o.observable(t.settingsGet("UserLogoMessage")||""),this.userLogoMessage.trigger=o.observable(e.SaveSettingsStep.Idle),this.userIframeMessage=o.observable(t.settingsGet("UserIframeMessage")||""),this.userIframeMessage.trigger=o.observable(e.SaveSettingsStep.Idle),this.userLogoTitle=o.observable(t.settingsGet("UserLogoTitle")||""),this.userLogoTitle.trigger=o.observable(e.SaveSettingsStep.Idle),this.loginDescription=o.observable(t.settingsGet("LoginDescription")),this.loginDescription.trigger=o.observable(e.SaveSettingsStep.Idle),this.loginCss=o.observable(t.settingsGet("LoginCss")),this.loginCss.trigger=o.observable(e.SaveSettingsStep.Idle),this.userCss=o.observable(t.settingsGet("UserCss")),this.userCss.trigger=o.observable(e.SaveSettingsStep.Idle),this.welcomePageUrl=o.observable(t.settingsGet("WelcomePageUrl")),this.welcomePageUrl.trigger=o.observable(e.SaveSettingsStep.Idle),this.welcomePageDisplay=o.observable(t.settingsGet("WelcomePageDisplay")),this.welcomePageDisplay.trigger=o.observable(e.SaveSettingsStep.Idle),this.welcomePageDisplay.options=o.computed(function(){return r.trigger(),[{optValue:"none",optText:r.i18n("TAB_BRANDING/OPTION_WELCOME_PAGE_DISPLAY_NONE")},{optValue:"once",optText:r.i18n("TAB_BRANDING/OPTION_WELCOME_PAGE_DISPLAY_ONCE")},{optValue:"always",optText:r.i18n("TAB_BRANDING/OPTION_WELCOME_PAGE_DISPLAY_ALWAYS")}]}),this.loginPowered=o.observable(!!t.settingsGet("LoginPowered")),this.community=!0}var n=i(3),o=i(2),s=i(1),r=i(6);t.prototype.onBuild=function(){var e=this,t=i(20);n.delay(function(){var i=s.settingsSaveHelperSimpleFunction(e.title.trigger,e),n=s.settingsSaveHelperSimpleFunction(e.loadingDesc.trigger,e),o=s.settingsSaveHelperSimpleFunction(e.faviconUrl.trigger,e);e.title.subscribe(function(e){t.saveAdminConfig(i,{Title:s.trim(e)})}),e.loadingDesc.subscribe(function(e){t.saveAdminConfig(n,{LoadingDescription:s.trim(e)})}),e.faviconUrl.subscribe(function(e){t.saveAdminConfig(o,{FaviconUrl:s.trim(e)})})},50)},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){var e=i(20);this.defautOptionsAfterRender=r.defautOptionsAfterRender,this.enableContacts=o.observable(!!l.settingsGet("ContactsEnable")),this.contactsSharing=o.observable(!!l.settingsGet("ContactsSharing")),this.contactsSync=o.observable(!!l.settingsGet("ContactsSync"));var t=["sqlite","mysql","pgsql"],u=[],c=function(e){switch(e){case"sqlite":e="SQLite";break;case"mysql":e="MySQL";break;case"pgsql":e="PostgreSQL"}return e};l.settingsGet("SQLiteIsSupported")&&u.push("sqlite"),l.settingsGet("MySqlIsSupported")&&u.push("mysql"),l.settingsGet("PostgreSqlIsSupported")&&u.push("pgsql"),this.contactsSupported=00?o--:!r&&o"+e.readme()+""}},this.saveCommand=a.createCommand(this,function(){var e={};e.Name=this.name(),n.each(this.configures(),function(t){var i=t.value();!1!==i&&!0!==i||(i=i?"1":"0"),e["_"+t.Name]=i},this),this.saveError(""),u.pluginSettingsUpdate(this.onPluginSettingsUpdateResponse,e)},this.hasConfiguration),this.bDisabeCloseOnEsc=!0,this.sDefaultKeyScope=r.KeyState.All,this.tryToClosePopup=n.debounce(n.bind(this.tryToClosePopup,this),200),c.constructorEnd(this)}var n=i(3),o=i(2),s=i(18),r=i(4),a=i(1),l=i(6),u=i(20),c=i(5),p=i(10);c.extendAsViewModel(["View/Popup/Plugin","PopupsPluginViewModel"],t),n.extend(t.prototype,p.prototype),t.prototype.onPluginSettingsUpdateResponse=function(e,t){r.StorageResultType.Success===e&&t&&t.Result?this.cancelCommand():(this.saveError(""),t&&t.ErrorCode?this.saveError(l.getNotification(t.ErrorCode)):this.saveError(l.getNotification(r.Notification.CantSavePluginSettings)))},t.prototype.onShow=function(e){if(this.name(),this.readme(),this.configures([]),e){this.name(e.Name),this.readme(e.Readme);var t=e.Config;a.isNonEmptyArray(t)&&this.configures(n.map(t,function(e){return{value:o.observable(e[0]),placeholder:o.observable(e[6]),Name:e[1],Type:e[2],Label:e[3],Default:e[4],Desc:e[5]}}))}},t.prototype.tryToClosePopup=function(){var e=this,t=i(43);c.isPopupVisible(t)||c.showScreenPopup(t,[l.i18n("POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW"),function(){e.modalVisibility()&&a.delegateRun(e,"cancelCommand")}])},t.prototype.onBuild=function(){s("esc",r.KeyState.All,n.bind(function(){return this.modalVisibility()&&this.tryToClosePopup(),!1},this))},e.exports=t}()}]);
diff --git a/rainloop/rainloop/v/1.10.0.103/static/js/min/admin.js b/rainloop/rainloop/v/1.10.0.103/static/js/min/admin.js
new file mode 100644
index 0000000..a24d616
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/static/js/min/admin.js
@@ -0,0 +1,327 @@
+(function(h){function f(a){if(c[a])return c[a].exports;var e=c[a]={exports:{},id:a,loaded:!1};h[a].call(e.exports,e,e.exports,f);e.loaded=!0;return e.exports}var c={};f.m=h;f.c=c;f.p="rainloop/v/0.0.0/static/js/";return f(0)})([function(h,f,c){h=(h=c(77))&&h.__esModule?h:{default:h};c=(c=c(22))&&c.__esModule?c:{default:c};(0,h.default)(c.default)},function(h,f,c){(function(){var a=null,e={},d=c(11),b=c(3),g=c(14),l=c(2),k=c(78),m=c(36),n=c(79),p=c(66),r=c(4),f=c(8);e.trim=g.trim;e.inArray=g.inArray;
+e.isArray=b.isArray;e.isObject=b.isObject;e.isFunc=b.isFunction;e.isUnd=b.isUndefined;e.isNull=b.isNull;e.emptyFunction=e.noop=function(){};e.silentTryCatch=function(b){try{b()}catch(a){}};e.isNormal=function(b){return!e.isUnd(b)&&!e.isNull(b)};e.windowResize=b.debounce(function(b){e.isUnd(b)?f.$win.resize():d.setTimeout(function(){f.$win.resize()},b)},50);e.windowResizeCallback=function(){e.windowResize()};e.isPosNumeric=function(b,a){return e.isNormal(b)?e.isUnd(a)||a?/^[0-9]*$/.test(b.toString()):
+/^[1-9]+[0-9]*$/.test(b.toString()):!1};e.pInt=function(b,a){var c=e.isNormal(b)&&""!==b?d.parseInt(b,10):a||0;return d.isNaN(c)?a||0:c};e.pString=function(b){return e.isNormal(b)?""+b:""};e.pBool=function(b){return!!b};e.encodeURIComponent=function(b){return d.encodeURIComponent(b)};e.isNonEmptyArray=function(b){return e.isArray(b)&&0a;)d=m.substring(0,a),g=d.lastIndexOf(" "),l=d.lastIndexOf("\n"),-1!==l&&(g=l),-1===g&&(g=a),c+=d.substring(0,g)+"\n",m=m.substring(g+1);return c+m};e.timeOutAction=function(){var b={};return function(a,c,m){e.isUnd(b[a])&&(b[a]=0);d.clearTimeout(b[a]);
+b[a]=d.setTimeout(c,m)}}();e.timeOutActionSecond=function(){var b={};return function(a,c,m){b[a]||(b[a]=d.setTimeout(function(){c();b[a]=0},m))}}();e.hos=function(b,a){return b&&d.Object&&d.Object.hasOwnProperty?d.Object.hasOwnProperty.call(b,a):!1};e.inFocus=function(){return d.document.activeElement?(e.isUnd(d.document.activeElement.__inFocusCache)&&(d.document.activeElement.__inFocusCache=g(d.document.activeElement).is("input,textarea,iframe,.cke_editable")),!!d.document.activeElement.__inFocusCache):
+!1};e.removeInFocus=function(b){if(d.document&&d.document.activeElement&&d.document.activeElement.blur)if(g(d.document.activeElement).is("input,textarea"))d.document.activeElement.blur();else if(b)try{d.document.activeElement.blur()}catch(a){}};e.removeSelection=function(){if(d&&d.getSelection){var b=d.getSelection();b&&b.removeAllRanges&&b.removeAllRanges()}else d.document&&d.document.selection&&d.document.selection.empty&&d.document.selection.empty()};e.replySubjectAdd=function(a,c){a=e.trim(a.toUpperCase());
+c=e.trim(c.replace(/[\s]+/g," "));var d=!1,m=[],g="RE"===a,l="FWD"===a,k=!l;""!==c&&b.each(c.split(":"),function(b){var a=e.trim(b);d||!/^(RE|FWD)$/i.test(a)&&!/^(RE|FWD)[\[\(][\d]+[\]\)]$/i.test(a)?(m.push(b),d=!0):(g||(g=!!/^RE/i.test(a)),l||(l=!!/^FWD/i.test(a)))});k?g=!1:l=!1;return e.trim((k?"Re: ":"Fwd: ")+(g?"Re: ":"")+(l?"Fwd: ":"")+e.trim(m.join(":")))};e.roundNumber=function(b,a){return d.Math.round(b*d.Math.pow(10,a))/d.Math.pow(10,a)};e.friendlySize=function(b){b=e.pInt(b);return 1073741824<=
+b?e.roundNumber(b/1073741824,1)+"GB":1048576<=b?e.roundNumber(b/1048576,1)+"MB":1024<=b?e.roundNumber(b/1024,0)+"KB":b+"B"};e.log=function(b){d.console&&d.console.log&&d.console.log(b)};e.delegateRun=function(a,c,d,m){a&&a[c]&&(m=e.pInt(m),0>=m?a[c].apply(a,e.isArray(d)?d:[]):b.delay(function(){a[c].apply(a,e.isArray(d)?d:[])},m))};e.kill_CtrlA_CtrlS=function(b){if((b=b||d.event)&&b.ctrlKey&&!b.shiftKey&&!b.altKey){var a=b.target||b.srcElement,c=b.keyCode||b.which;c===r.EventKeyCode.S?b.preventDefault():
+c!==r.EventKeyCode.A||a&&("true"===""+a.contentEditable||a.tagName&&a.tagName.match(/INPUT|TEXTAREA/i))||(d.getSelection?d.getSelection().removeAllRanges():d.document.selection&&d.document.selection.clear&&d.document.selection.clear(),b.preventDefault())}};e.createCommand=function(b,a,c){var d=e.emptyFunction,d=a?function(){d&&d.canExecute&&d.canExecute()&&a.apply(b,Array.prototype.slice.call(arguments));return!1}:e.emptyFunction;d.enabled=l.observable(!0);c=e.isUnd(c)?!0:c;e.isFunc(c)?d.canExecute=
+l.computed(function(){return d.enabled()&&c.call(b)}):d.canExecute=l.computed(function(){return d.enabled()&&!!c});return d};e.convertThemeName=b.memoize(function(b){"@custom"===b.substr(-7)&&(b=e.trim(b.substring(0,b.length-7)));return e.trim(b.replace(/[^a-zA-Z0-9]+/g," ").replace(/([A-Z])/g," $1").replace(/[\s]+/g," "))});e.quoteName=function(b){return b.replace(/["]/g,'\\"')};e.microtime=function(){return(new d.Date).getTime()};e.timestamp=function(){return d.Math.round(e.microtime()/1E3)};e.convertLangName=
+function(b,a){return c(6).i18n("LANGS_NAMES"+(!0===a?"_EN":"")+"/LANG_"+b.toUpperCase().replace(/[^a-zA-Z0-9]+/g,"_"),null,b)};e.fakeMd5=function(b){var a="";for(b=e.isUnd(b)?32:e.pInt(b);a.length ').appendTo("#rl-hidden")};
+e.defautOptionsAfterRender=function(b,a){a&&!e.isUnd(a.disabled)&&b&&g(b).toggleClass("disabled",a.disabled).prop("disabled",a.disabled)};e.windowPopupKnockout=function(b,a,m,k){var n=null,p=d.open(""),r="__OpenerApplyBindingsUid"+e.fakeMd5()+"__",f=g("#"+a);d[r]=function(){if(p&&p.document.body&&f&&f[0]){var a=g(p.document.body);g("#rl-content",a).html(f.html());g("html",p.document).addClass("external "+g("html").attr("class"));c(6).i18nToNodes(a);b&&g("#rl-content",a)[0]&&l.applyBindings(b,g("#rl-content",
+a)[0]);d[r]=null;k(p)}};p.document.open();p.document.write(''+e.encodeHtml(m)+'
');p.document.close();n=p.document.createElement("script");n.type="text/javascript";n.innerHTML=
+"if(window&&window.opener&&window.opener['"+r+"']){window.opener['"+r+"']();window.opener['"+r+"']=null}";p.document.getElementsByTagName("head")[0].appendChild(n)};e.settingsSaveHelperFunction=function(a,c,d,m){d=d||null;m=e.isUnd(m)?1E3:e.pInt(m);return function(g,e,l,k,n){c.call(d,e&&e.Result?r.SaveSettingsStep.TrueResult:r.SaveSettingsStep.FalseResult);a&&a.call(d,g,e,l,k,n);b.delay(function(){c.call(d,r.SaveSettingsStep.Idle)},m)}};e.settingsSaveHelperSimpleFunction=function(b,a){return e.settingsSaveHelperFunction(null,
+b,a,1E3)};e.settingsSaveHelperSubscribeFunction=function(b,a,c,d){return function(m){if(b){switch(c){default:m=e.pString(m);break;case "bool":case "boolean":m=m?"1":"0";break;case "int":case "integer":case "number":m=e.pInt(m);break;case "trim":m=e.trim(m)}var g={};g[a]=m;b.saveAdminConfig?b.saveAdminConfig(d||null,g):b.saveSettings&&b.saveSettings(d||null,g)}}};e.htmlToPlain=function(a){for(var c=0,d=c=0,m=0,l=0,k="",n=function(b){b=e.trim(b);b="> "+b.replace(/\n/gm,"\n> ");return b.replace(/(^|\n)([> ]+)/gm,
+function(){return arguments&&2]*>([\s\S\r\n]*)<\/div>/gmi,p),b="\n"+g.trim(b)+"\n");return b}return""},k=a.replace(/\u0002([\s\S]*)\u0002/gm,"\u200c$1\u200c").replace(/]*><\/p>/gi,"").replace(/
]*>([\s\S\r\n\t]*)<\/pre>/gmi,function(){return arguments&&1 ").replace(/[\r]/gm,""):""}).replace(/[\s]+/gm," ").replace(/((?:href|data)\s?=\s?)("[^"]+?"|'[^']+?')/gmi,function(){return arguments&&1]*>/gmi,"\n").replace(/<\/h[\d]>/gi,"\n").replace(/<\/p>/gi,"\n\n").replace(/]*>/gmi,"\n").replace(/<\/ul>/gi,"\n").replace(/]*>/gmi," * ").replace(/<\/li>/gi,"\n").replace(/<\/td>/gi,"\n").replace(/<\/tr>/gi,"\n").replace(/ ]*>/gmi,"\n_______________________________\n\n").replace(/]*>([\s\S\r\n]*)<\/div>/gmi,
+p).replace(/
]*>/gmi,"\n__bq__start__\n").replace(/<\/blockquote>/gmi,"\n__bq__end__\n").replace(/]*>([\s\S\r\n]*?)<\/a>/gmi,function(){return arguments&&1/gi,"\n").replace(/ /gi," ").replace(/"/gi,'"').replace(/<[^>]*>/gm,""),k=f.$div.html(k).text(),k=k.replace(/\n[ \t]+/gm,"\n").replace(/[\n]{3,}/gm,"\n\n").replace(/>/gi,">").replace(/</gi,"<").replace(/&/gi,"&"),k=e.splitPlainText(e.trim(k)),c=0,
+l=800;0"===l.substr(0,1))&&!c?
+(c=d=!0,g.push("~~~blockquote~~~"),g.push(l.substr(1))):!m&&c?(""!==l&&(c=!1,g.push("~~~/blockquote~~~")),g.push(l)):m&&c?g.push(l.substr(1)):g.push(l);c&&(c=!1,g.push("~~~/blockquote~~~"));n=g}while(d);b=n.join("\n");b=b.replace(/&/g,"&").replace(/>/g,">").replace(/").replace(/[\s]*~~~\/blockquote~~~/g," ").replace(/\u200C([\s\S]*)\u200C/g,"\u0002$1\u0002").replace(/\n/g,"
");return a?e.findEmailAndLinks(b):b};d.rainloop_Utils_htmlToPlain=
+e.htmlToPlain;d.rainloop_Utils_plainToHtml=e.plainToHtml;e.findEmailAndLinks=function(b){return b=k.link(b,{newWindow:!0,stripPrefix:!1,urls:!0,email:!0,twitter:!1,replaceFn:function(b,a){return!(b&&a&&"url"===a.getType()&&a.matchedText&&0!==a.matchedText.indexOf("http"))}})};e.resizeAndCrop=function(b,a,c){var m=new d.Image;m.onload=function(){var b=[0,0],m=d.document.createElement("canvas"),g=m.getContext("2d");m.width=a;m.height=a;b=this.width>this.height?[this.width-this.height,0]:[0,this.height-
+this.width];g.fillStyle="#fff";g.fillRect(0,0,a,a);g.drawImage(this,b[0]/2,b[1]/2,this.width-b[0],this.height-b[1],0,0,a,a);c(m.toDataURL("image/jpeg"))};m.src=b};e.folderListOptionsBuilder=function(b,a,c,m,g,l,k,n,p,f){var q=null,h=!1,y=0,D=0,A=[];f=e.isUnd(f)?!1:!!f;p=e.isNormal(p)?p:0
=k||n-2<=k)g+=2;p(k);m=c=k}for(;0=m)p(m,!0),g--;else if(0>=c)break;3===c?p(2,!1):3m&&p(d.Math.round((n+m)/2),!0,"...");1m&&p(n,!0)}return l}};
+e.selectElement=function(b){var a,c;d.getSelection?(a=d.getSelection(),a.removeAllRanges(),c=d.document.createRange(),c.selectNodeContents(b),a.addRange(c)):d.document.selection&&(c=d.document.body.createTextRange(),c.moveToElementText(b),c.select())};e.detectDropdownVisibility=b.debounce(function(){f.dropdownVisibility(!!b.find(f.aBootstrapDropdowns,function(b){return b.hasClass("open")}))},50);e.triggerAutocompleteInputChange=function(a){var c=function(){g(".checkAutocomplete").trigger("change")};
+(e.isUnd(a)?0:a)?b.delay(c,100):c()};e.setHeadViewport=function(a){var c=[];b.each(a,function(b,a){c.push(""+b+"="+a)});g("#rl-head-viewport").attr("content",c.join(", "))};e.getFileExtension=function(b){b=e.trim(b).toLowerCase();var a=b.split(".").pop();return a===b?"":a};e.configurationScriptTagCache={};e.getConfigurationFromScriptTag=function(b){var a={};e.configurationScriptTagCache[b]||(e.configurationScriptTagCache[b]=g('script[type="application/json"][data-configuration="'+b+'"]'));try{a=m.parse(e.configurationScriptTagCache[b].text())}catch(c){}return a};
+e.mimeContentType=function(b){var a="",c="application/octet-stream";b=e.trim(b).toLowerCase();if("winmail.dat"===b)return"application/ms-tnef";(a=e.getFileExtension(b))&&0'),c.after(m),c.remove()),m&&m[0]&&(m.attr("data-href",l).attr("data-theme",b[0]),m[0].styleSheet&&!e.isUnd(m[0].styleSheet.cssText)?m[0].styleSheet.cssText=b[1]:m.text(b[1])),a(r.SaveSettingsStep.TrueResult))}).always(function(){e.__themeTimer=d.setTimeout(function(){a(r.SaveSettingsStep.Idle)},1E3);e.__themeAjax=
+null}))};e.substr=d.String.substr;"b"!=="ab".substr(-1)&&(e.substr=function(b,a,c){0>a&&(a=b.length+a);return b.substr(a,c)});h.exports=e})()},function(h,f,c){(function(a){var e=c(11),d=c(3),b=c(14),g=c(36),l=c(54),k=function(b){a.utils.domNodeDisposal.addDisposeCallback(b,function(){b&&b.__opentip&&b.__opentip.deactivate()})};a.bindingHandlers.updateWidth={init:function(c,d){var l=b(e),g=b(c),k=d(),t=function(){k(g.width());e.setTimeout(function(){k(g.width())},500)};l.on("resize",t);t();a.utils.domNodeDisposal.addDisposeCallback(c,
+function(){l.off("resize",t)})}};a.bindingHandlers.editor={init:function(b,d){var l=null,g=d(),e=function(){g&&g.__editor&&g.__editor.setHtmlOrPlain(g())},k=function(){g&&g.__editor&&g(g.__editor.getDataWithHtmlMark())},f=function(){g.__editor=l;e()},h=c(45);a.isObservable(g)&&h&&(l=new h(b,k,f,k),g.__fetchEditorValue=k,g.subscribe(e))}};a.bindingHandlers.json={init:function(c,d){b(c).text(g.stringify(a.unwrap(d())))},update:function(c,d){b(c).text(g.stringify(a.unwrap(d())))}};a.bindingHandlers.scrollerShadows=
+{init:function(c){var g=b(c),l=b(e),k=g.find("[data-scroller-shadows-content]")[0]||null,f=d.throttle(function(){g.toggleClass("scroller-shadow-top",8=g.left&&a.pageX<=
+g.left+d.width()&&(a.pageY>=c-100&&a.pageY<=c&&(c=function(){d.scrollTop(d.scrollTop()+3);f.windowResize()},d.data("timerScroll",e.setInterval(c,10)),c()),a.pageY>=g.top&&a.pageY<=g.top+100&&(g=function(){d.scrollTop(d.scrollTop()-3);f.windowResize()},d.data("timerScroll",e.setInterval(g,10)),g()))})},d.stop=function(){b(t).each(function(){e.clearInterval(b(this).data("timerScroll"));b(this).data("timerScroll",!1)})});d.helper=function(b){return l()(b&&b.target?a.dataFor(b.target):null)};b(g).draggable(d).on("mousedown.koDraggable",
+function(){f.removeInFocus()});a.utils.domNodeDisposal.addDisposeCallback(g,function(){b(g).off("mousedown.koDraggable").draggable("destroy")})}}};a.bindingHandlers.droppable={init:function(g,d,l){if(!c(8).bMobileDevice){var e=d(),k=(d=l())&&d.droppableOver?d.droppableOver:null,f=d&&d.droppableOut?d.droppableOut:null;d={tolerance:"pointer",hoverClass:"droppableHover"};e&&(d.drop=function(b,a){e(b,a)},k&&(d.over=function(b,a){k(b,a)}),f&&(d.out=function(b,a){f(b,a)}),b(g).droppable(d),a.utils.domNodeDisposal.addDisposeCallback(g,
+function(){b(g).droppable("destroy")}))}}};a.bindingHandlers.nano={init:function(a){c(8).bDisableNanoScroll||b(a).addClass("nano").nanoScroller({iOSNativeScrolling:!1,preventPageScrolling:!0})}};a.bindingHandlers.saveTrigger={init:function(a){a=b(a);a.data("save-trigger-type",a.is("input[type=text],input[type=email],input[type=password],select,textarea")?"input":"custom");"custom"===a.data("save-trigger-type")?a.append(' ').addClass("settings-saved-trigger"):
+a.addClass("settings-saved-trigger-input")},update:function(c,g){var d=a.unwrap(g()),l=b(c);if("custom"===l.data("save-trigger-type"))switch(d.toString()){case "1":l.find(".animated,.error").hide().removeClass("visible").end().find(".success").show().addClass("visible");break;case "0":l.find(".animated,.success").hide().removeClass("visible").end().find(".error").show().addClass("visible");break;case "-2":l.find(".error,.success").hide().removeClass("visible").end().find(".animated").show().addClass("visible");
+break;default:l.find(".animated").hide().end().find(".error,.success").removeClass("visible")}else switch(d.toString()){case "1":l.addClass("success").removeClass("error");break;case "0":l.addClass("error").removeClass("success");break;case "-2":break;default:l.removeClass("error success")}}};a.bindingHandlers.emailsTags={init:function(a,g,l){var e=c(1),k=c(30),f=b(a),h=g();a=l().autoCompleteSource||null;f.inputosaurus({parseOnBlur:!0,allowDragAndDrop:!0,focusCallback:function(b){h&&h.focused&&h.focused(!!b)},
+inputDelimiters:[",",";","\n"],autoCompleteSource:a,parseHook:function(b){return d.map(b,function(b){b=e.trim(b);var a=null;return""!==b?(a=new k,a.mailsoParse(b),[a.toLine(!1),a]):[b,null]})},change:d.bind(function(b){f.data("EmailsTagsValue",b.target.value);h(b.target.value)},this)});h&&h.focused&&h.focused.subscribe&&h.focused.subscribe(function(b){f.inputosaurus(b?"focus":"blur")})},update:function(c,g){var d=b(c),l=g(),l=a.unwrap(l);d.data("EmailsTagsValue")!==l&&(d.val(l),d.data("EmailsTagsValue",
+l),d.inputosaurus("refresh"))}};a.bindingHandlers.command={init:function(c,g,d,l){var e=b(c),k=g();if(!k||!k.enabled||!k.canExecute)throw Error("You are not using command function");e.addClass("command");a.bindingHandlers[e.is("form")?"submit":"click"].init.apply(l,arguments)},update:function(a,c){var g=!0,d=b(a),l=c(),g=l.enabled();d.toggleClass("command-not-enabled",!g);g&&(g=l.canExecute(),d.toggleClass("command-can-not-be-execute",!g));d.toggleClass("command-disabled disable disabled",!g).toggleClass("no-disabled",
+!!g);(d.is("input")||d.is("button"))&&d.prop("disabled",!g)}};a.extenders.trimmer=function(b){var g=c(1),d=a.computed({read:b,write:function(a){b(g.trim(a.toString()))},owner:this});d(b());return d};a.extenders.posInterer=function(b,g){var d=c(1),l=a.computed({read:b,write:function(a){var c=d.pInt(a.toString(),g);0>=c&&(c=g);c===b()&&""+c!==""+a&&b(c+1);b(c)}});l(b());return l};a.extenders.limitedList=function(b,g){var d=c(1),l=a.computed({read:b,write:function(c){var l=a.unwrap(b),e=a.unwrap(g);
+d.isNonEmptyArray(e)?-1 ").addClass("rl-view-model").addClass("RL-"+l.viewModelTemplate()).hide(),
+u.appendTo(h),l.viewModelDom=u,a.__dom=u,"Popups"===f&&(l.cancelCommand=l.closeCommand=n.createCommand(l,function(){g.hideScreenPopup(a)}),l.modalVisibility.subscribe(function(b){var a=this;if(b){this.viewModelDom.show();this.storeAndSetKeyScope();k.popupVisibilityNames.push(this.viewModelName);l.viewModelDom.css("z-index",3E3+k.popupVisibilityNames().length+10);if(this.onShowTrigger)this.onShowTrigger(!this.onShowTrigger());n.delegateRun(this,"onShowWithDelay",[],500)}else{n.delegateRun(this,"onHide");
+n.delegateRun(this,"onHideWithDelay",[],500);if(this.onHideTrigger)this.onHideTrigger(!this.onHideTrigger());this.restoreKeyScope();e.each(this.viewModelNames,function(b){m.runHook("view-model-on-hide",[b,a])});k.popupVisibilityNames.remove(this.viewModelName);l.viewModelDom.css("z-index",2E3);e.delay(function(){a.viewModelDom.hide()},300)}},l)),e.each(a.__names,function(b){m.runHook("view-model-pre-build",[b,l,u])}),b.applyBindingAccessorsToNode(u[0],{translatorInit:!0,template:function(){return{name:l.viewModelTemplate()}}},
+l),n.delegateRun(l,"onBuild",[u]),l&&"Popups"===f&&l.registerPopupKeyDown(),e.each(a.__names,function(b){m.runHook("view-model-post-build",[b,l,u])})):n.log("Cannot find view model position: "+f)}return a?a.__vm:null};a.prototype.hideScreenPopup=function(b){b&&b.__vm&&b.__dom&&b.__vm.modalVisibility(!1)};a.prototype.showScreenPopup=function(b,a){b&&(this.buildViewModel(b),b.__vm&&b.__dom&&(n.delegateRun(b.__vm,"onBeforeShow",a||[]),b.__vm.modalVisibility(!0),n.delegateRun(b.__vm,"onShow",a||[]),e.each(b.__names,
+function(c){m.runHook("view-model-on-show",[c,b.__vm,a||[]])})))};a.prototype.isPopupVisible=function(b){return b&&b.__vm?b.__vm.modalVisibility():!1};a.prototype.screenOnRoute=function(b,a){var c=this,g=null,l=!1,d=null;""===n.pString(b)&&(b=this.sDefaultScreenName);""!==b&&(g=this.screen(b),!g&&(g=this.screen(this.sDefaultScreenName))&&(a=b+"/"+a,b=this.sDefaultScreenName),g&&g.__started&&(l=this.oCurrentScreen&&g===this.oCurrentScreen,g.__builded||(g.__builded=!0,n.isNonEmptyArray(g.viewModels())&&
+e.each(g.viewModels(),function(b){this.buildViewModel(b,g)},this),n.delegateRun(g,"onBuild")),e.defer(function(){if(c.oCurrentScreen&&!l){n.delegateRun(c.oCurrentScreen,"onHide");n.delegateRun(c.oCurrentScreen,"onHideWithDelay",[],500);if(c.oCurrentScreen.onHideTrigger)c.oCurrentScreen.onHideTrigger(!c.oCurrentScreen.onHideTrigger());n.isNonEmptyArray(c.oCurrentScreen.viewModels())&&e.each(c.oCurrentScreen.viewModels(),function(b){if(b.__vm&&b.__dom&&"Popups"!==b.__vm.viewModelPosition()&&(b.__dom.hide(),
+b.__vm.viewModelVisibility(!1),n.delegateRun(b.__vm,"onHide"),n.delegateRun(b.__vm,"onHideWithDelay",[],500),b.__vm.onHideTrigger))b.__vm.onHideTrigger(!b.__vm.onHideTrigger())})}c.oCurrentScreen=g;if(c.oCurrentScreen&&!l){n.delegateRun(c.oCurrentScreen,"onShow");if(c.oCurrentScreen.onShowTrigger)c.oCurrentScreen.onShowTrigger(!c.oCurrentScreen.onShowTrigger());m.runHook("screen-on-show",[c.oCurrentScreen.screenName(),c.oCurrentScreen]);n.isNonEmptyArray(c.oCurrentScreen.viewModels())&&e.each(c.oCurrentScreen.viewModels(),
+function(b){if(b.__vm&&b.__dom&&"Popups"!==b.__vm.viewModelPosition()){n.delegateRun(b.__vm,"onBeforeShow");b.__dom.show();b.__vm.viewModelVisibility(!0);n.delegateRun(b.__vm,"onShow");if(b.__vm.onShowTrigger)b.__vm.onShowTrigger(!b.__vm.onShowTrigger());n.delegateRun(b.__vm,"onShowWithDelay",[],200);e.each(b.__names,function(a){m.runHook("view-model-on-show",[a,b.__vm])})}},c)}(d=g.__cross?g.__cross():null)&&d.parse(a)})))};a.prototype.startScreens=function(b){d("#rl-content").css({visibility:"hidden"});
+e.each(b,function(b){if(b){var a=(b=new b)?b.screenName():"";b&&""!==a&&(""===this.sDefaultScreenName&&(this.sDefaultScreenName=a),this.oScreens[a]=b)}},this);e.each(this.oScreens,function(b){b&&!b.__started&&b.__start&&(b.__started=!0,b.__start(),m.runHook("screen-pre-start",[b.screenName(),b]),n.delegateRun(b,"onStart"),m.runHook("screen-post-start",[b.screenName(),b]))},this);b=l.create();b.addRoute(/^([a-zA-Z0-9\-]*)\/?(.*)$/,e.bind(this.screenOnRoute,this));g.initialized.add(b.parse,b);g.changed.add(b.parse,
+b);g.init();d("#rl-content").css({visibility:"visible"});e.delay(function(){k.$html.removeClass("rl-started-trigger").addClass("rl-started")},100);e.delay(function(){k.$html.addClass("rl-started-delay")},200)};a.prototype.setHash=function(b,a,c){b="#"===b.substr(0,1)?b.substr(1):b;b="/"===b.substr(0,1)?b.substr(1):b;c=n.isUnd(c)?!1:!!c;(n.isUnd(a)?0:a)?(g.changed.active=!1,g[c?"replaceHash":"setHash"](b),g.changed.active=!0):(g.changed.active=!0,g[c?"replaceHash":"setHash"](b),g.setHash(b))};h.exports=
+new a})()},function(h,f,c){function a(b){return b&&b.__esModule?b:{default:b}}var e=c(13);f=c(2);var d=a(f),b=c(4);f=c(1);var g=a(f);f=c(8);var l=a(f);f=function(){function a(){if(!(this instanceof a))throw new TypeError("Cannot call a class as a function");this.data={};this.notificationI18N={};this.data=e.window.rainloopI18N||{};this.trigger=d.default.observable(!1);this.i18n=e._.bind(this.i18n,this);this.init()}a.prototype.i18n=function(b,a,c){var g="",l=this.data[b];e._.isUndefined(l)&&(l=e._.isUndefined(c)?
+b:c);if(!e._.isUndefined(a)&&!e._.isNull(a))for(g in a)e._.has(a,g)&&(l=l.replace("%"+g+"%",a[g]));return l};a.prototype.i18nToNode=function(b){b=(0,e.$)(b);var a=b.data("i18n");if(a)if("["===a.substr(0,1))switch(a.substr(0,6)){case "[html]":b.html(this.i18n(a.substr(6)));break;case "[place":b.attr("placeholder",this.i18n(a.substr(13)));break;case "[title":b.attr("title",this.i18n(a.substr(7)))}else b.text(this.i18n(a))};a.prototype.i18nToNodes=function(b){var a=this,c=1>=arguments.length||void 0===
+arguments[1]?!1:arguments[1];e._.defer(function(){(0,e.$)("[data-i18n]",b).each(function(b,c){a.i18nToNode(c)});c&&l.default.bAnimationSupported&&(0,e.$)(".i18n-animation[data-i18n]",b).letterfx({fx:"fall fade",backwards:!1,timing:50,fx_duration:"50ms",letter_end:"restore",element_end:"restore"})})};a.prototype.reloadData=function(){e.window.rainloopI18N&&(this.data=e.window.rainloopI18N||{},this.i18nToNodes(e.window.document,!0),c(26).reload(),this.trigger(!this.trigger()));e.window.rainloopI18N=
+null};a.prototype.initNotificationLanguage=function(){var a=this,c=[[b.Notification.InvalidToken,"NOTIFICATIONS/INVALID_TOKEN"],[b.Notification.InvalidToken,"NOTIFICATIONS/INVALID_TOKEN"],[b.Notification.AuthError,"NOTIFICATIONS/AUTH_ERROR"],[b.Notification.AccessError,"NOTIFICATIONS/ACCESS_ERROR"],[b.Notification.ConnectionError,"NOTIFICATIONS/CONNECTION_ERROR"],[b.Notification.CaptchaError,"NOTIFICATIONS/CAPTCHA_ERROR"],[b.Notification.SocialFacebookLoginAccessDisable,"NOTIFICATIONS/SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE"],
+[b.Notification.SocialTwitterLoginAccessDisable,"NOTIFICATIONS/SOCIAL_TWITTER_LOGIN_ACCESS_DISABLE"],[b.Notification.SocialGoogleLoginAccessDisable,"NOTIFICATIONS/SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE"],[b.Notification.DomainNotAllowed,"NOTIFICATIONS/DOMAIN_NOT_ALLOWED"],[b.Notification.AccountNotAllowed,"NOTIFICATIONS/ACCOUNT_NOT_ALLOWED"],[b.Notification.AccountTwoFactorAuthRequired,"NOTIFICATIONS/ACCOUNT_TWO_FACTOR_AUTH_REQUIRED"],[b.Notification.AccountTwoFactorAuthError,"NOTIFICATIONS/ACCOUNT_TWO_FACTOR_AUTH_ERROR"],
+[b.Notification.CouldNotSaveNewPassword,"NOTIFICATIONS/COULD_NOT_SAVE_NEW_PASSWORD"],[b.Notification.CurrentPasswordIncorrect,"NOTIFICATIONS/CURRENT_PASSWORD_INCORRECT"],[b.Notification.NewPasswordShort,"NOTIFICATIONS/NEW_PASSWORD_SHORT"],[b.Notification.NewPasswordWeak,"NOTIFICATIONS/NEW_PASSWORD_WEAK"],[b.Notification.NewPasswordForbidden,"NOTIFICATIONS/NEW_PASSWORD_FORBIDDENT"],[b.Notification.ContactsSyncError,"NOTIFICATIONS/CONTACTS_SYNC_ERROR"],[b.Notification.CantGetMessageList,"NOTIFICATIONS/CANT_GET_MESSAGE_LIST"],
+[b.Notification.CantGetMessage,"NOTIFICATIONS/CANT_GET_MESSAGE"],[b.Notification.CantDeleteMessage,"NOTIFICATIONS/CANT_DELETE_MESSAGE"],[b.Notification.CantMoveMessage,"NOTIFICATIONS/CANT_MOVE_MESSAGE"],[b.Notification.CantCopyMessage,"NOTIFICATIONS/CANT_MOVE_MESSAGE"],[b.Notification.CantSaveMessage,"NOTIFICATIONS/CANT_SAVE_MESSAGE"],[b.Notification.CantSendMessage,"NOTIFICATIONS/CANT_SEND_MESSAGE"],[b.Notification.InvalidRecipients,"NOTIFICATIONS/INVALID_RECIPIENTS"],[b.Notification.CantSaveFilters,
+"NOTIFICATIONS/CANT_SAVE_FILTERS"],[b.Notification.CantGetFilters,"NOTIFICATIONS/CANT_GET_FILTERS"],[b.Notification.FiltersAreNotCorrect,"NOTIFICATIONS/FILTERS_ARE_NOT_CORRECT"],[b.Notification.CantCreateFolder,"NOTIFICATIONS/CANT_CREATE_FOLDER"],[b.Notification.CantRenameFolder,"NOTIFICATIONS/CANT_RENAME_FOLDER"],[b.Notification.CantDeleteFolder,"NOTIFICATIONS/CANT_DELETE_FOLDER"],[b.Notification.CantDeleteNonEmptyFolder,"NOTIFICATIONS/CANT_DELETE_NON_EMPTY_FOLDER"],[b.Notification.CantSubscribeFolder,
+"NOTIFICATIONS/CANT_SUBSCRIBE_FOLDER"],[b.Notification.CantUnsubscribeFolder,"NOTIFICATIONS/CANT_UNSUBSCRIBE_FOLDER"],[b.Notification.CantSaveSettings,"NOTIFICATIONS/CANT_SAVE_SETTINGS"],[b.Notification.CantSavePluginSettings,"NOTIFICATIONS/CANT_SAVE_PLUGIN_SETTINGS"],[b.Notification.DomainAlreadyExists,"NOTIFICATIONS/DOMAIN_ALREADY_EXISTS"],[b.Notification.CantInstallPackage,"NOTIFICATIONS/CANT_INSTALL_PACKAGE"],[b.Notification.CantDeletePackage,"NOTIFICATIONS/CANT_DELETE_PACKAGE"],[b.Notification.InvalidPluginPackage,
+"NOTIFICATIONS/INVALID_PLUGIN_PACKAGE"],[b.Notification.UnsupportedPluginPackage,"NOTIFICATIONS/UNSUPPORTED_PLUGIN_PACKAGE"],[b.Notification.LicensingServerIsUnavailable,"NOTIFICATIONS/LICENSING_SERVER_IS_UNAVAILABLE"],[b.Notification.LicensingExpired,"NOTIFICATIONS/LICENSING_EXPIRED"],[b.Notification.LicensingBanned,"NOTIFICATIONS/LICENSING_BANNED"],[b.Notification.DemoSendMessageError,"NOTIFICATIONS/DEMO_SEND_MESSAGE_ERROR"],[b.Notification.DemoAccountError,"NOTIFICATIONS/DEMO_ACCOUNT_ERROR"],[b.Notification.AccountAlreadyExists,
+"NOTIFICATIONS/ACCOUNT_ALREADY_EXISTS"],[b.Notification.AccountDoesNotExist,"NOTIFICATIONS/ACCOUNT_DOES_NOT_EXIST"],[b.Notification.MailServerError,"NOTIFICATIONS/MAIL_SERVER_ERROR"],[b.Notification.InvalidInputArgument,"NOTIFICATIONS/INVALID_INPUT_ARGUMENT"],[b.Notification.UnknownNotification,"NOTIFICATIONS/UNKNOWN_ERROR"],[b.Notification.UnknownError,"NOTIFICATIONS/UNKNOWN_ERROR"]];this.notificationI18N=this.notificationI18N||{};c.forEach(function(b){a.notificationI18N[b[0]]=a.i18n(b[1])})};a.prototype.initOnStartOrLangChange=
+function(b,a){var c=2>=arguments.length||void 0===arguments[2]?null:arguments[2];b&&b.call(a);c?this.trigger.subscribe(function(){b&&b.call(a);c.call(a)}):b&&this.trigger.subscribe(b,a)};a.prototype.getNotification=function(a){var c=1>=arguments.length||void 0===arguments[1]?"":arguments[1],g=2>=arguments.length||void 0===arguments[2]?null:arguments[2];a=e.window.parseInt(a,10)||0;if(b.Notification.ClientViewError===a&&c)return c;g=g?e.window.parseInt(g,10)||0:0;return e._.isUndefined(this.notificationI18N[a])?
+g&&e._.isUndefined(this.notificationI18N[g])?this.notificationI18N[g]:"":this.notificationI18N[a]};a.prototype.getNotificationFromResponse=function(a){var c=1>=arguments.length||void 0===arguments[1]?b.Notification.UnknownNotification:arguments[1];return a&&a.ErrorCode?this.getNotification(g.default.pInt(a.ErrorCode),a.ErrorMessage||""):this.getNotification(c)};a.prototype.getUploadErrorDescByCode=function(a){var c="";switch(e.window.parseInt(a,10)||0){case b.UploadErrorCode.FileIsTooBig:c=this.i18n("UPLOAD/ERROR_FILE_IS_TOO_BIG");
+break;case b.UploadErrorCode.FilePartiallyUploaded:c=this.i18n("UPLOAD/ERROR_FILE_PARTIALLY_UPLOADED");break;case b.UploadErrorCode.FileNoUploaded:c=this.i18n("UPLOAD/ERROR_NO_FILE_UPLOADED");break;case b.UploadErrorCode.MissingTempFolder:c=this.i18n("UPLOAD/ERROR_MISSING_TEMP_FOLDER");break;case b.UploadErrorCode.FileOnSaveingError:c=this.i18n("UPLOAD/ERROR_ON_SAVING_FILE");break;case b.UploadErrorCode.FileType:c=this.i18n("UPLOAD/ERROR_FILE_TYPE");break;default:c=this.i18n("UPLOAD/ERROR_UNKNOWN")}return c};
+a.prototype.reload=function(b,a,d,k){var f=this,h=g.default.microtime();l.default.$html.addClass("rl-changing-language");e.$.ajax({url:c(12).langLink(a,b),dataType:"script",cache:!0}).fail(k||g.default.emptyFunction).done(function(){e._.delay(function(){f.reloadData();(d||g.default.emptyFunction)();var b=-1 ");a.$win.__sizes=[0,0];a.startMicrotime=(new e.Date).getTime();a.community=!0;a.dropdownVisibility=g.observable(!1).extend({rateLimit:0});a.useKeyboardShortcuts=g.observable(!0);a.iAjaxErrorCount=
+0;a.iTokenErrorCount=0;a.iMessageBodyCacheCount=0;a.bUnload=!1;a.sUserAgent="navigator"in e&&"userAgent"in e.navigator&&e.navigator.userAgent.toLowerCase()||"";a.bIE=-1=arguments.length||void 0===arguments[0]?"":arguments[0])};b.prototype.rootAdmin=function(){return this.sServer+this.sAdminPath};b.prototype.rootUser=function(){return(0>=arguments.length||
+void 0===arguments[0]?0:arguments[0])?"./?/Mobile/":"./"};b.prototype.attachmentRaw=function(b,a,c){c=e.default.isUnd(c)?this.sAuthSuffix:c;return this.sServer+"/Raw/"+this.subQueryPrefix()+"/"+c+"/"+b+"/"+this.subQueryPrefix()+"/"+a};b.prototype.attachmentDownload=function(b,a){return this.attachmentRaw("Download",b,a)};b.prototype.attachmentPreview=function(b,a){return this.attachmentRaw("View",b,a)};b.prototype.attachmentThumbnailPreview=function(b,a){return this.attachmentRaw("ViewThumbnail",
+b,a)};b.prototype.attachmentPreviewAsPlain=function(b,a){return this.attachmentRaw("ViewAsPlain",b,a)};b.prototype.attachmentFramed=function(b,a){return this.attachmentRaw("FramedView",b,a)};b.prototype.upload=function(){return this.sServer+"/Upload/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/"};b.prototype.uploadContacts=function(){return this.sServer+"/UploadContacts/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/"};b.prototype.uploadBackground=function(){return this.sServer+"/UploadBackground/"+
+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/"};b.prototype.append=function(){return this.sServer+"/Append/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/"};b.prototype.change=function(b){return this.sServer+"/Change/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/"+e.default.encodeURIComponent(b)+"/"};b.prototype.ajax=function(b){return this.sServer+"/Ajax/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/"+b};b.prototype.messageViewLink=function(b){return this.sServer+"/Raw/"+this.subQueryPrefix()+
+"/"+this.sAuthSuffix+"/ViewAsPlain/"+this.subQueryPrefix()+"/"+b};b.prototype.messageDownloadLink=function(b){return this.sServer+"/Raw/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/Download/"+this.subQueryPrefix()+"/"+b};b.prototype.avatarLink=function(b){return this.sServer+"/Raw/0/Avatar/"+e.default.encodeURIComponent(b)+"/"};b.prototype.publicLink=function(b){return this.sServer+"/Raw/0/Public/"+b+"/"};b.prototype.userBackground=function(b){return this.sServer+"/Raw/"+this.subQueryPrefix()+"/"+
+this.sAuthSuffix+"/UserBackground/"+this.subQueryPrefix()+"/"+b};b.prototype.inbox=function(){return this.sBase+"mailbox/"+(0>=arguments.length||void 0===arguments[0]?"INBOX":arguments[0])};b.prototype.settings=function(){var b=0>=arguments.length||void 0===arguments[0]?"":arguments[0];return this.sBase+"settings"+(b?"/"+b:"")};b.prototype.about=function(){return this.sBase+"about"};b.prototype.admin=function(b){var a=this.sBase;switch(b){case "AdminDomains":a+="domains";break;case "AdminSecurity":a+=
+"security";break;case "AdminLicensing":a+="licensing"}return a};b.prototype.mailBox=function(b){var c=1>=arguments.length||void 0===arguments[1]?1:arguments[1],d=2>=arguments.length||void 0===arguments[2]?"":arguments[2],f=3>=arguments.length||void 0===arguments[3]?"":arguments[3],c=e.default.isNormal(c)?e.default.pInt(c):1,d=e.default.pString(d),n=this.sBase+"mailbox/";""!==b&&(f=e.default.pInt(f),n+=a.window.encodeURI(b)+(0=arguments.length||void 0===arguments[0]?!1:arguments[0];return this.sServer+"SocialGoogle"+(""!==this.sAuthSuffix?"/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/":"")+(b?"&xauth=1":"")};b.prototype.socialTwitter=function(){return this.sServer+"SocialTwitter"+
+(""!==this.sAuthSuffix?"/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/":"")};b.prototype.socialFacebook=function(){return this.sServer+"SocialFacebook"+(""!==this.sAuthSuffix?"/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/":"")};return b}();h.exports=new c},function(h,f,c){function a(b){return b&&b.__esModule?b:{default:b}}f.__esModule=!0;f.key=f.moment=f.Q=f._=f.JSON=f.$=f.window=void 0;h=c(11);h=a(h);var e=c(14),e=a(e),d=c(36),d=a(d),b=c(3),b=a(b),g=c(48),g=a(g),l=c(82),l=a(l);c=c(18);c=a(c);
+f.window=h.default;f.$=e.default;f.JSON=d.default;f._=b.default;f.Q=g.default;f.moment=l.default;f.key=c.default},function(h,f){h.exports=window.jQuery},,function(h,f,c){f.__esModule=!0;f.componentExportHelper=f.AbstractComponent=void 0;var a=c(13),e=(h=c(2))&&h.__esModule?h:{default:h},d=(h=c(1))&&h.__esModule?h:{default:h};h=function(){function b(){if(!(this instanceof b))throw new TypeError("Cannot call a class as a function");this.disposable=[]}b.prototype.dispose=function(){this.disposable.forEach(function(b){b&&
+b.dispose&&b.dispose()})};return b}();f.AbstractComponent=h;f.componentExportHelper=function(b){var g=1>=arguments.length||void 0===arguments[1]?"":arguments[1];return{template:g?{element:g}:" ",viewModel:{createViewModel:function(g,k){g=g||{};g.element=null;k&&k.element&&(g.component=k,g.element=(0,a.$)(k.element),c(6).i18nToNodes(g.element),!d.default.isUnd(g.inline)&&e.default.unwrap(g.inline)&&g.element.css("display","inline-block"));return new b(g)}}}}},function(h,f){f.__esModule=!0;f.MESSAGES_PER_PAGE=
+20;f.MESSAGES_PER_PAGE_VALUES=[10,20,30,50,100];f.CONTACTS_PER_PAGE=50;f.DEFAULT_AJAX_TIMEOUT=3E4;f.SEARCH_AJAX_TIMEOUT=3E5;f.SEND_MESSAGE_AJAX_TIMEOUT=3E5;f.SAVE_MESSAGE_AJAX_TIMEOUT=2E5;f.CONTACTS_SYNC_AJAX_TIMEOUT=2E5;f.UNUSED_OPTION_VALUE="__UNUSE__";f.CLIENT_SIDE_STORAGE_INDEX_NAME="rlcsc";f.IMAP_DEFAULT_PORT=143;f.IMAP_DEFAULT_SECURE_PORT=993;f.SMTP_DEFAULT_PORT=25;f.SMTP_DEFAULT_SECURE_PORT=465;f.SIEVE_DEFAULT_PORT=4190;f.MESSAGE_BODY_CACHE_LIMIT=15;f.AJAX_ERROR_LIMIT=7;f.TOKEN_ERROR_LIMIT=
+10;f.RAINLOOP_TRIAL_KEY="RAINLOOP-TRIAL-KEY";f.DATA_IMAGE_USER_DOT_PIC="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAuCAYAAABXuSs3AAAHHklEQVRoQ7VZW08bVxCeXRuwIbTGXIwNtBBaqjwgVUiR8lDlbza9qe1DpVZ9aNQ/0KpPeaJK07SpcuEeCEmUAObm21bfrL9lONjexSYrWfbunj37zXdmvpkz9oIgCKTD0Wg0xPd94TDP83Q0zvWa50vzklSrdanVanqf4/D84GBGr+F+Op3S8fqoJxLOdnZgTvsO/nYhenHA+UC7CWF1uXwkb9++ldPTUwVerVbVqFQqpR8YPjQ0JCMjI5LNDijoRgP3PQVu5+5Eor2XGLg7IV4GkIdHJ/LmzRs5ODiIwNbrdR0O0GCcq4Xz4eFhmZyclP7+tDQaIik/BG5XKQn4SwG3zJTLZXn9+rUclI8UHD5YVoDDN8bSzXhONwL48fFxGR4eilzFZT1uFRIB5yT8BqCdnR3Z3d0VP9Un6XRawYJpggVrZBv38ME4XKtUKnLt2jUplUoy1PR/l3U7T6sVSAQcgMAkj8PDQ9ne3pajoyMRL7zeKsYZWHgWYDGmv78/mmdwcFA+mJlSgziHDWrERrsjEXDXegTi1tZW+DLxI2bxIrqFNYTXyDyCFweMAHCwb8e4RnTNuOsqe3t7sra21pTD0Kct666E8XlcZyzw9/RUUXK5nK5oUinUQI6TQ3cynO/v78vq6qrKXCNwlTiJJpyNGc3nZHp6uqV2dwrQWOCtZBDAV1ZWwsQk7f0wiQn5kffbAu/0/KWBYzIC1+XukfGx0RGZmppKlC2tIV0Bh4aDcZW7HhkfH8urLLZL7T2pihvlkMNnz56FiadHxicL41IsFpN41bkxsYxbRdFo9jwB8KdPn14J8KnSpBQKhQs63nPmbCVRcBUAR2Lq1VVmpksyMTFxAXjcEsQybiegESionjx5osCZOeNe1O4+EhCAX7bQSgQcxRHTMgAgcz5+/Dis/hL4uHU3/B4YGNASGHIKxuEql0k+l05AeIAF1vPnz5VxFFmdDlaJrMtZITJeSsXCOTlMunKxjLtMYOKNjQ158eJFuAuKkUOb5sEwgff19SkJUBVkThZUbnXZrtCKBQ6gbnWIkjZpyne3ejAWoGnA7Icz6irvBLgbOMicCM6TkxPx/LAkbXfgWcsazuE2kFRsKD5Z+CiqDumKncpZvieWcS6dDVD8xiYCNflpJdwcdwJOf9airLmVQ7DPzMxIYWLsXGXoVqLt5k0M3K3JUVPDZdbWNzsCp48TPFdvdnZWUz32nDha7bJ63kgAJPzSdRks9/Kf9xMJAQ1gq2NpaUmy2Yz4zar4nQC3xb99AQwCcGzLAAwuhG8YiWvcOKts+r4GOe5nMhm5efOm9lUA3E3vSZJRrKvE0fnPv//Jy5cvo5cTHIPQbSjhOoqq69evS19f6lxDKK4+sVhigZPtKJqbrQeqxd5+WR4+fKgqgT0k2XX3nhiPgETWXFhYkFzuPZ2yVq1GTSOXpE47/VjgNnD4m4GG7/LhsTx69EiwD4Vr2MwIIxgbAH18fKx1yfz8vEogNvGtWnCuhLZa9UTAreVWFsHy/b/+Vrbdl7E5REMQD2jDoUbByty+/ZnU64GkU2HzyJLhktU1cLv8nARgkYS2d3ajAgwG8qU2oLmDZ92CMaOjo7K4uCiZgbDWaRWgnZhPxLhrMUCvr69riwKZk1LHF7XqrWAO9hJxH6ozNzcnCx/PqztZg9mf6SQMscCtm2C5ke4BGMlHWTUp36036AJajDVrFMzBrhhWslQsSrFYiOqVpMriNYIgqFRq2j3FAb/zffT6zuxFXxsNzs3NTXn16lW4gYiW96w1FyedF+83xG/2FNGCRpU4NjamMsn+OZ9xE5RXqdaDdPpib6RWCzuwKF9RxqI2AVNQBwQYJoK0wdBejnqtEikP3pfP51XjUTESl12FqJEKxsEorARYDD44ONTeID7YpsEnrRvQfWAI2e8WfDaTUSIwJ0iBCmFOtOUAHvVMPp/TPwvYFVYFIuP8l+DBgwdaa2Miqwa0GgYwfeMltovbDfh6c1vIgMYcliSsKv4IWFr6VDHxvldvBAH+1sA+cnl5WYOPmmr9ir+1l9I0Cgz0yjhXjfJJ0JROnmezWbl165ayr/5fqwcBNr7IfhjMqKcvESSM4eRcCasQ3bDNObmKPLdGUGpZsN24cUNLBm9zazu4d++e6qpNBFaTuUS26U5dpuR1CxyA7J9ddrMRqlz4pwLLYawymPd++/2PADt2ugcGwq9gCCdhQ96C6xWwa6j1ceuq+I0EhW0i8MAIVJfeL3d/DVD8EKi12P6/2S2jV/EccVB54O/ejz/9HGCpoBBMta5rXMXLu53D1XAwjhXwvvv+h4BAXVe4bOu3O3ChxF08LiZFG3fel199G9CH3fLyqv24NcB44MRhpdK788U3CpyKwsCw590xmfSpzsBt0Fqc3ud3vtZigxWcVZCklVpSiN0w3q5E/h9TGMIUuA3+EQAAAABJRU5ErkJggg==";
+f.DATA_IMAGE_TRANSP_PIC="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2NkAAIAAAoAAggA9GkAAAAASUVORK5CYII="},function(h,f){h.exports=window.key},,function(h,f,c){(function(){function a(){d.call(this);this.oRequests={}}var e=c(3),d=c(55);e.extend(a.prototype,d.prototype);a.prototype.adminLogin=function(b,a,c){this.defaultRequest(b,"AdminLogin",{Login:a,Password:c})};a.prototype.adminLogout=function(b){this.defaultRequest(b,"AdminLogout")};a.prototype.saveAdminConfig=
+function(b,a){this.defaultRequest(b,"AdminSettingsUpdate",a)};a.prototype.domainList=function(b){this.defaultRequest(b,"AdminDomainList")};a.prototype.pluginList=function(b){this.defaultRequest(b,"AdminPluginList")};a.prototype.packagesList=function(b){this.defaultRequest(b,"AdminPackagesList")};a.prototype.coreData=function(b){this.defaultRequest(b,"AdminCoreData")};a.prototype.updateCoreData=function(b){this.defaultRequest(b,"AdminUpdateCoreData",{},9E4)};a.prototype.packageInstall=function(b,a){this.defaultRequest(b,
+"AdminPackageInstall",{Id:a.id,Type:a.type,File:a.file},6E4)};a.prototype.packageDelete=function(b,a){this.defaultRequest(b,"AdminPackageDelete",{Id:a.id})};a.prototype.domain=function(b,a){this.defaultRequest(b,"AdminDomainLoad",{Name:a})};a.prototype.plugin=function(b,a){this.defaultRequest(b,"AdminPluginLoad",{Name:a})};a.prototype.domainDelete=function(b,a){this.defaultRequest(b,"AdminDomainDelete",{Name:a})};a.prototype.domainDisable=function(b,a,c){return this.defaultRequest(b,"AdminDomainDisable",
+{Name:a,Disabled:c?"1":"0"})};a.prototype.pluginSettingsUpdate=function(b,a){return this.defaultRequest(b,"AdminPluginSettingsUpdate",a)};a.prototype.licensing=function(b,a){return this.defaultRequest(b,"AdminLicensing",{Force:a?"1":"0"})};a.prototype.licensingActivate=function(b,a,c){return this.defaultRequest(b,"AdminLicensingActivate",{Domain:a,Key:c})};a.prototype.pluginDisable=function(b,a,c){return this.defaultRequest(b,"AdminPluginDisable",{Name:a,Disabled:c?"1":"0"})};a.prototype.createOrUpdateDomain=
+function(b,a,c,d,e,f,h,r,q,t,w,v,u,z,B,E,C,x,F){this.defaultRequest(b,"AdminDomainSave",{Create:a?"1":"0",Name:c,IncHost:d,IncPort:e,IncSecure:f,IncShortLogin:h?"1":"0",UseSieve:r?"1":"0",SieveAllowRaw:q?"1":"0",SieveHost:t,SievePort:w,SieveSecure:v,OutHost:u,OutPort:z,OutSecure:B,OutShortLogin:E?"1":"0",OutAuth:C?"1":"0",OutUsePhpMail:x?"1":"0",WhiteList:F})};a.prototype.testConnectionForDomain=function(b,a,c,d,e,f,h,r,q,t,w,v,u,z){this.defaultRequest(b,"AdminDomainTest",{Name:a,IncHost:c,IncPort:d,
+IncSecure:e,UseSieve:f?"1":"0",SieveHost:h,SievePort:r,SieveSecure:q,OutHost:t,OutPort:w,OutSecure:v,OutAuth:u?"1":"0",OutUsePhpMail:z?"1":"0"})};a.prototype.testContacts=function(b,a){this.defaultRequest(b,"AdminContactsTest",a)};a.prototype.saveNewAdminPassword=function(b,a){this.defaultRequest(b,"AdminPasswordUpdate",a)};a.prototype.adminPing=function(b){this.defaultRequest(b,"AdminPing")};h.exports=new a})()},,function(h,f,c){function a(b){return b&&b.__esModule?b:{default:b}}function e(b,a){if("function"!==
+typeof a&&null!==a)throw new TypeError("Super expression must either be null or a function, not "+typeof a);b.prototype=Object.create(a&&a.prototype,{constructor:{value:b,enumerable:!1,writable:!0,configurable:!0}});a&&(Object.setPrototypeOf?Object.setPrototypeOf(b,a):b.__proto__=a)}f.__esModule=!0;var d=c(13);h=c(2);var b=a(h);h=c(83);var g=a(h),l=function(b){if(b&&b.__esModule)return b;var a={};if(null!=b)for(var c in b)Object.prototype.hasOwnProperty.call(b,c)&&(a[c]=b[c]);a.default=b;return a}(c(4));
+h=c(1);var k=a(h);h=c(12);var m=a(h);h=c(6);var n=a(h);h=c(9);var p=a(h);h=c(35);var r=a(h);h=c(57);var q=a(h);h=c(59);var t=a(h);h=c(139);var w=a(h);h=c(58);var v=a(h);h=c(89);var u=a(h);h=c(20);var z=a(h);h=c(5);var B=a(h);h=new (function(a){function f(){if(!(this instanceof f))throw new TypeError("Cannot call a class as a function");var b=a.call(this,z.default);if(!this)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!b||"object"!==typeof b&&"function"!==
+typeof b?this:b}e(f,a);f.prototype.remote=function(){return z.default};f.prototype.reloadDomainList=function(){q.default.domains.loading(!0);z.default.domainList(function(a,c){q.default.domains.loading(!1);l.StorageResultType.Success===a&&c&&c.Result&&q.default.domains(d._.map(c.Result,function(a,c){return{name:c,disabled:b.default.observable(!a),deleteAccess:b.default.observable(!1)}}))})};f.prototype.reloadPluginList=function(){t.default.plugins.loading(!0);z.default.pluginList(function(a,c){t.default.plugins.loading(!1);
+l.StorageResultType.Success===a&&c&&c.Result&&t.default.plugins(d._.map(c.Result,function(a){return{name:a.Name,disabled:b.default.observable(!a.Enabled),configured:b.default.observable(!!a.Configured)}}))})};f.prototype.reloadPackagesList=function(){v.default.packages.loading(!0);v.default.packagesReal(!0);z.default.packagesList(function(a,c){v.default.packages.loading(!1);l.StorageResultType.Success===a&&c&&c.Result?function(){v.default.packagesReal(!!c.Result.Real);v.default.packagesMainUpdatable(!!c.Result.MainUpdatable);
+var a=[],g={};d._.each(v.default.packages(),function(b){b&&b.loading()&&(g[b.file]=b)});k.default.isArray(c.Result.List)&&(a=d._.compact(d._.map(c.Result.List,function(a){return a?(a.loading=b.default.observable(!k.default.isUnd(g[a.file])),"core"!==a.type||a.canBeInstalled?a:null):null})));v.default.packages(a)}():v.default.packagesReal(!1)})};f.prototype.updateCoreData=function(){u.default.coreUpdating(!0);z.default.updateCoreData(function(b,a){u.default.coreUpdating(!1);u.default.coreVersion("");
+u.default.coreRemoteVersion("");u.default.coreRemoteRelease("");u.default.coreVersionCompare(-2);l.StorageResultType.Success===b&&a&&a.Result?(u.default.coreReal(!0),d.window.location.reload()):u.default.coreReal(!1)})};f.prototype.reloadCoreData=function(){u.default.coreChecking(!0);u.default.coreReal(!0);z.default.coreData(function(b,a){u.default.coreChecking(!1);l.StorageResultType.Success===b&&a&&a.Result?(u.default.coreReal(!!a.Result.Real),u.default.coreChannel(a.Result.Channel||"stable"),u.default.coreType(a.Result.Type||
+"stable"),u.default.coreUpdatable(!!a.Result.Updatable),u.default.coreAccess(!!a.Result.Access),u.default.coreWarning(!!a.Result.Warning),u.default.coreVersion(a.Result.Version||""),u.default.coreRemoteVersion(a.Result.RemoteVersion||""),u.default.coreRemoteRelease(a.Result.RemoteRelease||""),u.default.coreVersionCompare(k.default.pInt(a.Result.VersionCompare))):(u.default.coreReal(!1),u.default.coreChannel("stable"),u.default.coreType("stable"),u.default.coreWarning(!1),u.default.coreVersion(""),
+u.default.coreRemoteVersion(""),u.default.coreRemoteRelease(""),u.default.coreVersionCompare(-2))})};f.prototype.reloadLicensing=function(){var b=0>=arguments.length||void 0===arguments[0]?!1:arguments[0];w.default.licensingProcess(!0);w.default.licenseError("");z.default.licensing(function(b,a){w.default.licensingProcess(!1);l.StorageResultType.Success===b&&a&&a.Result&&k.default.isNormal(a.Result.Expired)?(w.default.licenseValid(!0),w.default.licenseExpired(k.default.pInt(a.Result.Expired)),w.default.licenseError(""),
+w.default.licensing(!0),r.default.prem(!0)):a&&a.ErrorCode&&-1=arguments.length||void 0===arguments[0]?null:arguments[0];g.default&&g.default.end();b&&b()};f.prototype.bootstart=function(){a.prototype.bootstart.call(this);c(35).populate();c(50).populate();B.default.hideLoading();p.default.appSettingsGet("allowAdminPanel")?p.default.settingsGet("Auth")?B.default.startScreens([c(114)]):B.default.startScreens([c(113)]):(B.default.routeOff(),B.default.setHash(m.default.root(),!0),B.default.routeOff(),d._.defer(function(){d.window.location.href="/"}));this.bootend()};
+return f}(c(64).AbstractApp));f.default=h},function(h,f,c){function a(b){return b&&b.__esModule?b:{default:b}}var e=c(13);f=c(1);var d=a(f);f=c(8);var b=a(f);f=c(9);var g=a(f);f=function(){function a(){if(!(this instanceof a))throw new TypeError("Cannot call a class as a function");this.oSimpleHooks={};this.aUserViewModelsHooks=[];this.aAdminViewModelsHooks=[]}a.prototype.addHook=function(b,a){d.default.isFunc(a)&&(d.default.isArray(this.oSimpleHooks[b])||(this.oSimpleHooks[b]=[]),this.oSimpleHooks[b].push(a))};
+a.prototype.runHook=function(b){var a=1>=arguments.length||void 0===arguments[1]?[]:arguments[1];d.default.isArray(this.oSimpleHooks[b])&&e._.each(this.oSimpleHooks[b],function(b){b.apply(null,a)})};a.prototype.mainSettingsGet=function(b){return g.default.settingsGet(b)};a.prototype.remoteRequest=function(a,c,d,g){b.default.__APP__&&b.default.__APP__.remote().defaultRequest(a,"Plugin"+c,d,g)};a.prototype.addSettingsViewModel=function(b,a,c,d){this.aUserViewModelsHooks.push([b,a,c,d])};a.prototype.addSettingsViewModelForAdmin=
+function(b,a,c,d){this.aAdminViewModelsHooks.push([b,a,c,d])};a.prototype.runSettingsViewModelHooks=function(b){var a=c(5);e._.each(b?this.aAdminViewModelsHooks:this.aUserViewModelsHooks,function(b){a.addSettingsViewModel(b[0],b[1],b[2],b[3])})};a.prototype.settingsGet=function(b,a){var c=g.default.settingsGet("Plugins");return(c=c&&!d.default.isUnd(c[b])?c[b]:null)?d.default.isUnd(c[a])?null:c[a]:null};return a}();h.exports=new f},,function(h,f,c){var a=c(13),e=(f=c(1))&&f.__esModule?f:{default:f},
+d=(c=c(23))&&c.__esModule?c:{default:c};c=function(){function b(){if(!(this instanceof b))throw new TypeError("Cannot call a class as a function");this.subs={}}b.prototype.sub=function(b,c,d){var f=this;e.default.isObject(b)?(d=c||null,c=null,a._.each(b,function(b,a){f.sub(a,b,d)},this)):(e.default.isUnd(this.subs[b])&&(this.subs[b]=[]),this.subs[b].push([c,d]));return this};b.prototype.pub=function(b,c){d.default.runHook("rl-pub",[b,c]);e.default.isUnd(this.subs[b])||a._.each(this.subs[b],function(b){b[0]&&
+b[0].apply(b[1]||null,c||[])});return this};return b}();h.exports=new c},function(h,f,c){var a=c(13),e=(f=c(6))&&f.__esModule?f:{default:f};f=function(){function c(){var b=this;if(!(this instanceof c))throw new TypeError("Cannot call a class as a function");this._moment=null;this._momentNow=0;this.updateMomentNow=a._.debounce(function(){b._moment=(0,a.moment)()},500,!0);this.updateMomentNowUnix=a._.debounce(function(){b._momentNow=(0,a.moment)().unix()},500,!0);this.format=a._.bind(this.format,this)}
+c.prototype.momentNow=function(){this.updateMomentNow();return this._moment||(0,a.moment)()};c.prototype.momentNowUnix=function(){this.updateMomentNowUnix();return this._momentNow||0};c.prototype.searchSubtractFormatDateHelper=function(b){return this.momentNow().clone().subtract("days",b).format("YYYY.MM.DD")};c.prototype.formatCustomShortDate=function(b){var a=this.momentNow();if(b&&a)switch(!0){case 4>=a.diff(b,"hours"):return b.fromNow();case a.format("L")===b.format("L"):return e.default.i18n("MESSAGE_LIST/TODAY_AT",
+{TIME:b.format("LT")});case a.clone().subtract("days",1).format("L")===b.format("L"):return e.default.i18n("MESSAGE_LIST/YESTERDAY_AT",{TIME:b.format("LT")});case a.year()===b.year():return b.format("D MMM.")}return b?b.format("LL"):""};c.prototype.format=function(b,c){var d=null,e="",d=this.momentNowUnix();b=0,]+)>?,? ?/g.exec(a);b?(this.name=b[1]||"",this.email=b[2]||"",this.clearDuplicateName()):/^[^@]+@[^@]+$/.test(a)&&(this.name="",this.email=a)};a.prototype.initByJson=function(a){var b=!1;a&&"Object/Email"===a["@Object"]&&(this.name=e.trim(a.Name),this.email=e.trim(a.Email),this.dkimStatus=e.trim(a.DkimStatus||""),this.dkimValue=e.trim(a.DkimValue||""),b=""!==this.email,this.clearDuplicateName());return b};a.prototype.toLine=
+function(a,b,c){var l="";""!==this.email&&(b=e.isUnd(b)?!1:!!b,c=e.isUnd(c)?!1:!!c,a&&""!==this.name?l=b?'")+'" target="_blank" tabindex="-1">'+e.encodeHtml(this.name)+" ":c?e.encodeHtml(this.name):this.name:(l=this.email,""!==this.name?b?l=e.encodeHtml('"'+this.name+'" <')+'")+'" target="_blank" tabindex="-1">'+e.encodeHtml(l)+" "+e.encodeHtml(">"):(l='"'+this.name+
+'" <'+l+">",c&&(l=e.encodeHtml(l))):b&&(l=''+e.encodeHtml(this.email)+" ")));return l};a.prototype.mailsoParse=function(a){a=e.trim(a);if(""===a)return!1;for(var b=function(b,a,c){b+="";var d=b.length;0>a&&(a+=d);d="undefined"===typeof c?d:0>c?c+d:c+a;return a>=b.length||0>a||a>d?!1:b.slice(a,d)},c=function(b,a,c,d){0>c&&(c+=b.length);d=void 0!==d?d:b.length;0>d&&(d=d+b.length-c);return b.slice(0,c)+a.substr(0,d)+a.slice(d)+
+b.slice(c+d)},l="",k="",f="",h=!1,p=!1,r=!1,q=null,t=q=0,t=0;t":p&&(k=b(a,q+1,t-q-1),a=c(a,"",q,t-q+1),q=t=t=0,p=!1);break;case "(":h||p||r||(r=!0,q=t);break;case ")":r&&(f=b(a,q+1,t-q-1),a=c(a,"",q,t-q+1),q=t=t=0,r=!1);break;case "\\":t++}t++}0===k.length&&((q=a.match(/[^@\s]+@\S+/i))&&q[0]?k=q[0]:l=a);
+0]+$/,"");l=e.trim(l).replace(/^["']+/,"").replace(/["']+$/,"");f=e.trim(f).replace(/^[(]+/,"").replace(/[)]+$/,"");l=l.replace(/\\\\(.)/g,"$1");f=f.replace(/\\\\(.)/g,"$1");this.name=l;this.email=k;this.clearDuplicateName();return!0};h.exports=a})()},,,,function(h,f,c){(function(){function a(){this.google={};this.twitter={};this.facebook={};this.dropbox={};this.google.enabled=e.observable(!1);this.google.clientID=
+e.observable("");this.google.clientSecret=e.observable("");this.google.apiKey=e.observable("");this.google.loading=e.observable(!1);this.google.userName=e.observable("");this.google.loggined=e.computed(function(){return""!==this.google.userName()},this);this.google.capa={};this.google.capa.auth=e.observable(!1);this.google.capa.authFast=e.observable(!1);this.google.capa.drive=e.observable(!1);this.google.capa.preview=e.observable(!1);this.google.require={};this.google.require.clientSettings=e.computed(function(){return this.google.enabled()&&
+(this.google.capa.auth()||this.google.capa.drive())},this);this.google.require.apiKeySettings=e.computed(function(){return this.google.enabled()&&this.google.capa.drive()},this);this.facebook.enabled=e.observable(!1);this.facebook.appID=e.observable("");this.facebook.appSecret=e.observable("");this.facebook.loading=e.observable(!1);this.facebook.userName=e.observable("");this.facebook.supported=e.observable(!1);this.facebook.loggined=e.computed(function(){return""!==this.facebook.userName()},this);
+this.twitter.enabled=e.observable(!1);this.twitter.consumerKey=e.observable("");this.twitter.consumerSecret=e.observable("");this.twitter.loading=e.observable(!1);this.twitter.userName=e.observable("");this.twitter.loggined=e.computed(function(){return""!==this.twitter.userName()},this);this.dropbox.enabled=e.observable(!1);this.dropbox.apiKey=e.observable("")}var e=c(2);a.prototype.google={};a.prototype.twitter={};a.prototype.facebook={};a.prototype.dropbox={};a.prototype.populate=function(){var a=
+c(9);this.google.enabled(!!a.settingsGet("AllowGoogleSocial"));this.google.clientID(a.settingsGet("GoogleClientID"));this.google.clientSecret(a.settingsGet("GoogleClientSecret"));this.google.apiKey(a.settingsGet("GoogleApiKey"));this.google.capa.auth(!!a.settingsGet("AllowGoogleSocialAuth"));this.google.capa.authFast(!!a.settingsGet("AllowGoogleSocialAuthFast"));this.google.capa.drive(!!a.settingsGet("AllowGoogleSocialDrive"));this.google.capa.preview(!!a.settingsGet("AllowGoogleSocialPreview"));
+this.facebook.enabled(!!a.settingsGet("AllowFacebookSocial"));this.facebook.appID(a.settingsGet("FacebookAppID"));this.facebook.appSecret(a.settingsGet("FacebookAppSecret"));this.facebook.supported(!!a.settingsGet("SupportedFacebookSocial"));this.twitter.enabled=e.observable(!!a.settingsGet("AllowTwitterSocial"));this.twitter.consumerKey=e.observable(a.settingsGet("TwitterConsumerKey"));this.twitter.consumerSecret=e.observable(a.settingsGet("TwitterConsumerSecret"));this.dropbox.enabled(!!a.settingsGet("AllowDropboxSocial"));
+this.dropbox.apiKey(a.settingsGet("DropboxApiKey"))};h.exports=new a})()},function(h,f,c){function a(b,a){if("function"!==typeof a&&null!==a)throw new TypeError("Super expression must either be null or a function, not "+typeof a);b.prototype=Object.create(a&&a.prototype,{constructor:{value:b,enumerable:!1,writable:!0,configurable:!0}});a&&(Object.setPrototypeOf?Object.setPrototypeOf(b,a):b.__proto__=a)}var e=(f=c(2))&&f.__esModule?f:{default:f},d=(f=c(9))&&f.__esModule?f:{default:f};c=function(b){function c(){if(!(this instanceof
+c))throw new TypeError("Cannot call a class as a function");var a;a=b.call(this);if(!this)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");a=!a||"object"!==typeof a&&"function"!==typeof a?this:a;a.determineUserLanguage=e.default.observable(!1);a.determineUserDomain=e.default.observable(!1);a.weakPassword=e.default.observable(!1);a.useLocalProxyForExternalImages=e.default.observable(!1);return a}a(c,b);c.prototype.populate=function(){b.prototype.populate.call(this);
+this.determineUserLanguage(!!d.default.settingsGet("DetermineUserLanguage"));this.determineUserDomain(!!d.default.settingsGet("DetermineUserDomain"));this.weakPassword(!!d.default.settingsGet("WeakPassword"));this.useLocalProxyForExternalImages(!!d.default.settingsGet("UseLocalProxyForExternalImages"))};return c}(c(76).AbstractAppStore);h.exports=new c},function(h,f){h.exports=window.JSON},function(h,f,c){function a(b,a){if(!b)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+return!a||"object"!==typeof a&&"function"!==typeof a?b:a}function e(b,a){if("function"!==typeof a&&null!==a)throw new TypeError("Super expression must either be null or a function, not "+typeof a);b.prototype=Object.create(a&&a.prototype,{constructor:{value:b,enumerable:!1,writable:!0,configurable:!0}});a&&(Object.setPrototypeOf?Object.setPrototypeOf(b,a):b.__proto__=a)}f.__esModule=!0;f.default=f.AbstractInput=void 0;var d=(h=c(2))&&h.__esModule?h:{default:h},b=(h=c(1))&&h.__esModule?h:{default:h},
+g=c(4);c=function(c){function k(g){if(!(this instanceof k))throw new TypeError("Cannot call a class as a function");var e=a(this,c.call(this));e.value=g.value||"";e.size=g.size||0;e.label=g.label||"";e.preLabel=g.preLabel||"";e.enable=b.default.isUnd(g.enable)?!0:g.enable;e.trigger=g.trigger&&g.trigger.subscribe?g.trigger:null;e.placeholder=g.placeholder||"";e.labeled=!b.default.isUnd(g.label);e.preLabeled=!b.default.isUnd(g.preLabel);e.triggered=!b.default.isUnd(g.trigger)&&!!e.trigger;e.classForTrigger=
+d.default.observable("");e.className=d.default.computed(function(){var a=d.default.unwrap(e.size),c=e.trigger?" "+b.default.trim("settings-saved-trigger-input "+e.classForTrigger()):"";return(0=arguments.length||void 0===arguments[1]?null:arguments[1],e=2>=arguments.length||void 0===arguments[2]?null:arguments[2],f=3>=arguments.length||void 0===arguments[3]?null:arguments[3];if(!(this instanceof c))throw new TypeError("Cannot call a class as a function");this.$element=this.editor=null;this.blurTimer=0;this.__inited=this.onModeChange=this.onReady=this.onBlur=null;this.onBlur=d;this.onReady=e;this.onModeChange=f;this.$element=
+(0,a.$)(b);this.resize=a._.throttle(a._.bind(this.resize,this),100);this.__inited=!1;this.init()}c.prototype.blurTrigger=function(){var b=this;this.onBlur&&(a.window.clearTimeout(this.blurTimer),this.blurTimer=a.window.setTimeout(function(){b.onBlur()},200))};c.prototype.focusTrigger=function(){this.onBlur&&a.window.clearTimeout(this.blurTimer)};c.prototype.isHtml=function(){return this.editor?"wysiwyg"===this.editor.mode:!1};c.prototype.setSignature=function(b,a,c){this.editor&&this.editor.execCommand("insertSignature",
+{isHtml:a,insertBefore:c,signature:b})};c.prototype.checkDirty=function(){return this.editor?this.editor.checkDirty():!1};c.prototype.resetDirty=function(){this.editor&&this.editor.resetDirty()};c.prototype.clearSignatureSigns=function(b){return b.replace(/(\u200C|\u0002)/g,"")};c.prototype.getData=function(){var b=0>=arguments.length||void 0===arguments[0]?!1:arguments[0],a=1>=arguments.length||void 0===arguments[1]?!1:arguments[1],c="";if(this.editor){try{c="plain"===this.editor.mode&&this.editor.plugins.plain&&
+this.editor.__plain?this.editor.__plain.getRawData():b?''+this.editor.getData()+"
":this.editor.getData()}catch(d){}a&&(c=this.clearSignatureSigns(c))}return c};c.prototype.getDataWithHtmlMark=function(){var b=0>=arguments.length||void 0===arguments[0]?!1:arguments[0],a=1>=arguments.length||void 0===arguments[1]?!1:arguments[1];return(this.isHtml()?":HTML:":"")+this.getData(b,a)};c.prototype.modeToggle=
+function(b,a){if(this.editor){try{b?"plain"===this.editor.mode&&this.editor.setMode("wysiwyg"):"wysiwyg"===this.editor.mode&&this.editor.setMode("plain")}catch(c){}a&&this.resize()}};c.prototype.setHtmlOrPlain=function(b,a){":HTML:"===b.substr(0,6)?this.setHtml(b.substr(6),a):this.setPlain(b,a)};c.prototype.setHtml=function(b,a){if(this.editor&&this.__inited){this.modeToggle(!0);b=b.replace(/]*><\/p>/ig,"");try{this.editor.setData(b)}catch(c){}a&&this.focus()}};c.prototype.replaceHtml=function(b,
+a){if(this.editor&&this.__inited&&"wysiwyg"===this.editor.mode)try{this.editor.setData(this.editor.getData().replace(b,a))}catch(c){}};c.prototype.setPlain=function(b,a){if(this.editor&&this.__inited){this.modeToggle(!1);if("plain"===this.editor.mode&&this.editor.plugins.plain&&this.editor.__plain)this.editor.__plain.setRawData(b);else try{this.editor.setData(b)}catch(c){}a&&this.focus()}};c.prototype.init=function(){var c=this;if(this.$element&&this.$element[0]&&!this.editor){var e=function(){var e=
+d.default.oHtmlEditorDefaultConfig,g=b.default.settingsGet("Language"),k=!!b.default.appSettingsGet("allowHtmlEditorSourceButton"),f=!!b.default.appSettingsGet("allowHtmlEditorBitiButtons");!k&&f||e.toolbarGroups.__cfgInited||(e.toolbarGroups.__cfgInited=!0,k&&(e.removeButtons=e.removeButtons.replace(",Source","")),f||(e.removePlugins+=(e.removePlugins?",":"")+"bidi"));e.enterMode=a.window.CKEDITOR.ENTER_BR;e.shiftEnterMode=a.window.CKEDITOR.ENTER_P;e.language=d.default.oHtmlEditorLangsMap[g]||"en";
+a.window.CKEDITOR.env&&(a.window.CKEDITOR.env.isCompatible=!0);c.editor=a.window.CKEDITOR.appendTo(c.$element[0],e);c.editor.on("key",function(b){if(b&&b.data&&9===b.data.keyCode)return!1});c.editor.on("blur",function(){c.blurTrigger()});c.editor.on("mode",function(){c.blurTrigger();if(c.onModeChange)c.onModeChange("plain"!==c.editor.mode)});c.editor.on("focus",function(){c.focusTrigger()});if(a.window.FileReader)c.editor.on("drop",function(b){if(0 ')};g.readAsDataURL(d);b.data.dataTransfer.setData("text/html",e)}}});c.editor.on("instanceReady",function(){c.editor.removeMenuItem&&(c.editor.removeMenuItem("cut"),c.editor.removeMenuItem("copy"),c.editor.removeMenuItem("paste"));c.__resizable=!0;c.__inited=!0;c.resize();
+if(c.onReady)c.onReady()})};a.window.CKEDITOR?e():a.window.__initEditor=e}};c.prototype.focus=function(){if(this.editor)try{this.editor.focus()}catch(b){}};c.prototype.hasFocus=function(){if(this.editor)try{return!!this.editor.focusManager.hasFocus}catch(b){}return!1};c.prototype.blur=function(){if(this.editor)try{this.editor.focusManager.blur(!0)}catch(b){}};c.prototype.resize=function(){if(this.editor&&this.__resizable)try{this.editor.resize(this.$element.width(),this.$element.innerHeight())}catch(b){}};
+c.prototype.setReadOnly=function(b){if(this.editor)try{this.editor.setReadOnly(!!b)}catch(a){}};c.prototype.clear=function(b){this.setHtml("",b)};return c}();f.HtmlEditor=c;f.default=c;h.exports=c},function(h,f,c){function a(b,a){if("function"!==typeof a&&null!==a)throw new TypeError("Super expression must either be null or a function, not "+typeof a);b.prototype=Object.create(a&&a.prototype,{constructor:{value:b,enumerable:!1,writable:!0,configurable:!0}});a&&(Object.setPrototypeOf?Object.setPrototypeOf(b,
+a):b.__proto__=a)}f.__esModule=!0;f.default=f.AbstracCheckbox=void 0;var e=(h=c(2))&&h.__esModule?h:{default:h},d=(h=c(1))&&h.__esModule?h:{default:h};c=function(b){function c(){var a=0>=arguments.length||void 0===arguments[0]?{}:arguments[0];if(!(this instanceof c))throw new TypeError("Cannot call a class as a function");var k;k=b.call(this);if(!this)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");k=!k||"object"!==typeof k&&"function"!==typeof k?this:k;k.value=
+a.value;if(d.default.isUnd(k.value)||!k.value.subscribe)k.value=e.default.observable(d.default.isUnd(k.value)?!1:!!k.value);k.enable=a.enable;if(d.default.isUnd(k.enable)||!k.enable.subscribe)k.enable=e.default.observable(d.default.isUnd(k.enable)?!0:!!k.enable);k.disable=a.disable;if(d.default.isUnd(k.disable)||!k.disable.subscribe)k.disable=e.default.observable(d.default.isUnd(k.disable)?!1:!!k.disable);k.label=a.label||"";k.inline=d.default.isUnd(a.inline)?!1:a.inline;k.readOnly=d.default.isUnd(a.readOnly)?
+!1:!!a.readOnly;k.inverted=d.default.isUnd(a.inverted)?!1:!!a.inverted;k.labeled=!d.default.isUnd(a.label);k.labelAnimated=!!a.labelAnimated;return k}a(c,b);c.prototype.click=function(){this.readOnly||!this.enable()||this.disable()||this.value(!this.value())};return c}(c(16).AbstractComponent);f.AbstracCheckbox=c;f.default=c},,function(h,f){h.exports=window.Q},function(h,f){h.exports=window.crossroads},function(h,f,c){(function(){function a(){this.additionalAccounts=e.observable(!1);this.identities=
+e.observable(!1);this.gravatar=e.observable(!1);this.attachmentThumbnails=e.observable(!1);this.sieve=e.observable(!1);this.filters=e.observable(!1);this.themes=e.observable(!0);this.userBackground=e.observable(!1);this.openPGP=e.observable(!1);this.twoFactorAuth=e.observable(!1);this.twoFactorAuthForce=e.observable(!1);this.templates=e.observable(!1)}var e=c(2),d=c(4),b=c(9);a.prototype.populate=function(){this.additionalAccounts(b.capa(d.Capa.AdditionalAccounts));this.identities(b.capa(d.Capa.Identities));
+this.gravatar(b.capa(d.Capa.Gravatar));this.attachmentThumbnails(b.capa(d.Capa.AttachmentThumbnails));this.sieve(b.capa(d.Capa.Sieve));this.filters(b.capa(d.Capa.Filters));this.themes(b.capa(d.Capa.Themes));this.userBackground(b.capa(d.Capa.UserBackground));this.openPGP(b.capa(d.Capa.OpenPGP));this.twoFactorAuth(b.capa(d.Capa.TwoFactor));this.twoFactorAuthForce(b.capa(d.Capa.TwoFactorForce));this.templates(b.capa(d.Capa.Templates))};h.exports=new a})()},,,,function(h,f,c){f=c(11).Opentip;f.styles.rainloop=
+{"extends":"standard",fixed:!0,target:!0,delay:.2,hideDelay:0,hideEffect:"fade",hideEffectDuration:.2,showEffect:"fade",showEffectDuration:.2,showOn:"mouseover click",removeElementsOnHide:!0,background:"#fff",shadow:!1,borderColor:"#999",borderRadius:2,borderWidth:1};f.styles.rainloopTip={"extends":"rainloop",delay:.4,group:"rainloopTips"};f.styles.rainloopErrorTip={"extends":"rainloop",className:"rainloopErrorTip"};h.exports=f},function(h,f,c){(function(){function a(){this.oRequests={}}var e=c(11),
+d=c(3),b=c(14),g=c(17),l=c(4),k=c(8),f=c(1),n=c(23),p=c(12),r=c(9);a.prototype.oRequests={};a.prototype.defaultResponse=function(b,a,c,e,h,r){var p=function(){l.StorageResultType.Success!==c&&k.bUnload&&(c=l.StorageResultType.Unload);l.StorageResultType.Success===c&&e&&!e.Result?(e&&-1(new e.Date).getTime()-E);x&&h.oRequests[x]&&(h.oRequests[x].__aborted&&
+(d="abort"),h.oRequests[x]=null);h.defaultResponse(a,x,d,b,g,c)});x&&0
").addClass("rl-settings-view-model").hide(),v.appendTo(w),h.viewModelDom=v,h.__rlSettingsData=n.__rlSettingsData,n.__dom=v,n.__builded=!0,n.__vm=h,b.applyBindingAccessorsToNode(v[0],{translatorInit:!0,template:function(){return{name:n.__rlSettingsData.Template}}},h),l.delegateRun(h,"onBuild",[v])):l.log("Cannot find sub settings view model position: SettingsSubScreen"),
+h&&e.defer(function(){c.oCurrentSubScreen&&(l.delegateRun(c.oCurrentSubScreen,"onHide"),c.oCurrentSubScreen.viewModelDom.hide());c.oCurrentSubScreen=h;c.oCurrentSubScreen&&(l.delegateRun(c.oCurrentSubScreen,"onBeforeShow"),c.oCurrentSubScreen.viewModelDom.show(),l.delegateRun(c.oCurrentSubScreen,"onShow"),l.delegateRun(c.oCurrentSubScreen,"onShowWithDelay",[],200),e.each(c.menu(),function(b){b.selected(h&&h.__rlSettingsData&&b.route===h.__rlSettingsData.Route)}),d("#rl-content .b-settings .b-content .content").scrollTop(0));
+l.windowResize()})):f.setHash(k.settings(),!1,!0)};a.prototype.onHide=function(){this.oCurrentSubScreen&&this.oCurrentSubScreen.viewModelDom&&(l.delegateRun(this.oCurrentSubScreen,"onHide"),this.oCurrentSubScreen.viewModelDom.hide())};a.prototype.onBuild=function(){e.each(g.aViewModels.settings,function(a){a&&a.__rlSettingsData&&!e.find(g.aViewModels["settings-removed"],function(b){return b&&b===a})&&this.menu.push({route:a.__rlSettingsData.Route,label:a.__rlSettingsData.Label,selected:b.observable(!1),
+disabled:!!e.find(g.aViewModels["settings-disabled"],function(b){return b&&b===a})})},this);this.oViewModelPlace=d("#rl-content #rl-settings-subscreen")};a.prototype.routes=function(){var b=e.find(g.aViewModels.settings,function(b){return b&&b.__rlSettingsData&&b.__rlSettingsData.IsDefault}),a=b?b.__rlSettingsData.Route:"general",b={subname:/^(.*)$/,normalize_:function(b,c){c.subname=l.isUnd(c.subname)?a:l.pString(c.subname);return[c.subname]}};return[["{subname}/",b],["{subname}",b],["",b]]};h.exports=
+a})()},function(h,f,c){(function(){var a=c(2);h.exports=new function(){this.domains=a.observableArray([]);this.domains.loading=a.observable(!1).extend({throttle:100})}})()},function(h,f,c){(function(){var a=c(2);h.exports=new function(){this.packages=a.observableArray([]);this.packages.loading=a.observable(!1).extend({throttle:100});this.packagesReal=a.observable(!0);this.packagesMainUpdatable=a.observable(!0)}})()},function(h,f,c){(function(){var a=c(2);h.exports=new function(){this.plugins=a.observableArray([]);
+this.plugins.loading=a.observable(!1).extend({throttle:100});this.plugins.error=a.observable("")}})()},,,,,function(h,f,c){function a(b){return b&&b.__esModule?b:{default:b}}function e(b,a){if(!b)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!a||"object"!==typeof a&&"function"!==typeof a?b:a}function d(b,a){if("function"!==typeof a&&null!==a)throw new TypeError("Super expression must either be null or a function, not "+typeof a);b.prototype=Object.create(a&&
+a.prototype,{constructor:{value:b,enumerable:!1,writable:!0,configurable:!0}});a&&(Object.setPrototypeOf?Object.setPrototypeOf(b,a):b.__proto__=a)}f.__esModule=!0;f.default=f.AbstractApp=void 0;var b=c(13);h=c(8);var g=a(h),l=function(b){if(b&&b.__esModule)return b;var a={};if(null!=b)for(var c in b)Object.prototype.hasOwnProperty.call(b,c)&&(a[c]=b[c]);a.default=b;return a}(c(4));h=c(1);var k=a(h);h=c(12);var m=a(h);h=c(25);var n=a(h);h=c(6);var p=a(h);h=c(9);var r=a(h);h=function(a){function f(c){if(!(this instanceof
+f))throw new TypeError("Cannot call a class as a function");var d=e(this,a.call(this));d.googlePreviewSupportedCache=null;d.isLocalAutocomplete=!0;d.iframe=null;d.iframe=(0,b.$)('
').appendTo("body");g.default.$win.on("error",function(a){a&&a.originalEvent&&a.originalEvent.message&&-1===k.default.inArray(a.originalEvent.message,["Script error.","Uncaught Error: Error calling method on NPObject."])&&c.jsError(k.default.emptyFunction,a.originalEvent.message,
+a.originalEvent.filename,a.originalEvent.lineno,b.window.location&&b.window.location.toString?b.window.location.toString():"",g.default.$html.attr("class"),k.default.microtime()-g.default.startMicrotime)});g.default.$win.on("resize",function(){n.default.pub("window.resize")});n.default.sub("window.resize",b._.throttle(function(){var b=g.default.$win.height(),a=g.default.$win.height();if(g.default.$win.__sizes[0]!==b||g.default.$win.__sizes[1]!==a)g.default.$win.__sizes[0]=b,g.default.$win.__sizes[1]=
+a,n.default.pub("window.resize.real")},50));g.default.$doc.on("keydown",function(b){b&&b.ctrlKey&&g.default.$html.addClass("rl-ctrl-key-pressed")}).on("keyup",function(b){b&&!b.ctrlKey&&g.default.$html.removeClass("rl-ctrl-key-pressed")});g.default.$doc.on("mousemove keypress click",b._.debounce(function(){n.default.pub("rl.auto-logout-refresh")},5E3));(0,b.key)("esc, enter",l.KeyState.All,b._.bind(function(){k.default.detectDropdownVisibility()},d));return d}d(f,a);f.prototype.remote=function(){return null};
+f.prototype.data=function(){return null};f.prototype.getApplicationConfiguration=function(b,a){return this.applicationConfiguration[b]||a};f.prototype.download=function(a){if(g.default.sUserAgent&&(-1
=arguments.length||void 0===arguments[0]?!1:arguments[0],d=1>=arguments.length||void 0===arguments[1]?!1:arguments[1],e=2>=arguments.length||void 0===arguments[2]?!1:arguments[2],g=c(5),l=r.default.appSettingsGet("mobile"),f=!!r.default.appSettingsGet("inIframe"),h=k.default.pString(r.default.appSettingsGet("customLogoutLink"));d&&this.clearClientSideToken();d&&e&&b.window.close&&b.window.close();h=h||(a?m.default.rootAdmin(l):m.default.rootUser(l));d&&b.window.location.href!==
+h?b._.delay(function(){f&&b.window.parent?b.window.parent.location.href=h:b.window.location.href=h},100):(g.routeOff(),g.setHash(m.default.root(),!0),g.routeOff(),b._.delay(function(){f&&b.window.parent?b.window.parent.location.reload():b.window.location.reload()},100))};f.prototype.historyBack=function(){b.window.history.back()};f.prototype.bootstart=function(){n.default.pub("rl.bootstart");var a=r.default.appSettingsGet("mobile"),d=c(84),e=c(2);e.components.register("SaveTrigger",c(71));e.components.register("Input",
+c(68));e.components.register("Select",c(73));e.components.register("Radio",c(70));e.components.register("TextArea",c(74));e.components.register("x-script",c(72));r.default.appSettingsGet("materialDesign")&&g.default.bAnimationSupported?e.components.register("Checkbox",c(69)):e.components.register("Checkbox",c(38));e.components.register("CheckboxSimple",c(38));p.default.initOnStartOrLangChange(p.default.initNotificationLanguage,p.default);b._.delay(k.default.windowResizeCallback,1E3);n.default.sub("ssm.mobile-enter",
+function(){g.default.leftPanelDisabled(!0)});n.default.sub("ssm.mobile-leave",function(){g.default.leftPanelDisabled(!1)});a?(g.default.$html.addClass("ssm-state-mobile").addClass("rl-mobile"),n.default.pub("ssm.mobile-enter")):(d.addState({id:"mobile",maxWidth:767,onEnter:function(){g.default.$html.addClass("ssm-state-mobile");n.default.pub("ssm.mobile-enter")},onLeave:function(){g.default.$html.removeClass("ssm-state-mobile");n.default.pub("ssm.mobile-leave")}}),d.addState({id:"tablet",minWidth:768,
+maxWidth:999,onEnter:function(){g.default.$html.addClass("ssm-state-tablet")},onLeave:function(){g.default.$html.removeClass("ssm-state-tablet")}}),d.addState({id:"desktop",minWidth:1E3,maxWidth:1400,onEnter:function(){g.default.$html.addClass("ssm-state-desktop")},onLeave:function(){g.default.$html.removeClass("ssm-state-desktop")}}),d.addState({id:"desktop-large",minWidth:1400,onEnter:function(){g.default.$html.addClass("ssm-state-desktop-large")},onLeave:function(){g.default.$html.removeClass("ssm-state-desktop-large")}}));
+g.default.leftPanelDisabled.subscribe(function(b){g.default.$html.toggleClass("rl-left-panel-disabled",b);g.default.$html.toggleClass("rl-left-panel-enabled",!b)});g.default.leftPanelType.subscribe(function(b){g.default.$html.toggleClass("rl-left-panel-none","none"===b);g.default.$html.toggleClass("rl-left-panel-short","short"===b)});g.default.leftPanelDisabled.valueHasMutated();d.ready();c(40).populate();c(42).populate();c(34).populate()};return f}(c(75).AbstractBoot);f.AbstractApp=h;f.default=h},
+,function(h,f){h.exports={eml:"message/rfc822",mime:"message/rfc822",txt:"text/plain",text:"text/plain",def:"text/plain",list:"text/plain","in":"text/plain",ini:"text/plain",log:"text/plain",sql:"text/plain",cfg:"text/plain",conf:"text/plain",asc:"text/plain",rtx:"text/richtext",vcard:"text/vcard",vcf:"text/vcard",htm:"text/html",html:"text/html",csv:"text/csv",ics:"text/calendar",ifb:"text/calendar",xml:"text/xml",json:"application/json",swf:"application/x-shockwave-flash",hlp:"application/winhlp",
+wgt:"application/widget",chm:"application/vnd.ms-htmlhelp",p10:"application/pkcs10",p7c:"application/pkcs7-mime",p7m:"application/pkcs7-mime",p7s:"application/pkcs7-signature",torrent:"application/x-bittorrent",js:"application/javascript",pl:"text/perl",css:"text/css",asp:"text/asp",php:"application/x-httpd-php",php3:"application/x-httpd-php",php4:"application/x-httpd-php",php5:"application/x-httpd-php",phtml:"application/x-httpd-php",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",jpe:"image/jpeg",
+jfif:"image/jpeg",gif:"image/gif",bmp:"image/bmp",cgm:"image/cgm",ief:"image/ief",ico:"image/x-icon",tif:"image/tiff",tiff:"image/tiff",svg:"image/svg+xml",svgz:"image/svg+xml",djv:"image/vnd.djvu",djvu:"image/vnd.djvu",webp:"image/webp",zip:"application/zip","7z":"application/x-7z-compressed",rar:"application/x-rar-compressed",exe:"application/x-msdownload",dll:"application/x-msdownload",scr:"application/x-msdownload",com:"application/x-msdownload",bat:"application/x-msdownload",msi:"application/x-msdownload",
+cab:"application/vnd.ms-cab-compressed",gz:"application/x-gzip",tgz:"application/x-gzip",bz:"application/x-bzip",bz2:"application/x-bzip2",deb:"application/x-debian-package",psf:"application/x-font-linux-psf",otf:"application/x-font-otf",pcf:"application/x-font-pcf",snf:"application/x-font-snf",ttf:"application/x-font-ttf",ttc:"application/x-font-ttf",mp3:"audio/mpeg",amr:"audio/amr",aac:"audio/x-aac",aif:"audio/x-aiff",aifc:"audio/x-aiff",aiff:"audio/x-aiff",wav:"audio/x-wav",wma:"audio/x-ms-wma",
+wax:"audio/x-ms-wax",midi:"audio/midi",mp4a:"audio/mp4",ogg:"audio/ogg",weba:"audio/webm",ra:"audio/x-pn-realaudio",ram:"audio/x-pn-realaudio",rmp:"audio/x-pn-realaudio-plugin",m3u:"audio/x-mpegurl",flv:"video/x-flv",qt:"video/quicktime",mov:"video/quicktime",wmv:"video/windows-media",avi:"video/x-msvideo",mpg:"video/mpeg",mpeg:"video/mpeg",mpe:"video/mpeg",m1v:"video/mpeg",m2v:"video/mpeg","3gp":"video/3gpp","3g2":"video/3gpp2",h261:"video/h261",h263:"video/h263",h264:"video/h264",jpgv:"video/jpgv",
+mp4:"video/mp4",mp4v:"video/mp4",mpg4:"video/mp4",ogv:"video/ogg",webm:"video/webm",m4v:"video/x-m4v",asf:"video/x-ms-asf",asx:"video/x-ms-asf",wm:"video/x-ms-wm",wmx:"video/x-ms-wmx",wvx:"video/x-ms-wvx",movie:"video/x-sgi-movie",pdf:"application/pdf",psd:"image/vnd.adobe.photoshop",ai:"application/postscript",eps:"application/postscript",ps:"application/postscript",doc:"application/msword",dot:"application/msword",rtf:"application/rtf",xls:"application/vnd.ms-excel",ppt:"application/vnd.ms-powerpoint",
+docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",dotx:"application/vnd.openxmlformats-officedocument.wordprocessingml.template",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",odt:"application/vnd.oasis.opendocument.text",ods:"application/vnd.oasis.opendocument.spreadsheet"}},function(h,f,c){function a(b,a){if(!b)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+return!a||"object"!==typeof a&&"function"!==typeof a?b:a}function e(b,a){if("function"!==typeof a&&null!==a)throw new TypeError("Super expression must either be null or a function, not "+typeof a);b.prototype=Object.create(a&&a.prototype,{constructor:{value:b,enumerable:!1,writable:!0,configurable:!0}});a&&(Object.setPrototypeOf?Object.setPrototypeOf(b,a):b.__proto__=a)}f.__esModule=!0;f.default=f.AbstracRadio=void 0;var d=c(13),b=(h=c(2))&&h.__esModule?h:{default:h},g=(h=c(1))&&h.__esModule?h:{default:h};
+c=function(c){function f(e){if(!(this instanceof f))throw new TypeError("Cannot call a class as a function");var h=a(this,c.call(this));h.values=b.default.observableArray([]);h.value=e.value;if(g.default.isUnd(h.value)||!h.value.subscribe)h.value=b.default.observable("");h.inline=g.default.isUnd(e.inline)?!1:e.inline;h.readOnly=g.default.isUnd(e.readOnly)?!1:!!e.readOnly;e.values&&h.values(d._.map(e.values,function(b,a){return{label:b,value:a}}));h.click=d._.bind(h.click,h);return h}e(f,c);f.prototype.click=
+function(b){!this.readOnly&&b&&this.value(b.value)};return f}(c(16).AbstractComponent);f.AbstracRadio=c;f.default=c},function(h,f,c){function a(a,c){if("function"!==typeof c&&null!==c)throw new TypeError("Super expression must either be null or a function, not "+typeof c);a.prototype=Object.create(c&&c.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}});c&&(Object.setPrototypeOf?Object.setPrototypeOf(a,c):a.__proto__=c)}f=c(16);c=function(c){function d(){if(!(this instanceof
+d))throw new TypeError("Cannot call a class as a function");var b=c.apply(this,arguments);if(!this)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!b||"object"!==typeof b&&"function"!==typeof b?this:b}a(d,c);return d}(c(37).AbstractInput);h.exports=(0,f.componentExportHelper)(c,"InputComponent")},function(h,f,c){function a(b,a){if(!b)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!a||"object"!==typeof a&&"function"!==
+typeof a?b:a}function e(b,a){if("function"!==typeof a&&null!==a)throw new TypeError("Super expression must either be null or a function, not "+typeof a);b.prototype=Object.create(a&&a.prototype,{constructor:{value:b,enumerable:!1,writable:!0,configurable:!0}});a&&(Object.setPrototypeOf?Object.setPrototypeOf(b,a):b.__proto__=a)}var d=c(13),b=(f=c(2))&&f.__esModule?f:{default:f};f=c(16);c=function(c){function l(e){if(!(this instanceof l))throw new TypeError("Cannot call a class as a function");var f=
+a(this,c.call(this,e));f.animationBox=b.default.observable(!1).extend({falseTimeout:200});f.animationCheckmark=b.default.observable(!1).extend({falseTimeout:200});f.animationBoxSetTrue=d._.bind(f.animationBoxSetTrue,f);f.animationCheckmarkSetTrue=d._.bind(f.animationCheckmarkSetTrue,f);f.disposable.push(f.value.subscribe(function(b){f.triggerAnimation(b)},f));return f}e(l,c);l.prototype.animationBoxSetTrue=function(){this.animationBox(!0)};l.prototype.animationCheckmarkSetTrue=function(){this.animationCheckmark(!0)};
+l.prototype.triggerAnimation=function(b){b?(this.animationBoxSetTrue(),d._.delay(this.animationCheckmarkSetTrue,200)):(this.animationCheckmarkSetTrue(),d._.delay(this.animationBoxSetTrue,200))};return l}(c(46).AbstracCheckbox);h.exports=(0,f.componentExportHelper)(c,"CheckboxMaterialDesignComponent")},function(h,f,c){function a(a,c){if("function"!==typeof c&&null!==c)throw new TypeError("Super expression must either be null or a function, not "+typeof c);a.prototype=Object.create(c&&c.prototype,{constructor:{value:a,
+enumerable:!1,writable:!0,configurable:!0}});c&&(Object.setPrototypeOf?Object.setPrototypeOf(a,c):a.__proto__=c)}f=c(16);c=function(c){function d(){if(!(this instanceof d))throw new TypeError("Cannot call a class as a function");var b=c.apply(this,arguments);if(!this)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!b||"object"!==typeof b&&"function"!==typeof b?this:b}a(d,c);return d}(c(67).AbstracRadio);h.exports=(0,f.componentExportHelper)(c,"RadioComponent")},
+function(h,f,c){function a(b,a){if("function"!==typeof a&&null!==a)throw new TypeError("Super expression must either be null or a function, not "+typeof a);b.prototype=Object.create(a&&a.prototype,{constructor:{value:b,enumerable:!1,writable:!0,configurable:!0}});a&&(Object.setPrototypeOf?Object.setPrototypeOf(b,a):b.__proto__=a)}var e=(f=c(1))&&f.__esModule?f:{default:f},d=c(4);c=c(16);f=function(b){function c(a){if(!(this instanceof c))throw new TypeError("Cannot call a class as a function");var d;
+d=b.call(this);if(!this)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");d=!d||"object"!==typeof d&&"function"!==typeof d?this:d;d.element=a.element||null;d.value=a.value&&a.value.subscribe?a.value:null;d.element&&(d.value?(d.element.css("display","inline-block"),a.verticalAlign&&d.element.css("vertical-align",a.verticalAlign),d.setState(d.value()),d.disposable.push(d.value.subscribe(d.setState,d))):d.element.hide());return d}a(c,b);c.prototype.setState=function(b){switch(e.default.pInt(b)){case d.SaveSettingsStep.TrueResult:this.element.find(".animated,.error").hide().removeClass("visible").end().find(".success").show().addClass("visible");
+break;case d.SaveSettingsStep.FalseResult:this.element.find(".animated,.success").hide().removeClass("visible").end().find(".error").show().addClass("visible");break;case d.SaveSettingsStep.Animate:this.element.find(".error,.success").hide().removeClass("visible").end().find(".animated").show().addClass("visible");break;default:case d.SaveSettingsStep.Idle:this.element.find(".animated").hide().end().find(".error,.success").removeClass("visible")}};return c}(c.AbstractComponent);h.exports=(0,c.componentExportHelper)(f,
+"SaveTriggerComponent")},function(h,f,c){function a(a,b){if("function"!==typeof b&&null!==b)throw new TypeError("Super expression must either be null or a function, not "+typeof b);a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}});b&&(Object.setPrototypeOf?Object.setPrototypeOf(a,b):a.__proto__=b)}var e=c(13);f=c(16);c=function(c){function b(a){if(!(this instanceof b))throw new TypeError("Cannot call a class as a function");var l;l=c.call(this);
+if(!this)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");l=!l||"object"!==typeof l&&"function"!==typeof l?this:l;if(a.component&&a.component.templateNodes&&a.element&&a.element[0]&&a.element[0].outerHTML){var f=a.element[0].outerHTML;(f=f?f.replace(/<\/b><\/x-script>/i,"\x3c/script>"):"")?(a.element.text(""),a.element.replaceWith((0,e.$)(f).text(a.component.templateNodes[0]&&a.component.templateNodes[0].nodeValue?a.component.templateNodes[0].nodeValue:
+""))):a.element.remove()}return l}a(b,c);return b}(f.AbstractComponent);h.exports=(0,f.componentExportHelper)(c,"ScriptComponent")},function(h,f,c){function a(b,a){if("function"!==typeof a&&null!==a)throw new TypeError("Super expression must either be null or a function, not "+typeof a);b.prototype=Object.create(a&&a.prototype,{constructor:{value:b,enumerable:!1,writable:!0,configurable:!0}});a&&(Object.setPrototypeOf?Object.setPrototypeOf(b,a):b.__proto__=a)}var e=(f=c(1))&&f.__esModule?f:{default:f},
+d=(f=c(6))&&f.__esModule?f:{default:f};f=c(16);c=function(b){function c(a){if(!(this instanceof c))throw new TypeError("Cannot call a class as a function");var f;f=b.call(this,a);if(!this)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");f=!f||"object"!==typeof f&&"function"!==typeof f?this:f;f.options=a.options||"";f.optionsText=a.optionsText||null;f.optionsValue=a.optionsValue||null;f.optionsCaption=a.optionsCaption||null;f.optionsCaption&&(f.optionsCaption=d.default.i18n(f.optionsCaption));
+f.defautOptionsAfterRender=e.default.defautOptionsAfterRender;return f}a(c,b);return c}(c(37).AbstractInput);h.exports=(0,f.componentExportHelper)(c,"SelectComponent")},function(h,f,c){function a(a,b){if("function"!==typeof b&&null!==b)throw new TypeError("Super expression must either be null or a function, not "+typeof b);a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}});b&&(Object.setPrototypeOf?Object.setPrototypeOf(a,b):a.__proto__=b)}
+var e=(f=c(1))&&f.__esModule?f:{default:f};f=c(16);c=function(c){function b(a){if(!(this instanceof b))throw new TypeError("Cannot call a class as a function");var f;f=c.call(this,a);if(!this)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");f=!f||"object"!==typeof f&&"function"!==typeof f?this:f;f.rows=a.rows||5;f.spellcheck=e.default.isUnd(a.spellcheck)?!1:!!a.spellcheck;return f}a(b,c);return b}(c(37).AbstractInput);h.exports=(0,f.componentExportHelper)(c,"TextAreaComponent")},
+function(h,f){f.__esModule=!0;var c=function(){function a(){if(!(this instanceof a))throw new TypeError("Cannot call a class as a function");}a.prototype.bootstart=function(){};return a}();f.AbstractBoot=c;f.default=c},function(h,f,c){function a(a){return a&&a.__esModule?a:{default:a}}f.__esModule=!0;f.default=f.AbstractAppStore=void 0;h=c(2);var e=a(h);h=c(8);var d=a(h);c=c(9);var b=a(c);c=function(){function a(){if(!(this instanceof a))throw new TypeError("Cannot call a class as a function");this.allowLanguagesOnSettings=
+e.default.observable(!0);this.allowLanguagesOnLogin=e.default.observable(!0);this.interfaceAnimation=e.default.observable(!0);this.interfaceAnimation.subscribe(function(a){a=d.default.bMobileDevice||!a;d.default.$html.toggleClass("rl-anim",!a).toggleClass("no-rl-anim",a)});this.interfaceAnimation.valueHasMutated();this.prem=e.default.observable(!1);this.community=e.default.observable(!0)}a.prototype.populate=function(){this.allowLanguagesOnLogin(!!b.default.settingsGet("AllowLanguagesOnLogin"));this.allowLanguagesOnSettings(!!b.default.settingsGet("AllowLanguagesOnSettings"));
+this.interfaceAnimation(!!b.default.settingsGet("InterfaceAnimation"));this.prem(!!b.default.settingsGet("PremType"));this.community(!!b.default.settingsGet("Community"))};return a}();f.AbstractAppStore=c;f.default=c},function(h,f,c){f.__esModule=!0;f.default=function(a){var e=c(11),d=c(3),b=c(14),g=c(8),f=c(23),k=c(1),h=c(4),n=c(6),p=c(30);g.__APP__=a;g.$win.keydown(k.kill_CtrlA_CtrlS).unload(function(){g.bUnload=!0});g.$html.addClass(g.bMobileDevice?"mobile":"no-mobile").on("click.dropdown.data-api",
+function(){k.detectDropdownVisibility()});e.rl=e.rl||{};e.rl.i18n=d.bind(n.i18n,n);e.rl.addHook=d.bind(f.addHook,f);e.rl.settingsGet=d.bind(f.mainSettingsGet,f);e.rl.createCommand=k.createCommand;e.rl.addSettingsViewModel=d.bind(f.addSettingsViewModel,f);e.rl.pluginRemoteRequest=d.bind(f.remoteRequest,f);e.rl.pluginSettingsGet=d.bind(f.settingsGet,f);e.rl.EmailModel=p;e.rl.Enums=h;e.__APP_BOOT=function(c){b(d.delay(function(){b("#rl-check").is(":visible")||g.$html.addClass("no-css");b("#rl-check").remove();
+e.rainloopTEMPLATES&&e.rainloopTEMPLATES[0]?(b("#rl-templates").html(e.rainloopTEMPLATES[0]),d.delay(function(){a.bootstart();g.$html.removeClass("no-js rl-booted-trigger").addClass("rl-booted")},10)):c(!1);e.__APP_BOOT=null},10))}}},function(h,f){h.exports=window.Autolinker},function(h,f){h.exports=window.JSEncrypt},,function(h,f){h.exports=window.hasher},function(h,f){h.exports=window.moment},function(h,f){h.exports=window.rainloopProgressJs},function(h,f){h.exports=window.ssm},,,,,function(h,f,
+c){(function(){var a=c(2);h.exports=new function(){this.coreReal=a.observable(!0);this.coreChannel=a.observable("stable");this.coreType=a.observable("stable");this.coreUpdatable=a.observable(!0);this.coreAccess=a.observable(!0);this.coreWarning=a.observable(!1);this.coreChecking=a.observable(!1).extend({throttle:100});this.coreUpdating=a.observable(!1).extend({throttle:100});this.coreVersion=a.observable("");this.coreRemoteVersion=a.observable("");this.coreRemoteRelease=a.observable("");this.coreVersionCompare=
+a.observable(-2)}})()},,,,function(h,f,c){(function(){function a(){q.call(this,"Popups","PopupsDomain");this.edit=d.observable(!1);this.saving=d.observable(!1);this.savingError=d.observable("");this.page=d.observable("main");this.sieveSettings=d.observable(!1);this.testing=d.observable(!1);this.testingDone=d.observable(!1);this.testingImapError=d.observable(!1);this.testingSieveError=d.observable(!1);this.testingSmtpError=d.observable(!1);this.testingImapErrorDesc=d.observable("");this.testingSieveErrorDesc=
+d.observable("");this.testingSmtpErrorDesc=d.observable("");this.testingImapError.subscribe(function(a){a||this.testingImapErrorDesc("")},this);this.testingSieveError.subscribe(function(a){a||this.testingSieveErrorDesc("")},this);this.testingSmtpError.subscribe(function(a){a||this.testingSmtpErrorDesc("")},this);this.imapServerFocus=d.observable(!1);this.sieveServerFocus=d.observable(!1);this.smtpServerFocus=d.observable(!1);this.name=d.observable("");this.name.focused=d.observable(!1);this.imapServer=
+d.observable("");this.imapPort=d.observable(""+g.IMAP_DEFAULT_PORT);this.imapSecure=d.observable(b.ServerSecure.None);this.imapShortLogin=d.observable(!1);this.useSieve=d.observable(!1);this.sieveAllowRaw=d.observable(!1);this.sieveServer=d.observable("");this.sievePort=d.observable(""+g.SIEVE_DEFAULT_PORT);this.sieveSecure=d.observable(b.ServerSecure.None);this.smtpServer=d.observable("");this.smtpPort=d.observable(""+g.SMTP_DEFAULT_PORT);this.smtpSecure=d.observable(b.ServerSecure.None);this.smtpShortLogin=
+d.observable(!1);this.smtpAuth=d.observable(!0);this.smtpPhpMail=d.observable(!1);this.whiteList=d.observable("");this.enableSmartPorts=d.observable(!1);this.allowSieve=d.computed(function(){return n.filters()&&n.sieve()},this);this.headerText=d.computed(function(){var a=this.name();return this.edit()?m.i18n("POPUPS_DOMAIN/TITLE_EDIT_DOMAIN",{NAME:a}):""===a?m.i18n("POPUPS_DOMAIN/TITLE_ADD_DOMAIN"):m.i18n("POPUPS_DOMAIN/TITLE_ADD_DOMAIN_WITH_NAME",{NAME:a})},this);this.domainDesc=d.computed(function(){var a=
+this.name();return!this.edit()&&a?m.i18n("POPUPS_DOMAIN/NEW_DOMAIN_DESC",{NAME:"*@"+a}):""},this);this.domainIsComputed=d.computed(function(){var a=this.smtpPhpMail(),b=this.allowSieve(),c=this.useSieve();return""!==this.name()&&""!==this.imapServer()&&""!==this.imapPort()&&(b&&c?""!==this.sieveServer()&&""!==this.sievePort():!0)&&(""!==this.smtpServer()&&""!==this.smtpPort()||a)},this);this.canBeTested=d.computed(function(){return!this.testing()&&this.domainIsComputed()},this);this.canBeSaved=d.computed(function(){return!this.saving()&&
+this.domainIsComputed()},this);this.createOrAddCommand=k.createCommand(this,function(){this.saving(!0);p.createOrUpdateDomain(e.bind(this.onDomainCreateOrSaveResponse,this),!this.edit(),this.name(),this.imapServer(),k.pInt(this.imapPort()),this.imapSecure(),this.imapShortLogin(),this.useSieve(),this.sieveAllowRaw(),this.sieveServer(),k.pInt(this.sievePort()),this.sieveSecure(),this.smtpServer(),k.pInt(this.smtpPort()),this.smtpSecure(),this.smtpShortLogin(),this.smtpAuth(),this.smtpPhpMail(),this.whiteList())},
+this.canBeSaved);this.testConnectionCommand=k.createCommand(this,function(){this.page("main");this.testingDone(!1);this.testingImapError(!1);this.testingSieveError(!1);this.testingSmtpError(!1);this.testing(!0);p.testConnectionForDomain(e.bind(this.onTestConnectionResponse,this),this.name(),this.imapServer(),k.pInt(this.imapPort()),this.imapSecure(),this.useSieve(),this.sieveServer(),k.pInt(this.sievePort()),this.sieveSecure(),this.smtpServer(),k.pInt(this.smtpPort()),this.smtpSecure(),this.smtpAuth(),
+this.smtpPhpMail())},this.canBeTested);this.whiteListCommand=k.createCommand(this,function(){this.page("white-list")});this.backCommand=k.createCommand(this,function(){this.page("main")});this.sieveCommand=k.createCommand(this,function(){this.sieveSettings(!this.sieveSettings());this.clearTesting()});this.page.subscribe(function(){this.sieveSettings(!1)},this);this.imapServerFocus.subscribe(function(a){a&&""!==this.name()&&""===this.imapServer()&&this.imapServer(this.name().replace(/[.]?[*][.]?/g,
+""))},this);this.sieveServerFocus.subscribe(function(a){a&&""!==this.imapServer()&&""===this.sieveServer()&&this.sieveServer(this.imapServer())},this);this.smtpServerFocus.subscribe(function(a){a&&""!==this.imapServer()&&""===this.smtpServer()&&this.smtpServer(this.imapServer().replace(/imap/ig,"smtp"))},this);this.imapSecure.subscribe(function(a){if(this.enableSmartPorts()){var b=k.pInt(this.imapPort());a=k.pString(a);switch(a){case "0":993===b&&this.imapPort("143");break;case "1":143===b&&this.imapPort("993")}}},
+this);this.smtpSecure.subscribe(function(a){if(this.enableSmartPorts()){var b=k.pInt(this.smtpPort());a=k.pString(a);switch(a){case "0":465!==b&&587!==b||this.smtpPort("25");break;case "1":25!==b&&587!==b||this.smtpPort("465");break;case "2":25!==b&&465!==b||this.smtpPort("587")}}},this);r.constructorEnd(this)}var e=c(3),d=c(2),b=c(4),g=c(17),f=c(8),k=c(1),m=c(6),n=c(50),p=c(20),r=c(5),q=c(10);r.extendAsViewModel(["View/Popup/Domain","PopupsDomainViewModel"],a);e.extend(a.prototype,q.prototype);a.prototype.onTestConnectionResponse=
+function(a,c){this.testing(!1);if(b.StorageResultType.Success===a&&c.Result){var d=!1,e=!1;this.testingDone(!0);this.testingImapError(!0!==c.Result.Imap);this.testingSieveError(!0!==c.Result.Sieve);this.testingSmtpError(!0!==c.Result.Smtp);this.testingImapError()&&c.Result.Imap&&(d=!0,this.testingImapErrorDesc(""),this.testingImapErrorDesc(c.Result.Imap));this.testingSieveError()&&c.Result.Sieve&&(e=!0,this.testingSieveErrorDesc(""),this.testingSieveErrorDesc(c.Result.Sieve));this.testingSmtpError()&&
+c.Result.Smtp&&(this.testingSmtpErrorDesc(""),this.testingSmtpErrorDesc(c.Result.Smtp));this.sieveSettings()?!e&&d&&this.sieveSettings(!1):e&&!d&&this.sieveSettings(!0)}else this.testingImapError(!0),this.testingSieveError(!0),this.testingSmtpError(!0),this.sieveSettings(!1)};a.prototype.onDomainCreateOrSaveResponse=function(a,d){this.saving(!1);b.StorageResultType.Success===a&&d?d.Result?(c(22).default.reloadDomainList(),this.closeCommand()):b.Notification.DomainAlreadyExists===d.ErrorCode&&this.savingError(m.i18n("ERRORS/DOMAIN_ALREADY_EXISTS")):
+this.savingError(m.i18n("ERRORS/UNKNOWN_ERROR"))};a.prototype.clearTesting=function(){this.testing(!1);this.testingDone(!1);this.testingImapError(!1);this.testingSieveError(!1);this.testingSmtpError(!1)};a.prototype.onHide=function(){this.page("main");this.sieveSettings(!1)};a.prototype.onShow=function(a){this.saving(!1);this.page("main");this.sieveSettings(!1);this.clearTesting();this.clearForm();a&&(this.enableSmartPorts(!1),this.edit(!0),this.name(k.trim(a.Name)),this.imapServer(k.trim(a.IncHost)),
+this.imapPort(""+k.pInt(a.IncPort)),this.imapSecure(k.trim(a.IncSecure)),this.imapShortLogin(!!a.IncShortLogin),this.useSieve(!!a.UseSieve),this.sieveAllowRaw(!!a.SieveAllowRaw),this.sieveServer(k.trim(a.SieveHost)),this.sievePort(""+k.pInt(a.SievePort)),this.sieveSecure(k.trim(a.SieveSecure)),this.smtpServer(k.trim(a.OutHost)),this.smtpPort(""+k.pInt(a.OutPort)),this.smtpSecure(k.trim(a.OutSecure)),this.smtpShortLogin(!!a.OutShortLogin),this.smtpAuth(!!a.OutAuth),this.smtpPhpMail(!!a.OutUsePhpMail),
+this.whiteList(k.trim(a.WhiteList)),this.enableSmartPorts(!0))};a.prototype.onShowWithDelay=function(){""!==this.name()||f.bMobile||this.name.focused(!0)};a.prototype.clearForm=function(){this.edit(!1);this.page("main");this.sieveSettings(!1);this.enableSmartPorts(!1);this.savingError("");this.name("");this.name.focused(!1);this.imapServer("");this.imapPort(""+g.IMAP_DEFAULT_PORT);this.imapSecure(b.ServerSecure.None);this.imapShortLogin(!1);this.useSieve(!1);this.sieveAllowRaw(!1);this.sieveServer("");
+this.sievePort(""+g.SIEVE_DEFAULT_PORT);this.sieveSecure(b.ServerSecure.None);this.smtpServer("");this.smtpPort(""+g.SMTP_DEFAULT_PORT);this.smtpSecure(b.ServerSecure.None);this.smtpShortLogin(!1);this.smtpAuth(!0);this.smtpPhpMail(!1);this.whiteList("");this.enableSmartPorts(!0)};h.exports=a})()},,,,,,,,,,,,,,,,,,,,function(h,f,c){(function(){function a(){d.call(this,"login",[c(140)])}var e=c(3),d=c(39);e.extend(a.prototype,d.prototype);a.prototype.onShow=function(){c(22).default.setWindowTitle("")};
+h.exports=a})()},function(h,f,c){(function(){function a(){g.call(this,[c(141),c(142)])}var e=c(3),d=c(5),b=c(23),g=c(56);e.extend(a.prototype,g.prototype);a.prototype.setupSettings=function(a){d.addSettingsViewModel(c(122),"AdminSettingsGeneral","TABS_LABELS/LABEL_GENERAL_NAME","general",!0);d.addSettingsViewModel(c(123),"AdminSettingsLogin","TABS_LABELS/LABEL_LOGIN_NAME","login");d.addSettingsViewModel(c(119),"AdminSettingsBranding","TABS_LABELS/LABEL_BRANDING_NAME","branding");d.addSettingsViewModel(c(120),
+"AdminSettingsContacts","TABS_LABELS/LABEL_CONTACTS_NAME","contacts");d.addSettingsViewModel(c(126),"AdminSettingsSecurity","TABS_LABELS/LABEL_SECURITY_NAME","security");d.addSettingsViewModel(c(125),"AdminSettingsPlugins","TABS_LABELS/LABEL_PLUGINS_NAME","plugins");d.addSettingsViewModel(c(118),"AdminSettingsAbout","TABS_LABELS/LABEL_ABOUT_NAME","about");b.runSettingsViewModelHooks(!0);a&&a()};a.prototype.onShow=function(){c(22).default.setWindowTitle("")};h.exports=a})()},,,,function(h,f,c){(function(){function a(){this.version=
+e.observable(b.appSettingsGet("version"));this.access=e.observable(!!b.settingsGet("CoreAccess"));this.errorDesc=e.observable("");this.coreReal=g.coreReal;this.coreChannel=g.coreChannel;this.coreType=g.coreType;this.coreUpdatable=g.coreUpdatable;this.coreAccess=g.coreAccess;this.coreChecking=g.coreChecking;this.coreUpdating=g.coreUpdating;this.coreWarning=g.coreWarning;this.coreVersion=g.coreVersion;this.coreRemoteVersion=g.coreRemoteVersion;this.coreRemoteRelease=g.coreRemoteRelease;this.coreVersionCompare=
+g.coreVersionCompare;this.community=!0;this.coreRemoteVersionHtmlDesc=e.computed(function(){d.trigger();return d.i18n("TAB_ABOUT/HTML_NEW_VERSION",{VERSION:this.coreRemoteVersion()})},this);this.statusType=e.computed(function(){var a="",b=this.coreVersionCompare(),c=this.coreChecking(),d=this.coreUpdating(),e=this.coreReal();c?a="checking":d?a="updating":e&&0===b?a="up-to-date":e&&-1===b?a="available":e||(a="error",this.errorDesc("Cannot access the repository at the moment."));return a},this)}var e=
+c(2),d=c(6),b=c(9),g=c(89);c(35);a.prototype.onBuild=function(){this.access()&&!this.community&&c(22).default.reloadCoreData()};a.prototype.updateCoreData=function(){this.coreUpdating()||this.community||c(22).default.updateCoreData()};h.exports=a})()},function(h,f,c){(function(){function a(){var a=c(4),b=c(9);this.capa=c(35).prem;this.title=d.observable(b.settingsGet("Title"));this.title.trigger=d.observable(a.SaveSettingsStep.Idle);this.loadingDesc=d.observable(b.settingsGet("LoadingDescription"));
+this.loadingDesc.trigger=d.observable(a.SaveSettingsStep.Idle);this.faviconUrl=d.observable(b.settingsGet("FaviconUrl"));this.faviconUrl.trigger=d.observable(a.SaveSettingsStep.Idle);this.loginLogo=d.observable(b.settingsGet("LoginLogo")||"");this.loginLogo.trigger=d.observable(a.SaveSettingsStep.Idle);this.loginBackground=d.observable(b.settingsGet("LoginBackground")||"");this.loginBackground.trigger=d.observable(a.SaveSettingsStep.Idle);this.userLogo=d.observable(b.settingsGet("UserLogo")||"");
+this.userLogo.trigger=d.observable(a.SaveSettingsStep.Idle);this.userLogoMessage=d.observable(b.settingsGet("UserLogoMessage")||"");this.userLogoMessage.trigger=d.observable(a.SaveSettingsStep.Idle);this.userIframeMessage=d.observable(b.settingsGet("UserIframeMessage")||"");this.userIframeMessage.trigger=d.observable(a.SaveSettingsStep.Idle);this.userLogoTitle=d.observable(b.settingsGet("UserLogoTitle")||"");this.userLogoTitle.trigger=d.observable(a.SaveSettingsStep.Idle);this.loginDescription=d.observable(b.settingsGet("LoginDescription"));
+this.loginDescription.trigger=d.observable(a.SaveSettingsStep.Idle);this.loginCss=d.observable(b.settingsGet("LoginCss"));this.loginCss.trigger=d.observable(a.SaveSettingsStep.Idle);this.userCss=d.observable(b.settingsGet("UserCss"));this.userCss.trigger=d.observable(a.SaveSettingsStep.Idle);this.welcomePageUrl=d.observable(b.settingsGet("WelcomePageUrl"));this.welcomePageUrl.trigger=d.observable(a.SaveSettingsStep.Idle);this.welcomePageDisplay=d.observable(b.settingsGet("WelcomePageDisplay"));this.welcomePageDisplay.trigger=
+d.observable(a.SaveSettingsStep.Idle);this.welcomePageDisplay.options=d.computed(function(){g.trigger();return[{optValue:"none",optText:g.i18n("TAB_BRANDING/OPTION_WELCOME_PAGE_DISPLAY_NONE")},{optValue:"once",optText:g.i18n("TAB_BRANDING/OPTION_WELCOME_PAGE_DISPLAY_ONCE")},{optValue:"always",optText:g.i18n("TAB_BRANDING/OPTION_WELCOME_PAGE_DISPLAY_ALWAYS")}]});this.loginPowered=d.observable(!!b.settingsGet("LoginPowered"));this.community=!0}var e=c(3),d=c(2),b=c(1),g=c(6);a.prototype.onBuild=function(){var a=
+this,d=c(20);e.delay(function(){var c=b.settingsSaveHelperSimpleFunction(a.title.trigger,a),e=b.settingsSaveHelperSimpleFunction(a.loadingDesc.trigger,a),g=b.settingsSaveHelperSimpleFunction(a.faviconUrl.trigger,a);a.title.subscribe(function(a){d.saveAdminConfig(c,{Title:b.trim(a)})});a.loadingDesc.subscribe(function(a){d.saveAdminConfig(e,{LoadingDescription:b.trim(a)})});a.faviconUrl.subscribe(function(a){d.saveAdminConfig(g,{FaviconUrl:b.trim(a)})})},50)};h.exports=a})()},function(h,f,c){(function(){function a(){var a=
+c(20);this.defautOptionsAfterRender=g.defautOptionsAfterRender;this.enableContacts=d.observable(!!k.settingsGet("ContactsEnable"));this.contactsSharing=d.observable(!!k.settingsGet("ContactsSharing"));this.contactsSync=d.observable(!!k.settingsGet("ContactsSync"));var h=[];k.settingsGet("SQLiteIsSupported")&&h.push("sqlite");k.settingsGet("MySqlIsSupported")&&h.push("mysql");k.settingsGet("PostgreSqlIsSupported")&&h.push("pgsql");this.contactsSupported=0"+a.readme()+""}};this.saveCommand=l.createCommand(this,function(){var a={};a.Name=this.name();e.each(this.configures(),function(b){var c=b.value();if(!1===c||!0===c)c=c?"1":"0";a["_"+b.Name]=c},this);this.saveError("");m.pluginSettingsUpdate(this.onPluginSettingsUpdateResponse,
+a)},this.hasConfiguration);this.bDisabeCloseOnEsc=!0;this.sDefaultKeyScope=f.KeyState.All;this.tryToClosePopup=e.debounce(e.bind(this.tryToClosePopup,this),200);n.constructorEnd(this)}var e=c(3),d=c(2),b=c(18),f=c(4),l=c(1),k=c(6),m=c(20),n=c(5),p=c(10);n.extendAsViewModel(["View/Popup/Plugin","PopupsPluginViewModel"],a);e.extend(a.prototype,p.prototype);a.prototype.onPluginSettingsUpdateResponse=function(a,b){f.StorageResultType.Success===a&&b&&b.Result?this.cancelCommand():(this.saveError(""),b&&
+b.ErrorCode?this.saveError(k.getNotification(b.ErrorCode)):this.saveError(k.getNotification(f.Notification.CantSavePluginSettings)))};a.prototype.onShow=function(a){this.name();this.readme();this.configures([]);a&&(this.name(a.Name),this.readme(a.Readme),a=a.Config,l.isNonEmptyArray(a)&&this.configures(e.map(a,function(a){return{value:d.observable(a[0]),placeholder:d.observable(a[6]),Name:a[1],Type:a[2],Label:a[3],Default:a[4],Desc:a[5]}})))};a.prototype.tryToClosePopup=function(){var a=this,b=c(43);
+n.isPopupVisible(b)||n.showScreenPopup(b,[k.i18n("POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW"),function(){a.modalVisibility()&&l.delegateRun(a,"cancelCommand")}])};a.prototype.onBuild=function(){b("esc",f.KeyState.All,e.bind(function(){this.modalVisibility()&&this.tryToClosePopup();return!1},this))};h.exports=a})()}]);
\ No newline at end of file
diff --git a/rainloop/rainloop/v/1.10.0.103/static/js/min/app.js b/rainloop/rainloop/v/1.10.0.103/static/js/min/app.js
new file mode 100644
index 0000000..c226ceb
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/static/js/min/app.js
@@ -0,0 +1,15 @@
+/* RainLoop Webmail (c) RainLoop Team | Licensed under AGPL v3 */
+!function(e){function t(o){if(i[o])return i[o].exports;var s=i[o]={exports:{},id:o,loaded:!1};return e[o].call(s.exports,s,s.exports,t),s.loaded=!0,s.exports}var i={};return t.m=e,t.c=i,t.p="rainloop/v/0.0.0/static/js/min/",t(0)}([function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}var s=i(77),n=o(s),r=i(7),a=o(r);(0,n["default"])(a["default"])},function(e,t,i){!function(){"use strict";var t=null,o={},s=i(11),n=i(3),r=i(14),a=i(2),l=i(78),c=i(36),u=i(79),d=i(66),p=i(4),h=i(8);o.trim=r.trim,o.inArray=r.inArray,o.isArray=n.isArray,o.isObject=n.isObject,o.isFunc=n.isFunction,o.isUnd=n.isUndefined,o.isNull=n.isNull,o.emptyFunction=o.noop=function(){},o.silentTryCatch=function(e){try{e()}catch(t){}},o.isNormal=function(e){return!o.isUnd(e)&&!o.isNull(e)},o.windowResize=n.debounce(function(e){o.isUnd(e)?h.$win.resize():s.setTimeout(function(){h.$win.resize()},e)},50),o.windowResizeCallback=function(){o.windowResize()},o.isPosNumeric=function(e,t){return o.isNormal(e)?(o.isUnd(t)?0:!t)?/^[1-9]+[0-9]*$/.test(e.toString()):/^[0-9]*$/.test(e.toString()):!1},o.pInt=function(e,t){var i=o.isNormal(e)&&""!==e?s.parseInt(e,10):t||0;return s.isNaN(i)?t||0:i},o.pString=function(e){return o.isNormal(e)?""+e:""},o.pBool=function(e){return!!e},o.encodeURIComponent=function(e){return s.encodeURIComponent(e)},o.isNonEmptyArray=function(e){return o.isArray(e)&&0n;n++)o=i[n].split("="),t[s.decodeURIComponent(o[0])]=s.decodeURIComponent(o[1]);return t},o.mailToHelper=function(e,t){if(e&&"mailto:"===e.toString().substr(0,7).toLowerCase()){if(!t)return!0;e=e.toString().substr(7);var r=[],a=null,l=null,c={},u=i(30),d=e.replace(/\?.+$/,""),h=e.replace(/^[^\?]*\?/,""),f=function(e){return e?n.compact(n.map(s.decodeURIComponent(e).split(/[,]/),function(e){var t=new u;return t.mailsoParse(e),""!==t.email?t:null})):null};return r=f(d),c=o.simpleQueryParser(h),o.isUnd(c.cc)||(a=f(s.decodeURIComponent(c.cc))),o.isUnd(c.bcc)||(l=f(s.decodeURIComponent(c.bcc))),i(5).showScreenPopup(t,[p.ComposeType.Empty,null,r,a,l,o.isUnd(c.subject)?null:o.pString(s.decodeURIComponent(c.subject)),o.isUnd(c.body)?null:o.plainToHtml(o.pString(s.decodeURIComponent(c.body)))]),!0}return!1},o.rsaObject=function(e){return u&&e&&(null===t||t&&t.__sPublicKey!==e)&&s.crypto&&s.crypto.getRandomValues?(t=new u,t.setPublicKey(e),t.__sPublicKey=e):t=!1,t},o.rsaEncode=function(e,t){if(s.crypto&&s.crypto.getRandomValues&&t){var i=!1,n=o.rsaObject(t);if(n&&(i=n.encrypt(o.fakeMd5()+":"+e+":"+o.fakeMd5()),!1!==i&&o.isNormal(i)))return"rsa:xxx:"+i}return e},o.rsaEncode.supported=(s.crypto&&s.crypto.getRandomValues,!1),o.encodeHtml=function(e){return o.isNormal(e)?n.escape(e.toString()):""},o.splitPlainText=function(e,t){var i="",s="",n=e,r=0,a=0;for(t=o.isUnd(t)?100:t;n.length>t;)s=n.substring(0,t),r=s.lastIndexOf(" "),a=s.lastIndexOf("\n"),-1!==a&&(r=a),-1===r&&(r=t),i+=s.substring(0,r)+"\n",n=n.substring(r+1);return i+n},o.timeOutAction=function(){var e={};return function(t,i,n){o.isUnd(e[t])&&(e[t]=0),s.clearTimeout(e[t]),e[t]=s.setTimeout(i,n)}}(),o.timeOutActionSecond=function(){var e={};return function(t,i,o){e[t]||(e[t]=s.setTimeout(function(){i(),e[t]=0},o))}}(),o.hos=function(e,t){return e&&s.Object&&s.Object.hasOwnProperty?s.Object.hasOwnProperty.call(e,t):!1},o.inFocus=function(){return s.document.activeElement?(o.isUnd(s.document.activeElement.__inFocusCache)&&(s.document.activeElement.__inFocusCache=r(s.document.activeElement).is("input,textarea,iframe,.cke_editable")),!!s.document.activeElement.__inFocusCache):!1},o.removeInFocus=function(e){if(s.document&&s.document.activeElement&&s.document.activeElement.blur){var t=r(s.document.activeElement);if(t.is("input,textarea"))s.document.activeElement.blur();else if(e)try{s.document.activeElement.blur()}catch(i){}}},o.removeSelection=function(){if(s&&s.getSelection){var e=s.getSelection();e&&e.removeAllRanges&&e.removeAllRanges()}else s.document&&s.document.selection&&s.document.selection.empty&&s.document.selection.empty()},o.replySubjectAdd=function(e,t){e=o.trim(e.toUpperCase()),t=o.trim(t.replace(/[\s]+/g," "));var i=!1,s=[],r="RE"===e,a="FWD"===e,l=!a;return""!==t&&n.each(t.split(":"),function(e){var t=o.trim(e);i||!/^(RE|FWD)$/i.test(t)&&!/^(RE|FWD)[\[\(][\d]+[\]\)]$/i.test(t)?(s.push(e),i=!0):(r||(r=!!/^RE/i.test(t)),a||(a=!!/^FWD/i.test(t)))}),l?r=!1:a=!1,o.trim((l?"Re: ":"Fwd: ")+(r?"Re: ":"")+(a?"Fwd: ":"")+o.trim(s.join(":")))},o.roundNumber=function(e,t){return s.Math.round(e*s.Math.pow(10,t))/s.Math.pow(10,t)},o.friendlySize=function(e){return e=o.pInt(e),e>=1073741824?o.roundNumber(e/1073741824,1)+"GB":e>=1048576?o.roundNumber(e/1048576,1)+"MB":e>=1024?o.roundNumber(e/1024,0)+"KB":e+"B"},o.log=function(e){s.console&&s.console.log&&s.console.log(e)},o.delegateRun=function(e,t,i,s){e&&e[t]&&(s=o.pInt(s),0>=s?e[t].apply(e,o.isArray(i)?i:[]):n.delay(function(){e[t].apply(e,o.isArray(i)?i:[])},s))},o.kill_CtrlA_CtrlS=function(e){if(e=e||s.event,e&&e.ctrlKey&&!e.shiftKey&&!e.altKey){var t=e.target||e.srcElement,i=e.keyCode||e.which;if(i===p.EventKeyCode.S)return void e.preventDefault();if(i===p.EventKeyCode.A){if(t&&("true"==""+t.contentEditable||t.tagName&&t.tagName.match(/INPUT|TEXTAREA/i)))return;s.getSelection?s.getSelection().removeAllRanges():s.document.selection&&s.document.selection.clear&&s.document.selection.clear(),e.preventDefault()}}},o.createCommand=function(e,t,i){var s=o.emptyFunction,n=function(){return s&&s.canExecute&&s.canExecute()&&t.apply(e,Array.prototype.slice.call(arguments)),!1};return s=t?n:o.emptyFunction,s.enabled=a.observable(!0),i=o.isUnd(i)?!0:i,o.isFunc(i)?s.canExecute=a.computed(function(){return s.enabled()&&i.call(e)}):s.canExecute=a.computed(function(){return s.enabled()&&!!i}),s},o.convertThemeName=n.memoize(function(e){return"@custom"===e.substr(-7)&&(e=o.trim(e.substring(0,e.length-7))),o.trim(e.replace(/[^a-zA-Z0-9]+/g," ").replace(/([A-Z])/g," $1").replace(/[\s]+/g," "))}),o.quoteName=function(e){return e.replace(/["]/g,'\\"')},o.microtime=function(){return(new s.Date).getTime()},o.timestamp=function(){return s.Math.round(o.microtime()/1e3)},o.convertLangName=function(e,t){return i(6).i18n("LANGS_NAMES"+(!0===t?"_EN":"")+"/LANG_"+e.toUpperCase().replace(/[^a-zA-Z0-9]+/g,"_"),null,e)},o.fakeMd5=function(e){var t="",i="0123456789abcdefghijklmnopqrstuvwxyz";for(e=o.isUnd(e)?32:o.pInt(e);t.length ').appendTo("#rl-hidden")},o.defautOptionsAfterRender=function(e,t){t&&!o.isUnd(t.disabled)&&e&&r(e).toggleClass("disabled",t.disabled).prop("disabled",t.disabled)},o.windowPopupKnockout=function(e,t,n,l){var c=null,u=s.open(""),d="__OpenerApplyBindingsUid"+o.fakeMd5()+"__",p=r("#"+t);s[d]=function(){if(u&&u.document.body&&p&&p[0]){var t=r(u.document.body);r("#rl-content",t).html(p.html()),r("html",u.document).addClass("external "+r("html").attr("class")),i(6).i18nToNodes(t),e&&r("#rl-content",t)[0]&&a.applyBindings(e,r("#rl-content",t)[0]),s[d]=null,l(u)}},u.document.open(),u.document.write('
'+o.encodeHtml(n)+'
'),u.document.close(),c=u.document.createElement("script"),c.type="text/javascript",c.innerHTML="if(window&&window.opener&&window.opener['"+d+"']){window.opener['"+d+"']();window.opener['"+d+"']=null}",u.document.getElementsByTagName("head")[0].appendChild(c)},o.settingsSaveHelperFunction=function(e,t,i,s){return i=i||null,s=o.isUnd(s)?1e3:o.pInt(s),function(o,r,a,l,c){t.call(i,r&&r.Result?p.SaveSettingsStep.TrueResult:p.SaveSettingsStep.FalseResult),e&&e.call(i,o,r,a,l,c),n.delay(function(){t.call(i,p.SaveSettingsStep.Idle)},s)}},o.settingsSaveHelperSimpleFunction=function(e,t){return o.settingsSaveHelperFunction(null,e,t,1e3)},o.settingsSaveHelperSubscribeFunction=function(e,t,i,s){return function(n){if(e){switch(i){default:n=o.pString(n);break;case"bool":case"boolean":n=n?"1":"0";break;case"int":case"integer":case"number":n=o.pInt(n);break;case"trim":n=o.trim(n)}var r={};r[t]=n,e.saveAdminConfig?e.saveAdminConfig(s||null,r):e.saveSettings&&e.saveSettings(s||null,r)}}},o.htmlToPlain=function(e){var t=0,i=0,s=0,a=0,l=0,c="",u=function(e){return e=o.trim(e),e="> "+e.replace(/\n/gm,"\n> "),e.replace(/(^|\n)([> ]+)/gm,function(){return arguments&&2
]*>([\s\S\r\n]*)<\/div>/gim,d),e="\n"+r.trim(e)+"\n"),e}return""},p=function(){return arguments&&1 ").replace(/[\r]/gm,""):""},f=function(){return arguments&&1]*><\/p>/gi,"").replace(/]*>([\s\S\r\n\t]*)<\/pre>/gim,p).replace(/[\s]+/gm," ").replace(/((?:href|data)\s?=\s?)("[^"]+?"|'[^']+?')/gim,f).replace(/ ]*>/gim,"\n").replace(/<\/h[\d]>/gi,"\n").replace(/<\/p>/gi,"\n\n").replace(/ ]*>/gim,"\n").replace(/<\/ul>/gi,"\n").replace(/]*>/gim," * ").replace(/<\/li>/gi,"\n").replace(/<\/td>/gi,"\n").replace(/<\/tr>/gi,"\n").replace(/ ]*>/gim,"\n_______________________________\n\n").replace(/]*>([\s\S\r\n]*)<\/div>/gim,d).replace(/
]*>/gim,"\n__bq__start__\n").replace(/<\/blockquote>/gim,"\n__bq__end__\n").replace(/]*>([\s\S\r\n]*?)<\/a>/gim,m).replace(/<\/div>/gi,"\n").replace(/ /gi," ").replace(/"/gi,'"').replace(/<[^>]*>/gm,""),c=h.$div.html(c).text(),c=c.replace(/\n[ \t]+/gm,"\n").replace(/[\n]{3,}/gm,"\n\n").replace(/>/gi,">").replace(/</gi,"<").replace(/&/gi,"&"),c=o.splitPlainText(o.trim(c)),t=0,l=800;l>0&&(l--,i=c.indexOf("__bq__start__",t),i>-1);)s=c.indexOf("__bq__start__",i+5),a=c.indexOf("__bq__end__",i+5),(-1===s||s>a)&&a>i?(c=c.substring(0,i)+u(c.substring(i+13,a))+c.substring(a+11),t=0):t=s>-1&&a>s?s-1:0;return c=c.replace(/__bq__start__/gm,"").replace(/__bq__end__/gm,"")},o.plainToHtml=function(e,t){e=e.toString().replace(/\r/g,""),t=o.isUnd(t)?!1:!!t;var i=!1,s=!0,n=!0,r=[],a="",l=0,c=e.split("\n");do{for(s=!1,r=[],l=0;l"===a.substr(0,1),n&&!i?(s=!0,i=!0,r.push("~~~blockquote~~~"),r.push(a.substr(1))):!n&&i?""!==a?(i=!1,r.push("~~~/blockquote~~~"),r.push(a)):r.push(a):n&&i?r.push(a.substr(1)):r.push(a);i&&(i=!1,r.push("~~~/blockquote~~~")),c=r}while(s);return e=c.join("\n"),e=e.replace(/&/g,"&").replace(/>/g,">").replace(/").replace(/[\s]*~~~\/blockquote~~~/g," ").replace(/\u200C([\s\S]*)\u200C/g,"$1").replace(/\n/g,"
"),t?o.findEmailAndLinks(e):e},s.rainloop_Utils_htmlToPlain=o.htmlToPlain,s.rainloop_Utils_plainToHtml=o.plainToHtml,o.findEmailAndLinks=function(e){return e=l.link(e,{newWindow:!0,stripPrefix:!1,urls:!0,email:!0,twitter:!1,replaceFn:function(e,t){return!(e&&t&&"url"===t.getType()&&t.matchedText&&0!==t.matchedText.indexOf("http"))}})},o.resizeAndCrop=function(e,t,i){var o=new s.Image;o.onload=function(){var e=[0,0],o=s.document.createElement("canvas"),n=o.getContext("2d");o.width=t,o.height=t,e=this.width>this.height?[this.width-this.height,0]:[0,this.height-this.width],n.fillStyle="#fff",n.fillRect(0,0,t,t),n.drawImage(this,e[0]/2,e[1]/2,this.width-e[0],this.height-e[1],0,0,t,t),i(o.toDataURL("image/jpeg"))},o.src=e},o.folderListOptionsBuilder=function(e,t,i,n,r,a,l,c,u,d){var h=null,f=!1,m=0,g=0,b=" ",y=[];for(d=o.isUnd(d)?!1:!!d,u=o.isNormal(u)?u:0
m;m++)y.push({id:n[m][0],name:n[m][1],system:!1,seporator:!1,disabled:!1});for(f=!0,m=0,g=e.length;g>m;m++)h=e[m],(l?l.call(null,h):!0)&&(f&&0m;m++)h=t[m],!h.subScribed()&&h.existen&&!d||!h.selectable&&!h.hasSubScribedSubfolders()||(l?l.call(null,h):!0)&&(p.FolderType.User!==h.type()&&u&&!h.hasSubScribedSubfolders()||(f&&01||c>0&&l>c){for(l>c?(u(c),i=c,n=c):((3>=l||l>=c-2)&&(r+=2),u(l),i=l,n=l);r>0;)if(i-=1,n+=1,i>0&&(u(i,!1),r--),c>=n)u(n,!0),r--;else if(0>=i)break;3===i?u(2,!1):i>3&&u(s.Math.round((i-1)/2),!1,"..."),c-2===n?u(c-1,!0):c-2>n&&u(s.Math.round((c+n)/2),!0,"..."),i>1&&u(1,!1),c>n&&u(c,!0)}return a}},o.selectElement=function(e){var t,i;s.getSelection?(t=s.getSelection(),t.removeAllRanges(),i=s.document.createRange(),i.selectNodeContents(e),t.addRange(i)):s.document.selection&&(i=s.document.body.createTextRange(),i.moveToElementText(e),i.select())},o.detectDropdownVisibility=n.debounce(function(){h.dropdownVisibility(!!n.find(h.aBootstrapDropdowns,function(e){return e.hasClass("open")}))},50),o.triggerAutocompleteInputChange=function(e){var t=function(){r(".checkAutocomplete").trigger("change")};(o.isUnd(e)?1:!e)?t():n.delay(t,100)},o.setHeadViewport=function(e){var t=[];n.each(e,function(e,i){t.push(""+e+"="+i)}),r("#rl-head-viewport").attr("content",t.join(", "))},o.getFileExtension=function(e){e=o.trim(e).toLowerCase();var t=e.split(".").pop();return t===e?"":t},o.configurationScriptTagCache={},o.getConfigurationFromScriptTag=function(e){var t={};o.configurationScriptTagCache[e]||(o.configurationScriptTagCache[e]=r('script[type="application/json"][data-configuration="'+e+'"]'));try{t=c.parse(o.configurationScriptTagCache[e].text())}catch(i){}return t},o.mimeContentType=function(e){var t="",i="application/octet-stream";return e=o.trim(e).toLowerCase(),"winmail.dat"===e?"application/ms-tnef":(t=o.getFileExtension(e),t&&0'),i.after(n),i.remove()),n&&n[0]&&(n.attr("data-href",a).attr("data-theme",e[0]),n[0].styleSheet&&!o.isUnd(n[0].styleSheet.cssText)?n[0].styleSheet.cssText=e[1]:n.text(e[1])),t(p.SaveSettingsStep.TrueResult))}).always(function(){o.__themeTimer=s.setTimeout(function(){t(p.SaveSettingsStep.Idle)},1e3),o.__themeAjax=null}))},o.substr=s.String.substr,"b"!=="ab".substr(-1)&&(o.substr=function(e,t,i){return 0>t&&(t=e.length+t),e.substr(t,i)}),e.exports=o}()},function(e,t,i){!function(t){"use strict";var o=i(11),s=i(3),n=i(14),r=i(36),a=i(54),l=function(e){t.utils.domNodeDisposal.addDisposeCallback(e,function(){e&&e.__opentip&&e.__opentip.deactivate()})};t.bindingHandlers.updateWidth={init:function(e,i){var s=n(o),r=n(e),a=i(),l=function(){a(r.width()),o.setTimeout(function(){a(r.width())},500)};s.on("resize",l),l(),t.utils.domNodeDisposal.addDisposeCallback(e,function(){s.off("resize",l)})}},t.bindingHandlers.editor={init:function(e,o){var s=null,n=o(),r=function(){n&&n.__editor&&n.__editor.setHtmlOrPlain(n())},a=function(){n&&n.__editor&&n(n.__editor.getDataWithHtmlMark())},l=function(){n.__editor=s,r()},c=i(45);t.isObservable(n)&&c&&(s=new c(e,a,l,a),n.__fetchEditorValue=a,n.subscribe(r))}},t.bindingHandlers.json={init:function(e,i){n(e).text(r.stringify(t.unwrap(i())))},update:function(e,i){n(e).text(r.stringify(t.unwrap(i())))}},t.bindingHandlers.scrollerShadows={init:function(e){var i=8,r=n(e),a=n(o),l=r.find("[data-scroller-shadows-content]")[0]||null,c=s.throttle(function(){r.toggleClass("scroller-shadow-top",i0&&(u+=s.pInt(a[2]),c=r.$win.height()-u,c>l&&(l=c),n(e).css({height:l,"min-height":l}))}},t.bindingHandlers.appendDom={update:function(e,i){n(e).hide().empty().append(t.unwrap(i())).show()}},t.bindingHandlers.draggable={init:function(e,s,r){var a=i(8),l=i(1);if(!a.bMobileDevice){var c=100,u=3,d=r(),p=d&&d.droppableSelector?d.droppableSelector:"",h={distance:20,handle:".dragHandle",cursorAt:{top:22,left:3},refreshPositions:!0,scroll:!0};p&&(h.drag=function(e){n(p).each(function(){var t=null,i=null,s=n(this),r=s.offset(),a=r.top+s.height();o.clearInterval(s.data("timerScroll")),s.data("timerScroll",!1),e.pageX>=r.left&&e.pageX<=r.left+s.width()&&(e.pageY>=a-c&&e.pageY<=a&&(t=function(){s.scrollTop(s.scrollTop()+u),l.windowResize()},s.data("timerScroll",o.setInterval(t,10)),t()),e.pageY>=r.top&&e.pageY<=r.top+c&&(i=function(){s.scrollTop(s.scrollTop()-u),l.windowResize()},s.data("timerScroll",o.setInterval(i,10)),i()))})},h.stop=function(){n(p).each(function(){o.clearInterval(n(this).data("timerScroll")),n(this).data("timerScroll",!1)})}),h.helper=function(e){return s()(e&&e.target?t.dataFor(e.target):null)},n(e).draggable(h).on("mousedown.koDraggable",function(){l.removeInFocus()}),t.utils.domNodeDisposal.addDisposeCallback(e,function(){n(e).off("mousedown.koDraggable").draggable("destroy")})}}},t.bindingHandlers.droppable={init:function(e,o,s){var r=i(8);if(!r.bMobileDevice){var a=o(),l=s(),c=l&&l.droppableOver?l.droppableOver:null,u=l&&l.droppableOut?l.droppableOut:null,d={tolerance:"pointer",hoverClass:"droppableHover"};a&&(d.drop=function(e,t){a(e,t)},c&&(d.over=function(e,t){c(e,t)}),u&&(d.out=function(e,t){u(e,t)}),n(e).droppable(d),t.utils.domNodeDisposal.addDisposeCallback(e,function(){n(e).droppable("destroy")}))}}},t.bindingHandlers.nano={init:function(e){var t=i(8);t.bDisableNanoScroll||n(e).addClass("nano").nanoScroller({iOSNativeScrolling:!1,preventPageScrolling:!0})}},t.bindingHandlers.saveTrigger={init:function(e){var t=n(e);t.data("save-trigger-type",t.is("input[type=text],input[type=email],input[type=password],select,textarea")?"input":"custom"),"custom"===t.data("save-trigger-type")?t.append(' ').addClass("settings-saved-trigger"):t.addClass("settings-saved-trigger-input")},update:function(e,i){var o=t.unwrap(i()),s=n(e);if("custom"===s.data("save-trigger-type"))switch(o.toString()){case"1":s.find(".animated,.error").hide().removeClass("visible").end().find(".success").show().addClass("visible");break;case"0":s.find(".animated,.success").hide().removeClass("visible").end().find(".error").show().addClass("visible");break;case"-2":s.find(".error,.success").hide().removeClass("visible").end().find(".animated").show().addClass("visible");break;default:s.find(".animated").hide().end().find(".error,.success").removeClass("visible")}else switch(o.toString()){case"1":s.addClass("success").removeClass("error");break;case"0":s.addClass("error").removeClass("success");break;case"-2":break;default:s.removeClass("error success")}}},t.bindingHandlers.emailsTags={init:function(e,t,o){var r=i(1),a=i(30),l=n(e),c=t(),u=o(),d=u.autoCompleteSource||null,p=function(e){c&&c.focused&&c.focused(!!e)};l.inputosaurus({parseOnBlur:!0,allowDragAndDrop:!0,focusCallback:p,inputDelimiters:[",",";","\n"],autoCompleteSource:d,parseHook:function(e){return s.map(e,function(e){var t=r.trim(e),i=null;return""!==t?(i=new a,i.mailsoParse(t),[i.toLine(!1),i]):[t,null]})},change:s.bind(function(e){l.data("EmailsTagsValue",e.target.value),c(e.target.value)},this)}),c&&c.focused&&c.focused.subscribe&&c.focused.subscribe(function(e){l.inputosaurus(e?"focus":"blur")})},update:function(e,i){var o=n(e),s=i(),r=t.unwrap(s);o.data("EmailsTagsValue")!==r&&(o.val(r),o.data("EmailsTagsValue",r),o.inputosaurus("refresh"))}},t.bindingHandlers.command={init:function(e,i,o,s){var r=n(e),a=i();if(!a||!a.enabled||!a.canExecute)throw new Error("You are not using command function");r.addClass("command"),t.bindingHandlers[r.is("form")?"submit":"click"].init.apply(s,arguments)},update:function(e,t){var i=!0,o=n(e),s=t();i=s.enabled(),o.toggleClass("command-not-enabled",!i),i&&(i=s.canExecute(),o.toggleClass("command-can-not-be-execute",!i)),o.toggleClass("command-disabled disable disabled",!i).toggleClass("no-disabled",!!i),(o.is("input")||o.is("button"))&&o.prop("disabled",!i)}},t.extenders.trimmer=function(e){var o=i(1),s=t.computed({read:e,write:function(t){e(o.trim(t.toString()))},owner:this});return s(e()),s},t.extenders.posInterer=function(e,o){var s=i(1),n=t.computed({read:e,write:function(t){var i=s.pInt(t.toString(),o);0>=i&&(i=o),i===e()&&""+i!=""+t&&e(i+1),e(i)}});return n(e()),n},t.extenders.limitedList=function(e,o){var s=i(1),n=t.computed({read:e,write:function(i){var n=t.unwrap(e),r=t.unwrap(o);s.isNonEmptyArray(r)?-1 ").addClass("rl-view-model").addClass("RL-"+r.viewModelTemplate()).hide(),p.appendTo(d),r.viewModelDom=p,e.__dom=p,"Popups"===a&&(r.cancelCommand=r.closeCommand=u.createCommand(r,function(){i.hideScreenPopup(e)}),r.modalVisibility.subscribe(function(e){var t=this;e?(this.viewModelDom.show(),this.storeAndSetKeyScope(),l.popupVisibilityNames.push(this.viewModelName),r.viewModelDom.css("z-index",3e3+l.popupVisibilityNames().length+10),this.onShowTrigger&&this.onShowTrigger(!this.onShowTrigger()),u.delegateRun(this,"onShowWithDelay",[],500)):(u.delegateRun(this,"onHide"),u.delegateRun(this,"onHideWithDelay",[],500),this.onHideTrigger&&this.onHideTrigger(!this.onHideTrigger()),this.restoreKeyScope(),o.each(this.viewModelNames,function(e){c.runHook("view-model-on-hide",[e,t])}),l.popupVisibilityNames.remove(this.viewModelName),r.viewModelDom.css("z-index",2e3),o.delay(function(){t.viewModelDom.hide()},300))},r)),o.each(e.__names,function(e){c.runHook("view-model-pre-build",[e,r,p])}),n.applyBindingAccessorsToNode(p[0],{translatorInit:!0,template:function(){return{name:r.viewModelTemplate()}}},r),u.delegateRun(r,"onBuild",[p]),r&&"Popups"===a&&r.registerPopupKeyDown(),o.each(e.__names,function(e){c.runHook("view-model-post-build",[e,r,p])})):u.log("Cannot find view model position: "+a)}return e?e.__vm:null},t.prototype.hideScreenPopup=function(e){e&&e.__vm&&e.__dom&&e.__vm.modalVisibility(!1)},t.prototype.showScreenPopup=function(e,t){e&&(this.buildViewModel(e),e.__vm&&e.__dom&&(u.delegateRun(e.__vm,"onBeforeShow",t||[]),e.__vm.modalVisibility(!0),u.delegateRun(e.__vm,"onShow",t||[]),o.each(e.__names,function(i){c.runHook("view-model-on-show",[i,e.__vm,t||[]])})))},t.prototype.isPopupVisible=function(e){return e&&e.__vm?e.__vm.modalVisibility():!1},t.prototype.screenOnRoute=function(e,t){var i=this,s=null,n=!1,r=null;""===u.pString(e)&&(e=this.sDefaultScreenName),""!==e&&(s=this.screen(e),s||(s=this.screen(this.sDefaultScreenName),s&&(t=e+"/"+t,e=this.sDefaultScreenName)),s&&s.__started&&(n=this.oCurrentScreen&&s===this.oCurrentScreen,s.__builded||(s.__builded=!0,u.isNonEmptyArray(s.viewModels())&&o.each(s.viewModels(),function(e){this.buildViewModel(e,s)},this),u.delegateRun(s,"onBuild")),o.defer(function(){i.oCurrentScreen&&!n&&(u.delegateRun(i.oCurrentScreen,"onHide"),u.delegateRun(i.oCurrentScreen,"onHideWithDelay",[],500),i.oCurrentScreen.onHideTrigger&&i.oCurrentScreen.onHideTrigger(!i.oCurrentScreen.onHideTrigger()),u.isNonEmptyArray(i.oCurrentScreen.viewModels())&&o.each(i.oCurrentScreen.viewModels(),function(e){e.__vm&&e.__dom&&"Popups"!==e.__vm.viewModelPosition()&&(e.__dom.hide(),e.__vm.viewModelVisibility(!1),u.delegateRun(e.__vm,"onHide"),u.delegateRun(e.__vm,"onHideWithDelay",[],500),e.__vm.onHideTrigger&&e.__vm.onHideTrigger(!e.__vm.onHideTrigger()))})),i.oCurrentScreen=s,i.oCurrentScreen&&!n&&(u.delegateRun(i.oCurrentScreen,"onShow"),i.oCurrentScreen.onShowTrigger&&i.oCurrentScreen.onShowTrigger(!i.oCurrentScreen.onShowTrigger()),c.runHook("screen-on-show",[i.oCurrentScreen.screenName(),i.oCurrentScreen]),u.isNonEmptyArray(i.oCurrentScreen.viewModels())&&o.each(i.oCurrentScreen.viewModels(),function(e){e.__vm&&e.__dom&&"Popups"!==e.__vm.viewModelPosition()&&(u.delegateRun(e.__vm,"onBeforeShow"),e.__dom.show(),e.__vm.viewModelVisibility(!0),u.delegateRun(e.__vm,"onShow"),e.__vm.onShowTrigger&&e.__vm.onShowTrigger(!e.__vm.onShowTrigger()),u.delegateRun(e.__vm,"onShowWithDelay",[],200),o.each(e.__names,function(t){c.runHook("view-model-on-show",[t,e.__vm])}))},i)),r=s.__cross?s.__cross():null,r&&r.parse(t)})))},t.prototype.startScreens=function(e){s("#rl-content").css({visibility:"hidden"}),o.each(e,function(e){if(e){var t=new e,i=t?t.screenName():"";t&&""!==i&&(""===this.sDefaultScreenName&&(this.sDefaultScreenName=i),this.oScreens[i]=t)}},this),o.each(this.oScreens,function(e){e&&!e.__started&&e.__start&&(e.__started=!0,e.__start(),c.runHook("screen-pre-start",[e.screenName(),e]),u.delegateRun(e,"onStart"),c.runHook("screen-post-start",[e.screenName(),e]))},this);var t=a.create();t.addRoute(/^([a-zA-Z0-9\-]*)\/?(.*)$/,o.bind(this.screenOnRoute,this)),r.initialized.add(t.parse,t),r.changed.add(t.parse,t),r.init(),s("#rl-content").css({visibility:"visible"}),o.delay(function(){l.$html.removeClass("rl-started-trigger").addClass("rl-started")},100),o.delay(function(){l.$html.addClass("rl-started-delay")},200)},t.prototype.setHash=function(e,t,i){e="#"===e.substr(0,1)?e.substr(1):e,e="/"===e.substr(0,1)?e.substr(1):e,i=u.isUnd(i)?!1:!!i,(u.isUnd(t)?1:!t)?(r.changed.active=!0,r[i?"replaceHash":"setHash"](e),r.setHash(e)):(r.changed.active=!1,r[i?"replaceHash":"setHash"](e),r.changed.active=!0)},e.exports=new t}()},function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var n=i(13),r=i(2),a=o(r),l=i(4),c=i(1),u=o(c),d=i(8),p=o(d),h=function(){function e(){s(this,e),this.data={},this.notificationI18N={},this.data=n.window.rainloopI18N||{},this.trigger=a["default"].observable(!1),this.i18n=n._.bind(this.i18n,this),this.init()}return e.prototype.i18n=function(e,t,i){var o="",s=this.data[e];if(n._.isUndefined(s)&&(s=n._.isUndefined(i)?e:i),!n._.isUndefined(t)&&!n._.isNull(t))for(o in t)n._.has(t,o)&&(s=s.replace("%"+o+"%",t[o]));return s},e.prototype.i18nToNode=function(e){var t=(0,n.$)(e),i=t.data("i18n");if(i)if("["===i.substr(0,1))switch(i.substr(0,6)){case"[html]":t.html(this.i18n(i.substr(6)));break;case"[place":t.attr("placeholder",this.i18n(i.substr(13)));break;case"[title":t.attr("title",this.i18n(i.substr(7)))}else t.text(this.i18n(i))},e.prototype.i18nToNodes=function(e){var t=this,i=arguments.length<=1||void 0===arguments[1]?!1:arguments[1];n._.defer(function(){(0,n.$)("[data-i18n]",e).each(function(e,i){t.i18nToNode(i)}),i&&p["default"].bAnimationSupported&&(0,n.$)(".i18n-animation[data-i18n]",e).letterfx({fx:"fall fade",backwards:!1,timing:50,fx_duration:"50ms",letter_end:"restore",element_end:"restore"})})},e.prototype.reloadData=function(){n.window.rainloopI18N&&(this.data=n.window.rainloopI18N||{},this.i18nToNodes(n.window.document,!0),i(26).reload(),this.trigger(!this.trigger())),n.window.rainloopI18N=null},e.prototype.initNotificationLanguage=function(){var e=this,t=[[l.Notification.InvalidToken,"NOTIFICATIONS/INVALID_TOKEN"],[l.Notification.InvalidToken,"NOTIFICATIONS/INVALID_TOKEN"],[l.Notification.AuthError,"NOTIFICATIONS/AUTH_ERROR"],[l.Notification.AccessError,"NOTIFICATIONS/ACCESS_ERROR"],[l.Notification.ConnectionError,"NOTIFICATIONS/CONNECTION_ERROR"],[l.Notification.CaptchaError,"NOTIFICATIONS/CAPTCHA_ERROR"],[l.Notification.SocialFacebookLoginAccessDisable,"NOTIFICATIONS/SOCIAL_FACEBOOK_LOGIN_ACCESS_DISABLE"],[l.Notification.SocialTwitterLoginAccessDisable,"NOTIFICATIONS/SOCIAL_TWITTER_LOGIN_ACCESS_DISABLE"],[l.Notification.SocialGoogleLoginAccessDisable,"NOTIFICATIONS/SOCIAL_GOOGLE_LOGIN_ACCESS_DISABLE"],[l.Notification.DomainNotAllowed,"NOTIFICATIONS/DOMAIN_NOT_ALLOWED"],[l.Notification.AccountNotAllowed,"NOTIFICATIONS/ACCOUNT_NOT_ALLOWED"],[l.Notification.AccountTwoFactorAuthRequired,"NOTIFICATIONS/ACCOUNT_TWO_FACTOR_AUTH_REQUIRED"],[l.Notification.AccountTwoFactorAuthError,"NOTIFICATIONS/ACCOUNT_TWO_FACTOR_AUTH_ERROR"],[l.Notification.CouldNotSaveNewPassword,"NOTIFICATIONS/COULD_NOT_SAVE_NEW_PASSWORD"],[l.Notification.CurrentPasswordIncorrect,"NOTIFICATIONS/CURRENT_PASSWORD_INCORRECT"],[l.Notification.NewPasswordShort,"NOTIFICATIONS/NEW_PASSWORD_SHORT"],[l.Notification.NewPasswordWeak,"NOTIFICATIONS/NEW_PASSWORD_WEAK"],[l.Notification.NewPasswordForbidden,"NOTIFICATIONS/NEW_PASSWORD_FORBIDDENT"],[l.Notification.ContactsSyncError,"NOTIFICATIONS/CONTACTS_SYNC_ERROR"],[l.Notification.CantGetMessageList,"NOTIFICATIONS/CANT_GET_MESSAGE_LIST"],[l.Notification.CantGetMessage,"NOTIFICATIONS/CANT_GET_MESSAGE"],[l.Notification.CantDeleteMessage,"NOTIFICATIONS/CANT_DELETE_MESSAGE"],[l.Notification.CantMoveMessage,"NOTIFICATIONS/CANT_MOVE_MESSAGE"],[l.Notification.CantCopyMessage,"NOTIFICATIONS/CANT_MOVE_MESSAGE"],[l.Notification.CantSaveMessage,"NOTIFICATIONS/CANT_SAVE_MESSAGE"],[l.Notification.CantSendMessage,"NOTIFICATIONS/CANT_SEND_MESSAGE"],[l.Notification.InvalidRecipients,"NOTIFICATIONS/INVALID_RECIPIENTS"],[l.Notification.CantSaveFilters,"NOTIFICATIONS/CANT_SAVE_FILTERS"],[l.Notification.CantGetFilters,"NOTIFICATIONS/CANT_GET_FILTERS"],[l.Notification.FiltersAreNotCorrect,"NOTIFICATIONS/FILTERS_ARE_NOT_CORRECT"],[l.Notification.CantCreateFolder,"NOTIFICATIONS/CANT_CREATE_FOLDER"],[l.Notification.CantRenameFolder,"NOTIFICATIONS/CANT_RENAME_FOLDER"],[l.Notification.CantDeleteFolder,"NOTIFICATIONS/CANT_DELETE_FOLDER"],[l.Notification.CantDeleteNonEmptyFolder,"NOTIFICATIONS/CANT_DELETE_NON_EMPTY_FOLDER"],[l.Notification.CantSubscribeFolder,"NOTIFICATIONS/CANT_SUBSCRIBE_FOLDER"],[l.Notification.CantUnsubscribeFolder,"NOTIFICATIONS/CANT_UNSUBSCRIBE_FOLDER"],[l.Notification.CantSaveSettings,"NOTIFICATIONS/CANT_SAVE_SETTINGS"],[l.Notification.CantSavePluginSettings,"NOTIFICATIONS/CANT_SAVE_PLUGIN_SETTINGS"],[l.Notification.DomainAlreadyExists,"NOTIFICATIONS/DOMAIN_ALREADY_EXISTS"],[l.Notification.CantInstallPackage,"NOTIFICATIONS/CANT_INSTALL_PACKAGE"],[l.Notification.CantDeletePackage,"NOTIFICATIONS/CANT_DELETE_PACKAGE"],[l.Notification.InvalidPluginPackage,"NOTIFICATIONS/INVALID_PLUGIN_PACKAGE"],[l.Notification.UnsupportedPluginPackage,"NOTIFICATIONS/UNSUPPORTED_PLUGIN_PACKAGE"],[l.Notification.LicensingServerIsUnavailable,"NOTIFICATIONS/LICENSING_SERVER_IS_UNAVAILABLE"],[l.Notification.LicensingExpired,"NOTIFICATIONS/LICENSING_EXPIRED"],[l.Notification.LicensingBanned,"NOTIFICATIONS/LICENSING_BANNED"],[l.Notification.DemoSendMessageError,"NOTIFICATIONS/DEMO_SEND_MESSAGE_ERROR"],[l.Notification.DemoAccountError,"NOTIFICATIONS/DEMO_ACCOUNT_ERROR"],[l.Notification.AccountAlreadyExists,"NOTIFICATIONS/ACCOUNT_ALREADY_EXISTS"],[l.Notification.AccountDoesNotExist,"NOTIFICATIONS/ACCOUNT_DOES_NOT_EXIST"],[l.Notification.MailServerError,"NOTIFICATIONS/MAIL_SERVER_ERROR"],[l.Notification.InvalidInputArgument,"NOTIFICATIONS/INVALID_INPUT_ARGUMENT"],[l.Notification.UnknownNotification,"NOTIFICATIONS/UNKNOWN_ERROR"],[l.Notification.UnknownError,"NOTIFICATIONS/UNKNOWN_ERROR"]];this.notificationI18N=this.notificationI18N||{},t.forEach(function(t){e.notificationI18N[t[0]]=e.i18n(t[1])})},e.prototype.initOnStartOrLangChange=function(e,t){var i=arguments.length<=2||void 0===arguments[2]?null:arguments[2];e&&e.call(t),i?this.trigger.subscribe(function(){e&&e.call(t),i.call(t)}):e&&this.trigger.subscribe(e,t)},e.prototype.getNotification=function(e){var t=arguments.length<=1||void 0===arguments[1]?"":arguments[1],i=arguments.length<=2||void 0===arguments[2]?null:arguments[2];return e=n.window.parseInt(e,10)||0,l.Notification.ClientViewError===e&&t?t:(i=i?n.window.parseInt(i,10)||0:0,n._.isUndefined(this.notificationI18N[e])?i&&n._.isUndefined(this.notificationI18N[i])?this.notificationI18N[i]:"":this.notificationI18N[e])},e.prototype.getNotificationFromResponse=function(e){var t=arguments.length<=1||void 0===arguments[1]?l.Notification.UnknownNotification:arguments[1];return e&&e.ErrorCode?this.getNotification(u["default"].pInt(e.ErrorCode),e.ErrorMessage||""):this.getNotification(t)},e.prototype.getUploadErrorDescByCode=function(e){var t="";switch(n.window.parseInt(e,10)||0){case l.UploadErrorCode.FileIsTooBig:t=this.i18n("UPLOAD/ERROR_FILE_IS_TOO_BIG");break;case l.UploadErrorCode.FilePartiallyUploaded:t=this.i18n("UPLOAD/ERROR_FILE_PARTIALLY_UPLOADED");break;case l.UploadErrorCode.FileNoUploaded:t=this.i18n("UPLOAD/ERROR_NO_FILE_UPLOADED");break;case l.UploadErrorCode.MissingTempFolder:t=this.i18n("UPLOAD/ERROR_MISSING_TEMP_FOLDER");break;case l.UploadErrorCode.FileOnSaveingError:t=this.i18n("UPLOAD/ERROR_ON_SAVING_FILE");break;case l.UploadErrorCode.FileType:t=this.i18n("UPLOAD/ERROR_FILE_TYPE");break;default:t=this.i18n("UPLOAD/ERROR_UNKNOWN")}return t},e.prototype.reload=function(e,t,o,s){var r=this,a=u["default"].microtime();p["default"].$html.addClass("rl-changing-language"),n.$.ajax({url:i(12).langLink(t,e),dataType:"script",cache:!0}).fail(s||u["default"].emptyFunction).done(function(){n._.delay(function(){r.reloadData(),(o||u["default"].emptyFunction)();var e=-1t?r:t)}};p(!1),F["default"].sub("layout",function(e){p(f.Layout.BottomPreview!==e)})},t.prototype.initVerticalLayoutResizer=function(e){var t=60,i=155,o=(0,l.$)("#rl-left"),s=(0,l.$)("#rl-right"),n=Q["default"].get(e)||null,r=function(e){e&&(y["default"].leftPanelWidth(e),y["default"].$html.removeClass("rl-resizer"),o.css({width:""+e+"px"}),s.css({left:""+e+"px"}))},a=function(s){if(s)o.resizable("disable"),r(t);else{o.resizable("enable");var n=C["default"].pInt(Q["default"].get(e))||i;r(n>i?n:i)}},c=function(e){e&&e.target&&(0,l.$)(e.target).find(".ui-resizable-handle").on("mousedown",function(){y["default"].$html.addClass("rl-resizer")}).on("mouseup",function(){y["default"].$html.removeClass("rl-resizer")})},u=l._.debounce(function(){y["default"].$html.addClass("rl-resizer")},500,!0),d=function(){y["default"].$html.addClass("rl-resizer")},p=function(t,i){y["default"].$html.removeClass("rl-resizer"),i&&i.size&&i.size.width&&(Q["default"].set(e,i.size.width),y["default"].leftPanelWidth(i.size.width),s.css({left:""+i.size.width+"px"}),o.css({position:"",top:"",left:"",height:""}))};null!==n&&r(n>i?n:i),o.resizable({helper:"ui-resizable-helper-w",minWidth:i,maxWidth:350,handles:"e",create:c,resize:u,start:d,stop:p}),F["default"].sub("left-panel.off",function(){a(!0)}),F["default"].sub("left-panel.on",function(){a(!1)})},t.prototype.logout=function(){var e=this;ie["default"].logout(function(){e.loginAndLogoutReload(!1,!0,ee["default"].settingsGet("ParentEmail")&&0=5?r:20,r=320>=r?r:320,l._.delay(function(){return t.contactsSync()},1e4),l._.delay(function(){return t.folderInformationMultiply(!0)},2e3),l.window.setInterval(function(){return t.contactsSync()},6e4*r+5e3),t.accountsAndIdentities(!0),l._.delay(function(){var e=j["default"].currentFolderFullNameRaw();I["default"].getFolderInboxName()!==e&&t.folderInformation(e)},1e3),l._.delay(function(){return t.quota()},5e3),l._.delay(function(){return ie["default"].appDelayStart(C["default"].emptyFunction)},35e3),F["default"].sub("rl.auto-logout",function(){return t.logout()}),v["default"].runHook("rl-start-user-screens"),F["default"].pub("rl.bootstart-user-screens"),ee["default"].settingsGet("WelcomePageUrl")&&l._.delay(function(){return t.bootstartWelcomePopup(ee["default"].settingsGet("WelcomePageUrl"))},1e3),ee["default"].settingsGet("AccountSignMe")&&l.window.navigator.registerProtocolHandler&&ee["default"].capa(f.Capa.Composer)&&l._.delay(function(){try{l.window.navigator.registerProtocolHandler("mailto",l.window.location.protocol+"//"+l.window.location.host+l.window.location.pathname+"?mailto&to=%s",""+(ee["default"].settingsGet("Title")||"RainLoop"))}catch(e){}ee["default"].settingsGet("MailToEmail")&&C["default"].mailToHelper(ee["default"].settingsGet("MailToEmail"),i(29))},500),y["default"].bMobileDevice||(l._.defer(function(){return t.initVerticalLayoutResizer(f.ClientSideKeyName.FolderListSize)}),p["default"]&&ee["default"].appSettingsGet("faviconStatus")&&!ee["default"].appSettingsGet("listPermanentFiltered")&&(p["default"].setOptions({fallback:!1}),F["default"].sub("mailbox.inbox-unread-count",function(e){return p["default"].setBubble(e>0?e>99?99:e:0)})))):t.logout()}))):(this.bootend(),this.bootstartLoginScreen()),a&&(l.window["rl_"+s+"_google_service"]=function(){k["default"].google.loading(!0),t.socialUsers()}),c&&(l.window["rl_"+s+"_facebook_service"]=function(){k["default"].facebook.loading(!0),t.socialUsers()}),d&&(l.window["rl_"+s+"_twitter_service"]=function(){k["default"].twitter.loading(!0),t.socialUsers()}),F["default"].sub("interval.1m",function(){return P["default"].reload()}),v["default"].runHook("rl-start-screens"),F["default"].pub("rl.bootstart-end")},t}(be.AbstractApp);t["default"]=new ye},function(e,t,i){!function(){"use strict";var t={},o=i(11),s=i(3),n=i(14),r=i(2),a=i(18),l=i(4);t.$win=n(o),t.$doc=n(o.document),t.$html=n("html"),t.$body=n("body"),t.$div=n("
"),t.$win.__sizes=[0,0],t.startMicrotime=(new o.Date).getTime(),t.community=!0,t.dropdownVisibility=r.observable(!1).extend({rateLimit:0}),t.useKeyboardShortcuts=r.observable(!0),t.iAjaxErrorCount=0,t.iTokenErrorCount=0,t.iMessageBodyCacheCount=0,t.bUnload=!1,t.sUserAgent="navigator"in o&&"userAgent"in o.navigator&&o.navigator.userAgent.toLowerCase()||"",t.bIE=t.sUserAgent.indexOf("msie")>-1,t.bChrome=t.sUserAgent.indexOf("chrome")>-1,t.bSafari=!t.bChrome&&t.sUserAgent.indexOf("safari")>-1,t.bMobileDevice=/android/i.test(t.sUserAgent)||/iphone/i.test(t.sUserAgent)||/ipod/i.test(t.sUserAgent)||/ipad/i.test(t.sUserAgent)||/blackberry/i.test(t.sUserAgent),t.bDisableNanoScroll=t.bMobileDevice,t.bAllowPdfPreview=!t.bMobileDevice,t.bAnimationSupported=!t.bMobileDevice&&t.$html.hasClass("csstransitions")&&t.$html.hasClass("cssanimations"),t.bXMLHttpRequestSupported=!!o.XMLHttpRequest,t.__APP__=null,t.oHtmlEditorDefaultConfig={title:!1,stylesSet:!1,customConfig:"",contentsCss:"",toolbarGroups:[{name:"spec"},{name:"styles"},{name:"basicstyles",groups:["basicstyles","cleanup","bidi"]},{name:"colors"},t.bMobileDevice?{}:{name:"paragraph",groups:["list","indent","blocks","align"]},{name:"links"},{name:"insert"},{name:"document",groups:["mode","document","doctools"]},{name:"others"}],removePlugins:"liststyle",removeButtons:"Format,Undo,Redo,Cut,Copy,Paste,Anchor,Strike,Subscript,Superscript,Image,SelectAll,Source",removeDialogTabs:"link:advanced;link:target;image:advanced;images:advanced",extraPlugins:"plain,signature",allowedContent:!0,extraAllowedContent:!0,fillEmptyBlocks:!1,ignoreEmptyParagraph:!0,disableNativeSpellChecker:!1,font_defaultLabel:"Arial",fontSize_defaultLabel:"13",fontSize_sizes:"10/10px;12/12px;13/13px;14/14px;16/16px;18/18px;20/20px;24/24px;28/28px;36/36px;48/48px"},t.oHtmlEditorLangsMap={bg_bg:"bg",de_de:"de",el_gr:"el",es_es:"es",fr_fr:"fr",hu_hu:"hu",is_is:"is",it_it:"it",ja_jp:"ja",ko_kr:"ko",lt_lt:"lt",lv_lv:"lv",nl_nl:"nl",bg_no:"no",pl_pl:"pl",pt_pt:"pt",pt_br:"pt-br",ro_ro:"ro",ru_ru:"ru",sk_sk:"sk",sl_si:"sl",sv_se:"sv",tr_tr:"tr",uk_ua:"ru",zh_tw:"zh",zh_cn:"zh-cn"},t.bAllowPdfPreview&&o.navigator&&o.navigator.mimeTypes&&(t.bAllowPdfPreview=!!s.find(o.navigator.mimeTypes,function(e){return e&&"application/pdf"===e.type}),t.bAllowPdfPreview||(t.bAllowPdfPreview="undefined"!=typeof o.navigator.mimeTypes["application/pdf"])),t.aBootstrapDropdowns=[],t.aViewModels={settings:[],"settings-removed":[],"settings-disabled":[]},t.leftPanelDisabled=r.observable(!1),t.leftPanelType=r.observable(""),t.leftPanelWidth=r.observable(0),t.popupVisibilityNames=r.observableArray([]),t.popupVisibility=r.computed(function(){return 00?"~"+r:"")}return t>1&&(s=s.replace(/[\/]+$/,""),s+="/p"+t),""!==i&&(s=s.replace(/[\/]+$/,""),s+="/"+n.window.encodeURI(i)),s},e.prototype.phpInfo=function(){return this.sServer+"Info"},e.prototype.langLink=function(e,t){return this.sServer+"/Lang/0/"+(t?"Admin":"App")+"/"+n.window.encodeURI(e)+"/"+this.sVersion+"/"},e.prototype.exportContactsVcf=function(){return this.sServer+"/Raw/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/ContactsVcf/"},e.prototype.exportContactsCsv=function(){return this.sServer+"/Raw/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/ContactsCsv/"},e.prototype.emptyContactPic=function(){return this.sStaticPrefix+"css/images/empty-contact.png"},e.prototype.sound=function(e){return this.sStaticPrefix+"sounds/"+e},e.prototype.themePreviewLink=function(e){var t=this.sVersionPrefix;return"@custom"===e.substr(-7)&&(e=a["default"].trim(e.substring(0,e.length-7)),t=this.sWebPrefix),t+"themes/"+n.window.encodeURI(e)+"/images/preview.png"},e.prototype.notificationMailIcon=function(){return this.sStaticPrefix+"css/images/icom-message-notification.png"},e.prototype.openPgpJs=function(){return this.sStaticPrefix+"js/min/openpgp.min.js"},e.prototype.openPgpWorkerJs=function(){return this.sStaticPrefix+"js/min/openpgp.worker.min.js"},e.prototype.openPgpWorkerPath=function(){return this.sStaticPrefix+"js/min/"},e.prototype.socialGoogle=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0];return this.sServer+"SocialGoogle"+(""!==this.sAuthSuffix?"/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/":"")+(e?"&xauth=1":"")},e.prototype.socialTwitter=function(){return this.sServer+"SocialTwitter"+(""!==this.sAuthSuffix?"/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/":"")},e.prototype.socialFacebook=function(){return this.sServer+"SocialFacebook"+(""!==this.sAuthSuffix?"/"+this.subQueryPrefix()+"/"+this.sAuthSuffix+"/":"")},e}();e.exports=new u},function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}t.__esModule=!0,t.key=t.moment=t.Q=t._=t.JSON=t.$=t.window=void 0;var s=i(11),n=o(s),r=i(14),a=o(r),l=i(36),c=o(l),u=i(3),d=o(u),p=i(48),h=o(p),f=i(82),m=o(f),g=i(18),b=o(g);t.window=n["default"],t.$=a["default"],t.JSON=c["default"],t._=d["default"],t.Q=h["default"],t.moment=m["default"],t.key=b["default"]},function(e,t){e.exports=window.jQuery},function(e,t,i){!function(){"use strict";function t(){p.call(this),this.oRequests={}}var o=i(3),s=i(1),n=i(17),r=i(161),a=i(19),l=i(12),c=i(9),u=i(24),d=i(28),p=i(55);o.extend(t.prototype,p.prototype),t.prototype.folders=function(e){this.defaultRequest(e,"Folders",{SentFolder:c.settingsGet("SentFolder"),DraftFolder:c.settingsGet("DraftFolder"),SpamFolder:c.settingsGet("SpamFolder"),TrashFolder:c.settingsGet("TrashFolder"),ArchiveFolder:c.settingsGet("ArchiveFolder")},null,"",["Folders"])},t.prototype.login=function(e,t,i,o,s,n,r,a){this.defaultRequest(e,"Login",{Email:t,Login:i,Password:o,Language:n||"",AdditionalCode:r||"",AdditionalCodeSignMe:a?"1":"0",SignMe:s?"1":"0"})},t.prototype.getTwoFactor=function(e){this.defaultRequest(e,"GetTwoFactorInfo")},t.prototype.createTwoFactor=function(e){this.defaultRequest(e,"CreateTwoFactorSecret")},t.prototype.clearTwoFactor=function(e){this.defaultRequest(e,"ClearTwoFactorInfo")},t.prototype.showTwoFactorSecret=function(e){this.defaultRequest(e,"ShowTwoFactorSecret")},t.prototype.testTwoFactor=function(e,t){this.defaultRequest(e,"TestTwoFactorInfo",{Code:t})},t.prototype.enableTwoFactor=function(e,t){this.defaultRequest(e,"EnableTwoFactor",{Enable:t?"1":"0"})},t.prototype.clearTwoFactorInfo=function(e){this.defaultRequest(e,"ClearTwoFactorInfo")},t.prototype.contactsSync=function(e){this.defaultRequest(e,"ContactsSync",null,n.CONTACTS_SYNC_AJAX_TIMEOUT)},t.prototype.saveContactsSyncData=function(e,t,i,o,s){this.defaultRequest(e,"SaveContactsSyncData",{Enable:t?"1":"0",Url:i,User:o,Password:s})},t.prototype.accountSetup=function(e,t,i,o){o=s.isUnd(o)?!0:!!o,this.defaultRequest(e,"AccountSetup",{Email:t,Password:i,New:o?"1":"0"})},t.prototype.accountDelete=function(e,t){this.defaultRequest(e,"AccountDelete",{EmailToDelete:t})},t.prototype.accountsAndIdentitiesSortOrder=function(e,t,i){this.defaultRequest(e,"AccountsAndIdentitiesSortOrder",{Accounts:t,Identities:i})},t.prototype.identityUpdate=function(e,t,i,o,s,n,r,a){this.defaultRequest(e,"IdentityUpdate",{Id:t,Email:i,Name:o,ReplyTo:s,Bcc:n,Signature:r,SignatureInsertBefore:a?"1":"0"})},t.prototype.identityDelete=function(e,t){this.defaultRequest(e,"IdentityDelete",{IdToDelete:t})},t.prototype.accountsAndIdentities=function(e){this.defaultRequest(e,"AccountsAndIdentities")},t.prototype.accountsCounts=function(e){this.defaultRequest(e,"AccountsCounts")},t.prototype.filtersSave=function(e,t,i,s){this.defaultRequest(e,"FiltersSave",{Raw:i,RawIsActive:s?"1":"0",Filters:o.map(t,function(e){return e.toJson()})})},t.prototype.filtersGet=function(e){this.defaultRequest(e,"Filters",{})},t.prototype.templates=function(e){this.defaultRequest(e,"Templates",{})},t.prototype.templateGetById=function(e,t){this.defaultRequest(e,"TemplateGetByID",{ID:t})},t.prototype.templateDelete=function(e,t){this.defaultRequest(e,"TemplateDelete",{IdToDelete:t})},t.prototype.templateSetup=function(e,t,i,o){this.defaultRequest(e,"TemplateSetup",{ID:t,Name:i,Body:o})},t.prototype.messageList=function(e,t,i,o,c,p,h){t=s.pString(t);var f=a.getFolderHash(t),m=u.threadsAllowed()&&d.useThreads(),g=a.getFolderInboxName()===t?a.getFolderUidNext(t):"";return h=s.isUnd(h)?!1:!!h,i=s.isUnd(i)?0:s.pInt(i),o=s.isUnd(i)?20:s.pInt(o),c=s.pString(c),p=s.pString(p),""===f||""!==c&&-1!==c.indexOf("is:")?this.defaultRequest(e,"MessageList",{Folder:t,Offset:i,Limit:o,Search:c,UidNext:g,UseThreads:m?"1":"0",ThreadUid:m?p:""},""===c?n.DEFAULT_AJAX_TIMEOUT:n.SEARCH_AJAX_TIMEOUT,"",h?[]:["MessageList"]):this.defaultRequest(e,"MessageList",{},""===c?n.DEFAULT_AJAX_TIMEOUT:n.SEARCH_AJAX_TIMEOUT,"MessageList/"+l.subQueryPrefix()+"/"+r.urlsafe_encode([t,i,o,c,u.projectHash(),f,g,m?"1":"0",m?p:""].join(String.fromCharCode(0))),h?[]:["MessageList"])},t.prototype.messageUploadAttachments=function(e,t){this.defaultRequest(e,"MessageUploadAttachments",{Attachments:t},999e3)},t.prototype.message=function(e,t,i){return t=s.pString(t),i=s.pInt(i),a.getFolderFromCacheList(t)&&i>0?(this.defaultRequest(e,"Message",{},null,"Message/"+l.subQueryPrefix()+"/"+r.urlsafe_encode([t,i,u.projectHash(),u.threadsAllowed()&&d.useThreads()?"1":"0"].join(String.fromCharCode(0))),["Message"]),!0):!1},t.prototype.composeUploadExternals=function(e,t){this.defaultRequest(e,"ComposeUploadExternals",{Externals:t},999e3)},t.prototype.composeUploadDrive=function(e,t,i){this.defaultRequest(e,"ComposeUploadDrive",{AccessToken:i,Url:t},999e3)},t.prototype.folderInformation=function(e,t,n){var r=!0,l=[];s.isArray(n)&&0",viewModel:{createViewModel:function(t,o){return t=t||{},t.element=null,o&&o.element&&(t.component=o,t.element=(0,n.$)(o.element),i(6).i18nToNodes(t.element),!c["default"].isUnd(t.inline)&&a["default"].unwrap(t.inline)&&t.element.css("display","inline-block")),new e(t)}}}};t.AbstractComponent=u,t.componentExportHelper=d},function(e,t){"use strict";t.__esModule=!0;t.MESSAGES_PER_PAGE=20,t.MESSAGES_PER_PAGE_VALUES=[10,20,30,50,100],t.CONTACTS_PER_PAGE=50,t.DEFAULT_AJAX_TIMEOUT=3e4,t.SEARCH_AJAX_TIMEOUT=3e5,t.SEND_MESSAGE_AJAX_TIMEOUT=3e5,t.SAVE_MESSAGE_AJAX_TIMEOUT=2e5,t.CONTACTS_SYNC_AJAX_TIMEOUT=2e5,t.UNUSED_OPTION_VALUE="__UNUSE__",t.CLIENT_SIDE_STORAGE_INDEX_NAME="rlcsc",t.IMAP_DEFAULT_PORT=143,t.IMAP_DEFAULT_SECURE_PORT=993,t.SMTP_DEFAULT_PORT=25,t.SMTP_DEFAULT_SECURE_PORT=465,t.SIEVE_DEFAULT_PORT=4190,t.MESSAGE_BODY_CACHE_LIMIT=15,t.AJAX_ERROR_LIMIT=7,t.TOKEN_ERROR_LIMIT=10,t.RAINLOOP_TRIAL_KEY="RAINLOOP-TRIAL-KEY",t.DATA_IMAGE_USER_DOT_PIC="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAuCAYAAABXuSs3AAAHHklEQVRoQ7VZW08bVxCeXRuwIbTGXIwNtBBaqjwgVUiR8lDlbza9qe1DpVZ9aNQ/0KpPeaJK07SpcuEeCEmUAObm21bfrL9lONjexSYrWfbunj37zXdmvpkz9oIgCKTD0Wg0xPd94TDP83Q0zvWa50vzklSrdanVanqf4/D84GBGr+F+Op3S8fqoJxLOdnZgTvsO/nYhenHA+UC7CWF1uXwkb9++ldPTUwVerVbVqFQqpR8YPjQ0JCMjI5LNDijoRgP3PQVu5+5Eor2XGLg7IV4GkIdHJ/LmzRs5ODiIwNbrdR0O0GCcq4Xz4eFhmZyclP7+tDQaIik/BG5XKQn4SwG3zJTLZXn9+rUclI8UHD5YVoDDN8bSzXhONwL48fFxGR4eilzFZT1uFRIB5yT8BqCdnR3Z3d0VP9Un6XRawYJpggVrZBv38ME4XKtUKnLt2jUplUoy1PR/l3U7T6sVSAQcgMAkj8PDQ9ne3pajoyMRL7zeKsYZWHgWYDGmv78/mmdwcFA+mJlSgziHDWrERrsjEXDXegTi1tZW+DLxI2bxIrqFNYTXyDyCFweMAHCwb8e4RnTNuOsqe3t7sra21pTD0Kct666E8XlcZyzw9/RUUXK5nK5oUinUQI6TQ3cynO/v78vq6qrKXCNwlTiJJpyNGc3nZHp6uqV2dwrQWOCtZBDAV1ZWwsQk7f0wiQn5kffbAu/0/KWBYzIC1+XukfGx0RGZmppKlC2tIV0Bh4aDcZW7HhkfH8urLLZL7T2pihvlkMNnz56FiadHxicL41IsFpN41bkxsYxbRdFo9jwB8KdPn14J8KnSpBQKhQs63nPmbCVRcBUAR2Lq1VVmpksyMTFxAXjcEsQybiegESionjx5osCZOeNe1O4+EhCAX7bQSgQcxRHTMgAgcz5+/Dis/hL4uHU3/B4YGNASGHIKxuEql0k+l05AeIAF1vPnz5VxFFmdDlaJrMtZITJeSsXCOTlMunKxjLtMYOKNjQ158eJFuAuKkUOb5sEwgff19SkJUBVkThZUbnXZrtCKBQ6gbnWIkjZpyne3ejAWoGnA7Icz6irvBLgbOMicCM6TkxPx/LAkbXfgWcsazuE2kFRsKD5Z+CiqDumKncpZvieWcS6dDVD8xiYCNflpJdwcdwJOf9airLmVQ7DPzMxIYWLsXGXoVqLt5k0M3K3JUVPDZdbWNzsCp48TPFdvdnZWUz32nDha7bJ63kgAJPzSdRks9/Kf9xMJAQ1gq2NpaUmy2Yz4zar4nQC3xb99AQwCcGzLAAwuhG8YiWvcOKts+r4GOe5nMhm5efOm9lUA3E3vSZJRrKvE0fnPv//Jy5cvo5cTHIPQbSjhOoqq69evS19f6lxDKK4+sVhigZPtKJqbrQeqxd5+WR4+fKgqgT0k2XX3nhiPgETWXFhYkFzuPZ2yVq1GTSOXpE47/VjgNnD4m4GG7/LhsTx69EiwD4Vr2MwIIxgbAH18fKx1yfz8vEogNvGtWnCuhLZa9UTAreVWFsHy/b/+Vrbdl7E5REMQD2jDoUbByty+/ZnU64GkU2HzyJLhktU1cLv8nARgkYS2d3ajAgwG8qU2oLmDZ92CMaOjo7K4uCiZgbDWaRWgnZhPxLhrMUCvr69riwKZk1LHF7XqrWAO9hJxH6ozNzcnCx/PqztZg9mf6SQMscCtm2C5ke4BGMlHWTUp36036AJajDVrFMzBrhhWslQsSrFYiOqVpMriNYIgqFRq2j3FAb/zffT6zuxFXxsNzs3NTXn16lW4gYiW96w1FyedF+83xG/2FNGCRpU4NjamMsn+OZ9xE5RXqdaDdPpib6RWCzuwKF9RxqI2AVNQBwQYJoK0wdBejnqtEikP3pfP51XjUTESl12FqJEKxsEorARYDD44ONTeID7YpsEnrRvQfWAI2e8WfDaTUSIwJ0iBCmFOtOUAHvVMPp/TPwvYFVYFIuP8l+DBgwdaa2Miqwa0GgYwfeMltovbDfh6c1vIgMYcliSsKv4IWFr6VDHxvldvBAH+1sA+cnl5WYOPmmr9ir+1l9I0Cgz0yjhXjfJJ0JROnmezWbl165ayr/5fqwcBNr7IfhjMqKcvESSM4eRcCasQ3bDNObmKPLdGUGpZsN24cUNLBm9zazu4d++e6qpNBFaTuUS26U5dpuR1CxyA7J9ddrMRqlz4pwLLYawymPd++/2PADt2ugcGwq9gCCdhQ96C6xWwa6j1ceuq+I0EhW0i8MAIVJfeL3d/DVD8EKi12P6/2S2jV/EccVB54O/ejz/9HGCpoBBMta5rXMXLu53D1XAwjhXwvvv+h4BAXVe4bOu3O3ChxF08LiZFG3fel199G9CH3fLyqv24NcB44MRhpdK788U3CpyKwsCw590xmfSpzsBt0Fqc3ud3vtZigxWcVZCklVpSiN0w3q5E/h9TGMIUuA3+EQAAAABJRU5ErkJggg==",t.DATA_IMAGE_TRANSP_PIC="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQIW2NkAAIAAAoAAggA9GkAAAAASUVORK5CYII="},function(e,t){e.exports=window.key},function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var n=i(13),r=i(4),a=i(1),l=o(a),c=i(12),u=o(c),d=i(9),p=o(d),h=function(){function e(){s(this,e),this.oFoldersCache={},this.oFoldersNamesCache={},this.oFolderHashCache={},this.oFolderUidNextCache={},this.oMessageListHashCache={},this.oMessageFlagsCache={},this.oNewMessage={},this.oRequestedMessage={},this.bCapaGravatar=!1,this.inboxFolderName="",this.bCapaGravatar=p["default"].capa(r.Capa.Gravatar)}return e.prototype.clear=function(){this.oFoldersCache={},this.oFoldersNamesCache={},this.oFolderHashCache={},this.oFolderUidNextCache={},this.oMessageListHashCache={},this.oMessageFlagsCache={}},e.prototype.getUserPic=function(e,t){e=l["default"].trim(e),t(this.bCapaGravatar&&""!==e?u["default"].avatarLink(e):"",e)},e.prototype.getMessageKey=function(e,t){return e+"#"+t},e.prototype.addRequestedMessage=function(e,t){this.oRequestedMessage[this.getMessageKey(e,t)]=!0},e.prototype.hasRequestedMessage=function(e,t){return!0===this.oRequestedMessage[this.getMessageKey(e,t)]},e.prototype.addNewMessageCache=function(e,t){this.oNewMessage[this.getMessageKey(e,t)]=!0},e.prototype.hasNewMessageAndRemoveFromCache=function(e,t){return this.oNewMessage[this.getMessageKey(e,t)]?(this.oNewMessage[this.getMessageKey(e,t)]=null,!0):!1},e.prototype.clearNewMessageCache=function(){this.oNewMessage={}},e.prototype.getFolderInboxName=function(){return""===this.inboxFolderName?"INBOX":this.inboxFolderName},e.prototype.getFolderFullNameRaw=function(e){return""!==e&&this.oFoldersNamesCache[e]?this.oFoldersNamesCache[e]:""},e.prototype.setFolderFullNameRaw=function(e,t){this.oFoldersNamesCache[e]=t,"INBOX"!==t&&""!==this.inboxFolderName||(this.inboxFolderName=t)},e.prototype.getFolderHash=function(e){return""!==e&&this.oFolderHashCache[e]?this.oFolderHashCache[e]:""},e.prototype.setFolderHash=function(e,t){""!==e&&(this.oFolderHashCache[e]=t)},e.prototype.getFolderUidNext=function(e){return""!==e&&this.oFolderUidNextCache[e]?this.oFolderUidNextCache[e]:""},e.prototype.setFolderUidNext=function(e,t){this.oFolderUidNextCache[e]=t},e.prototype.getFolderFromCacheList=function(e){return""!==e&&this.oFoldersCache[e]?this.oFoldersCache[e]:null},e.prototype.setFolderToCacheList=function(e,t){this.oFoldersCache[e]=t},e.prototype.removeFolderFromCacheList=function(e){this.setFolderToCacheList(e,null)},e.prototype.getMessageFlagsFromCache=function(e,t){return this.oMessageFlagsCache[e]&&this.oMessageFlagsCache[e][t]?this.oMessageFlagsCache[e][t]:null},e.prototype.setMessageFlagsToCache=function(e,t,i){this.oMessageFlagsCache[e]||(this.oMessageFlagsCache[e]={}),this.oMessageFlagsCache[e][t]=i},e.prototype.clearMessageFlagsFromCacheByFolder=function(e){this.oMessageFlagsCache[e]={}},e.prototype.initMessageFlagsFromCache=function(e){var t=this;e&&!function(){var i=e.uid,o=t.getMessageFlagsFromCache(e.folderFullNameRaw,i);if(o&&0e.interval&&(e.isSystemFolder()||e.subScribed()&&e.checkable())&&r.push([e.interval,e.fullNameRaw]),e&&0t[0]?1:0}),o.find(r,function(i){var o=l.getFolderFromCacheList(i[1]);return o&&(o.interval=s,e.push(i[1])),t<=e.length}),e=o.uniq(e)},e.exports=new t}()},,function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var n=i(13),r=i(1),a=o(r),l=i(8),c=o(l),u=i(9),d=o(u),p=function(){function e(){s(this,e),this.oSimpleHooks={},this.aUserViewModelsHooks=[],this.aAdminViewModelsHooks=[]}return e.prototype.addHook=function(e,t){a["default"].isFunc(t)&&(a["default"].isArray(this.oSimpleHooks[e])||(this.oSimpleHooks[e]=[]),this.oSimpleHooks[e].push(t))},e.prototype.runHook=function(e){var t=arguments.length<=1||void 0===arguments[1]?[]:arguments[1];a["default"].isArray(this.oSimpleHooks[e])&&n._.each(this.oSimpleHooks[e],function(e){e.apply(null,t)})},e.prototype.mainSettingsGet=function(e){return d["default"].settingsGet(e)},e.prototype.remoteRequest=function(e,t,i,o){c["default"].__APP__&&c["default"].__APP__.remote().defaultRequest(e,"Plugin"+t,i,o)},e.prototype.addSettingsViewModel=function(e,t,i,o){this.aUserViewModelsHooks.push([e,t,i,o])},e.prototype.addSettingsViewModelForAdmin=function(e,t,i,o){this.aAdminViewModelsHooks.push([e,t,i,o])},e.prototype.runSettingsViewModelHooks=function(e){var t=i(5);n._.each(e?this.aAdminViewModelsHooks:this.aUserViewModelsHooks,function(e){t.addSettingsViewModel(e[0],e[1],e[2],e[3])})},e.prototype.settingsGet=function(e,t){var i=d["default"].settingsGet("Plugins");return i=i&&!a["default"].isUnd(i[e])?i[e]:null,i?a["default"].isUnd(i[t])?null:i[t]:null},e}();e.exports=new p},function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function n(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function r(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var a=i(2),l=o(a),c=i(4),u=i(8),d=o(u),p=i(1),h=o(p),f=i(9),m=o(f),g=i(76),b=function(e){function t(){s(this,t);var i=n(this,e.call(this));return i.currentAudio=l["default"].observable(""),i.focusedState=l["default"].observable(c.Focused.None),i.focusedState.subscribe(function(e){switch(e){default:break;case c.Focused.MessageList:d["default"].keyScope(c.KeyState.MessageList);break;case c.Focused.MessageView:d["default"].keyScope(c.KeyState.MessageView);break;case c.Focused.FolderList:d["default"].keyScope(c.KeyState.FolderList)}},i),i.projectHash=l["default"].observable(""),i.threadsAllowed=l["default"].observable(!1),i.composeInEdit=l["default"].observable(!1),i.contactsAutosave=l["default"].observable(!1),i.useLocalProxyForExternalImages=l["default"].observable(!1),i.contactsIsAllowed=l["default"].observable(!1),i.attachmentsActions=l["default"].observableArray([]),i.devEmail="",i.devPassword="",i}return r(t,e),t.prototype.populate=function(){e.prototype.populate.call(this),this.projectHash(m["default"].settingsGet("ProjectHash")),this.contactsAutosave(!!m["default"].settingsGet("ContactsAutosave")),this.useLocalProxyForExternalImages(!!m["default"].settingsGet("UseLocalProxyForExternalImages")),this.contactsIsAllowed(!!m["default"].settingsGet("ContactsIsAllowed"));var t=m["default"].appSettingsGet("attachmentsActions");this.attachmentsActions(h["default"].isNonEmptyArray(t)?t:[]),this.devEmail=m["default"].settingsGet("DevEmail"),this.devPassword=m["default"].settingsGet("DevPassword")},t}(g.AbstractAppStore);e.exports=new b},function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var n=i(13),r=i(1),a=o(r),l=i(23),c=o(l),u=function(){function e(){s(this,e),this.subs={}}return e.prototype.sub=function(e,t,i){var o=this;return a["default"].isObject(e)?(i=t||null,t=null,n._.each(e,function(e,t){o.sub(t,e,i)},this)):(a["default"].isUnd(this.subs[e])&&(this.subs[e]=[]),this.subs[e].push([t,i])),this},e.prototype.pub=function(e,t){return c["default"].runHook("rl-pub",[e,t]),a["default"].isUnd(this.subs[e])||n._.each(this.subs[e],function(e){e[0]&&e[0].apply(e[1]||null,t||[])}),this},e}();e.exports=new u},function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var n=i(13),r=i(6),a=o(r),l=function(){function e(){var t=this;s(this,e),this._moment=null,this._momentNow=0,this.updateMomentNow=n._.debounce(function(){t._moment=(0,n.moment)()},500,!0),this.updateMomentNowUnix=n._.debounce(function(){t._momentNow=(0,n.moment)().unix()},500,!0),this.format=n._.bind(this.format,this)}return e.prototype.momentNow=function(){return this.updateMomentNow(),this._moment||(0,n.moment)()},e.prototype.momentNowUnix=function(){return this.updateMomentNowUnix(),this._momentNow||0},e.prototype.searchSubtractFormatDateHelper=function(e){return this.momentNow().clone().subtract("days",e).format("YYYY.MM.DD")},e.prototype.formatCustomShortDate=function(e){var t=this.momentNow();if(e&&t)switch(!0){case 4>=t.diff(e,"hours"):return e.fromNow();case t.format("L")===e.format("L"):return a["default"].i18n("MESSAGE_LIST/TODAY_AT",{TIME:e.format("LT")});case t.clone().subtract("days",1).format("L")===e.format("L"):return a["default"].i18n("MESSAGE_LIST/YESTERDAY_AT",{TIME:e.format("LT")});case t.year()===e.year():return e.format("D MMM.")}return e?e.format("LL"):""},e.prototype.format=function(e,t){var i=null,o="",s=this.momentNowUnix();if(e=e>0?e:0===e?s:0,e=e>s?s:e,i=e>0?n.moment.unix(e):null,i&&1970===i.year()&&(i=null),i)switch(t){case"FROMNOW":o=i.fromNow();break;case"SHORT":o=this.formatCustomShortDate(i);break;case"FULL":o=i.format("LLL");break;default:o=i.format(t)}return o},e.prototype.momentToNode=function(e){var t="",i=0,o=(0,n.$)(e);i=o.data("moment-time"),i&&(t=o.data("moment-format"),t&&o.text(this.format(i,t)),t=o.data("moment-format-title"),t&&o.attr("title",this.format(i,t)))},e.prototype.momentToNodes=function(e){var t=this;n._.defer(function(){(0,n.$)(".moment",e).each(function(e,i){t.momentToNode(i)})})},e.prototype.reload=function(){this.momentToNodes(n.window.document)},e}();e.exports=new l},function(e,t,i){!function(){"use strict";function t(e){this.sModelName=e||"",this.disposables=[]}var o=i(3),s=i(1);t.prototype.regDisposables=function(e){s.isArray(e)?o.each(e,function(e){this.disposables.push(e)},this):e&&this.disposables.push(e)},t.prototype.onDestroy=function(){s.disposeObject(this)},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){this.iAutoLogoutTimer=0,this.layout=s.observable(r.Layout.SidePreview).extend({limitedList:[r.Layout.SidePreview,r.Layout.BottomPreview,r.Layout.NoPreview]}),this.editorDefaultType=s.observable(r.EditorDefaultType.Html).extend({limitedList:[r.EditorDefaultType.Html,r.EditorDefaultType.Plain,r.EditorDefaultType.HtmlForced,r.EditorDefaultType.PlainForced]}),this.messagesPerPage=s.observable(n.MESSAGES_PER_PAGE).extend({limitedList:n.MESSAGES_PER_PAGE_VALUES}),this.showImages=s.observable(!1),this.useCheckboxesInList=s.observable(!0),this.useThreads=s.observable(!1),this.replySameFolder=s.observable(!1),this.autoLogout=s.observable(30),this.computers(),this.subscribers()}var o=i(11),s=i(2),n=i(17),r=i(4),a=i(8),l=i(1),c=i(25),u=i(9);t.prototype.computers=function(){this.usePreviewPane=s.computed(function(){return r.Layout.NoPreview!==this.layout()},this)},t.prototype.subscribers=function(){this.layout.subscribe(function(e){a.$html.toggleClass("rl-no-preview-pane",r.Layout.NoPreview===e),a.$html.toggleClass("rl-side-preview-pane",r.Layout.SidePreview===e),a.$html.toggleClass("rl-bottom-preview-pane",r.Layout.BottomPreview===e),a.$html.toggleClass("rl-mobile-layout",r.Layout.Mobile===e),c.pub("layout",[e])})},t.prototype.populate=function(){this.layout(l.pInt(u.settingsGet("Layout"))),this.editorDefaultType(u.settingsGet("EditorDefaultType")),this.autoLogout(l.pInt(u.settingsGet("AutoLogout"))),this.messagesPerPage(u.settingsGet("MPP")),this.showImages(!!u.settingsGet("ShowImages")),this.useCheckboxesInList(!!u.settingsGet("UseCheckboxesInList")),this.useThreads(!!u.settingsGet("UseThreads")),this.replySameFolder(!!u.settingsGet("ReplySameFolder"));var e=this;c.sub("rl.auto-logout-refresh",function(){o.clearTimeout(e.iAutoLogoutTimer),0r[e.email][1])&&(n=r[e.email][0],o=r[e.email][1])};if(s.each(i,function(e,t){r[e.email()]=[e,t]}),t)switch(e){case c.ComposeType.Empty:break;case c.ComposeType.Reply:case c.ComposeType.ReplyAll:case c.ComposeType.Forward:case c.ComposeType.ForwardAsAttachment:s.each(s.union(t.to,t.cc,t.bcc),a),n||s.each(t.deliveredTo,a);break;case c.ComposeType.Draft:s.each(s.union(t.from,t.replyTo),a)}return n||i[0]||null},t.prototype.selectIdentity=function(e){e&&e.item&&(this.currentIdentity(e.item),this.setSignatureFromIdentity(e.item))},t.prototype.sendMessageResponse=function(e,t){var i=!1,o="";this.sending(!1),c.StorageResultType.Success===e&&t&&t.Result&&(i=!0,this.modalVisibility()&&d.delegateRun(this,"closeCommand")),this.modalVisibility()&&!i&&(t&&c.Notification.CantSaveMessage===t.ErrorCode?(this.sendSuccessButSaveError(!0),this.savedErrorDesc(d.trim(g.i18n("COMPOSE/SAVED_ERROR_ON_SEND")))):(o=g.getNotification(t&&t.ErrorCode?t.ErrorCode:c.Notification.CantSendMessage,t&&t.ErrorMessage?t.ErrorMessage:""),this.sendError(!0),this.sendErrorDesc(o||g.getNotification(c.Notification.CantSendMessage)))),this.reloadDraftFolder()},t.prototype.saveMessageResponse=function(e,t){var i=!1,s=null;this.saving(!1),c.StorageResultType.Success===e&&t&&t.Result&&t.Result.NewFolder&&t.Result.NewUid&&(i=!0,this.bFromDraft&&(s=E.message(),s&&this.draftFolder()===s.folderFullNameRaw&&this.draftUid()===s.uid&&E.message(null)),this.draftFolder(t.Result.NewFolder),this.draftUid(t.Result.NewUid),this.savedTime(o.Math.round((new o.Date).getTime()/1e3)),this.bFromDraft&&y.setFolderHash(this.draftFolder(),"")),i||(this.savedError(!0),this.savedErrorDesc(g.getNotification(c.Notification.CantSaveMessage))),this.reloadDraftFolder()},t.prototype.onHide=function(){this.autosaveStop(),this.bSkipNextHide||(S.composeInEdit(!1),this.reset()),this.bSkipNextHide=!1,this.to.focused(!1),P.routeOn()},t.prototype.editor=function(e){if(e){var t=this;!this.oEditor&&this.composeEditorArea()?t.oEditor=new m(t.composeEditorArea(),null,function(){e(t.oEditor),t.resizerTrigger()},function(e){t.isHtml(!!e)}):this.oEditor&&(e(this.oEditor),this.resizerTrigger())}},t.prototype.converSignature=function(e){var t=10,i=null,o=[],n=/{{MOMENT:([^}]+)}}/g,r="";if(e=e.replace(/[\r]/g,""),r=this.oLastMessage?this.emailArrayToStringLineHelper(this.oLastMessage.from,!0):"",""!==r&&(e=e.replace(/{{FROM-FULL}}/g,r),-1===r.indexOf(" ")&&0i;i++)s.push(e[i].toLine(!!t));return s.join(", ")},t.prototype.initOnShow=function(e,t,i,o,r,a,l){S.composeInEdit(!0);var u=this,p="",h="",f="",m="",y="",v=null,w="",T="",A=[],E={},F=null,N=C.email(),R=[],P=null,L=null,I=e||c.ComposeType.Empty;if(t=t||null,t&&d.isNormal(t)&&(L=d.isArray(t)&&1===t.length?t[0]:d.isArray(t)?null:t),this.oLastMessage=L,null!==N&&(E[N]=!0),this.reset(),F=this.findIdentityByMessage(I,L),F&&(E[F.email()]=!0),d.isNonEmptyArray(i)&&this.to(this.emailArrayToStringLineHelper(i)),d.isNonEmptyArray(o)&&this.cc(this.emailArrayToStringLineHelper(o)),d.isNonEmptyArray(r)&&this.bcc(this.emailArrayToStringLineHelper(r)),""!==I&&L){switch(m=b.format(L.dateTimeStampInUTC(),"FULL"),y=L.subject(),P=L.aDraftInfo,v=n(L.body).clone(),v&&(v.find("blockquote.rl-bq-switcher").removeClass("rl-bq-switcher hidden-bq"),v.find(".rlBlockquoteSwitcher").off(".rlBlockquoteSwitcher").remove(),v.find("[data-html-editor-font-wrapper]").removeAttr("data-html-editor-font-wrapper"),w=v.html()),I){case c.ComposeType.Empty:break;case c.ComposeType.Reply:this.to(this.emailArrayToStringLineHelper(L.replyEmails(E))),this.subject(d.replySubjectAdd("Re",y)),this.prepearMessageAttachments(L,I),this.aDraftInfo=["reply",L.uid,L.folderFullNameRaw],this.sInReplyTo=L.sMessageId,this.sReferences=d.trim(this.sInReplyTo+" "+L.sReferences);break;case c.ComposeType.ReplyAll:A=L.replyAllEmails(E),this.to(this.emailArrayToStringLineHelper(A[0])),this.cc(this.emailArrayToStringLineHelper(A[1])),this.subject(d.replySubjectAdd("Re",y)),this.prepearMessageAttachments(L,I),this.aDraftInfo=["reply",L.uid,L.folderFullNameRaw],this.sInReplyTo=L.sMessageId,this.sReferences=d.trim(this.sInReplyTo+" "+L.references());break;case c.ComposeType.Forward:this.subject(d.replySubjectAdd("Fwd",y)),this.prepearMessageAttachments(L,I),this.aDraftInfo=["forward",L.uid,L.folderFullNameRaw],this.sInReplyTo=L.sMessageId,this.sReferences=d.trim(this.sInReplyTo+" "+L.sReferences);break;case c.ComposeType.ForwardAsAttachment:this.subject(d.replySubjectAdd("Fwd",y)),this.prepearMessageAttachments(L,I),this.aDraftInfo=["forward",L.uid,L.folderFullNameRaw],this.sInReplyTo=L.sMessageId,this.sReferences=d.trim(this.sInReplyTo+" "+L.sReferences);break;case c.ComposeType.Draft:this.to(this.emailArrayToStringLineHelper(L.to)),this.cc(this.emailArrayToStringLineHelper(L.cc)),this.bcc(this.emailArrayToStringLineHelper(L.bcc)),this.replyTo(this.emailArrayToStringLineHelper(L.replyTo)),this.bFromDraft=!0,this.draftFolder(L.folderFullNameRaw),this.draftUid(L.uid),this.subject(y),this.prepearMessageAttachments(L,I),this.aDraftInfo=d.isNonEmptyArray(P)&&3===P.length?P:null,this.sInReplyTo=L.sInReplyTo,this.sReferences=L.sReferences;break;case c.ComposeType.EditAsNew:this.to(this.emailArrayToStringLineHelper(L.to)),this.cc(this.emailArrayToStringLineHelper(L.cc)),this.bcc(this.emailArrayToStringLineHelper(L.bcc)),this.replyTo(this.emailArrayToStringLineHelper(L.replyTo)),this.subject(y),this.prepearMessageAttachments(L,I),this.aDraftInfo=d.isNonEmptyArray(P)&&3===P.length?P:null,this.sInReplyTo=L.sInReplyTo,this.sReferences=L.sReferences}switch(I){case c.ComposeType.Reply:case c.ComposeType.ReplyAll:p=L.fromToLine(!1,!0),T=g.i18n("COMPOSE/REPLY_MESSAGE_TITLE",{DATETIME:m,EMAIL:p}),w=" "+T+":"+d.trim(w)+" ";break;case c.ComposeType.Forward:p=L.fromToLine(!1,!0),h=L.toToLine(!1,!0),f=L.ccToLine(!1,!0),w=" "+g.i18n("COMPOSE/FORWARD_MESSAGE_TOP_TITLE")+" "+g.i18n("COMPOSE/FORWARD_MESSAGE_TOP_FROM")+": "+p+" "+g.i18n("COMPOSE/FORWARD_MESSAGE_TOP_TO")+": "+h+(0 "+g.i18n("COMPOSE/FORWARD_MESSAGE_TOP_CC")+": "+f:"")+" "+g.i18n("COMPOSE/FORWARD_MESSAGE_TOP_SENT")+": "+d.encodeHtml(m)+" "+g.i18n("COMPOSE/FORWARD_MESSAGE_TOP_SUBJECT")+": "+d.encodeHtml(y)+" "+d.trim(w)+" ";break;case c.ComposeType.ForwardAsAttachment:w=""}this.editor(function(e){e.setHtml(w,!1),(c.EditorDefaultType.PlainForced===u.editorDefaultType()||!L.isHtml()&&c.EditorDefaultType.HtmlForced!==u.editorDefaultType())&&e.modeToggle(!1),F&&c.ComposeType.Draft!==I&&c.ComposeType.EditAsNew!==I&&u.setSignatureFromIdentity(F),u.setFocusInPopup()})}else c.ComposeType.Empty===I?(this.subject(d.isNormal(a)?""+a:""),w=d.isNormal(l)?""+l:"",this.editor(function(e){e.setHtml(w,!1),c.EditorDefaultType.Html!==u.editorDefaultType()&&c.EditorDefaultType.HtmlForced!==u.editorDefaultType()&&e.modeToggle(!1),F&&u.setSignatureFromIdentity(F),u.setFocusInPopup()})):d.isNonEmptyArray(t)?(s.each(t,function(e){u.addMessageAsAttachment(e)}),this.editor(function(e){e.setHtml("",!1),c.EditorDefaultType.Html!==u.editorDefaultType()&&c.EditorDefaultType.HtmlForced!==u.editorDefaultType()&&e.modeToggle(!1),F&&c.ComposeType.Draft!==I&&c.ComposeType.EditAsNew!==I&&u.setSignatureFromIdentity(F),u.setFocusInPopup()})):this.setFocusInPopup();R=this.getAttachmentsDownloadsForUpload(),d.isNonEmptyArray(R)&&_.messageUploadAttachments(this.onMessageUploadAttachments,R),F&&this.currentIdentity(F),this.resizerTrigger()},t.prototype.onMessageUploadAttachments=function(e,t){if(c.StorageResultType.Success===e&&t&&t.Result){var i=null,o="";if(!this.viewModelVisibility())for(o in t.Result)t.Result.hasOwnProperty(o)&&(i=this.getAttachmentById(t.Result[o]),i&&(i.tempName(o),i.waiting(!1).uploading(!1).complete(!0)))}else this.setMessageAttachmentFailedDownloadText()},t.prototype.setFocusInPopup=function(){if(!p.bMobileDevice){var e=this;s.delay(function(){""===e.to()?e.to.focused(!0):e.oEditor&&(e.to.focused()||e.oEditor.focus())},100)}},t.prototype.onShowWithDelay=function(){this.resizerTrigger()},t.prototype.tryToClosePopup=function(){var e=this,t=i(43);!P.isPopupVisible(t)&&this.modalVisibility()&&(this.bSkipNextHide||this.isEmptyForm()&&!this.draftUid()?d.delegateRun(e,"closeCommand"):P.showScreenPopup(t,[g.i18n("POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW"),function(){e.modalVisibility()&&d.delegateRun(e,"closeCommand")}]))},t.prototype.onBuild=function(){this.initUploader();var e=this,t=null;key("ctrl+q, command+q, ctrl+w, command+w",c.KeyState.Compose,function(){return!1}),key("`",c.KeyState.Compose,function(){return!e.oEditor||e.oEditor.hasFocus()||d.inFocus()?void 0:(e.identitiesDropdownTrigger(!0),!1)}),key("ctrl+`",c.KeyState.Compose,function(){return e.identitiesDropdownTrigger(!0),!1}),key("esc, ctrl+down, command+down",c.KeyState.Compose,function(){return e.skipCommand(),!1}),this.allowFolders&&key("ctrl+s, command+s",c.KeyState.Compose,function(){return e.saveCommand(),!1}),N.appSettingsGet("allowCtrlEnterOnCompose")&&key("ctrl+enter, command+enter",c.KeyState.Compose,function(){return e.sendCommand(),!1}),key("shift+esc",c.KeyState.Compose,function(){return e.modalVisibility()&&e.tryToClosePopup(),!1}),h.sub("window.resize.real",this.resizerTrigger),h.sub("window.resize.real",s.debounce(this.resizerTrigger,50)),this.dropboxEnabled()&&this.dropboxApiKey()&&!o.Dropbox&&(t=o.document.createElement("script"),t.type="text/javascript",t.src="https://www.dropbox.com/static/api/2/dropins.js",n(t).attr("id","dropboxjs").attr("data-app-key",e.dropboxApiKey()),o.document.body.appendChild(t)),this.driveEnabled()&&n.getScript("https://apis.google.com/js/api.js",function(){o.gapi&&e.driveVisible(!0)}),o.setInterval(function(){e.modalVisibility()&&e.oEditor&&e.oEditor.resize()},5e3)},t.prototype.driveCallback=function(e,t){if(t&&o.XMLHttpRequest&&o.google&&t[o.google.picker.Response.ACTION]===o.google.picker.Action.PICKED&&t[o.google.picker.Response.DOCUMENTS]&&t[o.google.picker.Response.DOCUMENTS][0]&&t[o.google.picker.Response.DOCUMENTS][0].id){var i=this,s=new o.XMLHttpRequest;s.open("GET","https://www.googleapis.com/drive/v2/files/"+t[o.google.picker.Response.DOCUMENTS][0].id),s.setRequestHeader("Authorization","Bearer "+e),s.addEventListener("load",function(){if(s&&s.responseText){var t=a.parse(s.responseText),o=function(e,t,i){e&&e.exportLinks&&(e.exportLinks[t]?(e.downloadUrl=e.exportLinks[t],e.title=e.title+"."+i,e.mimeType=t):e.exportLinks["application/pdf"]&&(e.downloadUrl=e.exportLinks["application/pdf"],e.title=e.title+".pdf",e.mimeType="application/pdf"))};if(t&&!t.downloadUrl&&t.mimeType&&t.exportLinks)switch(t.mimeType.toString().toLowerCase()){case"application/vnd.google-apps.document":o(t,"application/vnd.openxmlformats-officedocument.wordprocessingml.document","docx");break;case"application/vnd.google-apps.spreadsheet":o(t,"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","xlsx");break;case"application/vnd.google-apps.drawing":o(t,"image/png","png");break;case"application/vnd.google-apps.presentation":o(t,"application/vnd.openxmlformats-officedocument.presentationml.presentation","pptx");break;default:o(t,"application/pdf","pdf")}t&&t.downloadUrl&&i.addDriveAttachment(t,e)}}),s.send()}},t.prototype.driveCreatePiker=function(e){if(o.gapi&&e&&e.access_token){var t=this;o.gapi.load("picker",{callback:function(){if(o.google&&o.google.picker){var i=(new o.google.picker.PickerBuilder).addView(o.google.picker.ViewId.DOCS).setAppId(N.settingsGet("GoogleClientID")).setOAuthToken(e.access_token).setCallback(s.bind(t.driveCallback,t,e.access_token)).enableFeature(o.google.picker.Feature.NAV_HIDDEN).build();i.setVisible(!0)}}})}},t.prototype.driveOpenPopup=function(){if(o.gapi){var e=this;o.gapi.load("auth",{callback:function(){var t=o.gapi.auth.getToken(),i=function(t){if(t&&!t.error){var i=o.gapi.auth.getToken();return i&&e.driveCreatePiker(i),!0}return!1};t?e.driveCreatePiker(t):o.gapi.auth.authorize({client_id:N.settingsGet("GoogleClientID"),scope:"https://www.googleapis.com/auth/drive.readonly",immediate:!0},function(e){i(e)||o.gapi.auth.authorize({client_id:N.settingsGet("GoogleClientID"),scope:"https://www.googleapis.com/auth/drive.readonly",immediate:!1},i)})}})}},t.prototype.getAttachmentById=function(e){for(var t=this.attachments(),i=0,o=t.length;o>i;i++)if(t[i]&&e===t[i].id)return t[i];return null},t.prototype.cancelAttachmentHelper=function(e,t){var i=this;return function(){var o=s.find(i.attachments(),function(t){return t&&t.id===e});o&&(i.attachments.remove(o),d.delegateRunOnDestroy(o),t&&t.cancel(e))}},t.prototype.initUploader=function(){if(this.composeUploaderButton()){var e={},t=d.pInt(N.settingsGet("AttachmentLimit")),i=new l({action:f.upload(),name:"uploader",queueSize:2,multipleSizeLimit:50,clickElement:this.composeUploaderButton(),dragAndDropElement:this.composeUploaderDropPlace()});i?(i.on("onDragEnter",s.bind(function(){this.dragAndDropOver(!0)},this)).on("onDragLeave",s.bind(function(){this.dragAndDropOver(!1)},this)).on("onBodyDragEnter",s.bind(function(){this.attachmentsPlace(!0),this.dragAndDropVisible(!0)},this)).on("onBodyDragLeave",s.bind(function(){this.dragAndDropVisible(!1)},this)).on("onProgress",s.bind(function(t,i,s){var n=null;d.isUnd(e[t])?(n=this.getAttachmentById(t),n&&(e[t]=n)):n=e[t],n&&n.progress(o.Math.floor(i/s*100))},this)).on("onSelect",s.bind(function(e,o){this.dragAndDropOver(!1);var s=this,n=d.isUnd(o.FileName)?"":o.FileName.toString(),r=d.isNormal(o.Size)?d.pInt(o.Size):null,a=new R(e,n,r);return a.cancel=s.cancelAttachmentHelper(e,i),this.attachments.push(a),this.attachmentsPlace(!0),r>0&&t>0&&r>t?(a.waiting(!1).uploading(!0).complete(!0).error(g.i18n("UPLOAD/ERROR_FILE_IS_TOO_BIG")),!1):!0},this)).on("onStart",s.bind(function(t){var i=null;d.isUnd(e[t])?(i=this.getAttachmentById(t),i&&(e[t]=i)):i=e[t],i&&i.waiting(!1).uploading(!0).complete(!1)},this)).on("onComplete",s.bind(function(t,i,o){var s="",n=null,r=null,a=this.getAttachmentById(t);r=i&&o&&o.Result&&o.Result.Attachment?o.Result.Attachment:null,n=o&&o.Result&&o.Result.ErrorCode?o.Result.ErrorCode:null,null!==n?s=g.getUploadErrorDescByCode(n):r||(s=g.i18n("UPLOAD/ERROR_UNKNOWN")),a&&(""!==s&&00&&i>0&&o>i?(t.uploading(!1).complete(!0),t.error(g.i18n("UPLOAD/ERROR_FILE_IS_TOO_BIG")),!1):(_.composeUploadExternals(function(e,i){var o=!1;t.uploading(!1).complete(!0),c.StorageResultType.Success===e&&i&&i.Result&&i.Result[t.id]&&(o=!0,t.tempName(i.Result[t.id])),o||t.error(g.getUploadErrorDescByCode(c.UploadErrorCode.FileNoUploaded))},[e.link]),!0)},t.prototype.addDriveAttachment=function(e,t){var i=d.pInt(N.settingsGet("AttachmentLimit")),o=null,s=e.fileSize?d.pInt(e.fileSize):0;return o=new R(e.downloadUrl,e.title,s),o.fromMessage=!1,o.cancel=this.cancelAttachmentHelper(e.downloadUrl),o.waiting(!1).uploading(!0).complete(!1),this.attachments.push(o),this.attachmentsPlace(!0),s>0&&i>0&&s>i?(o.uploading(!1).complete(!0),o.error(g.i18n("UPLOAD/ERROR_FILE_IS_TOO_BIG")),!1):(_.composeUploadDrive(function(e,t){var i=!1;o.uploading(!1).complete(!0),c.StorageResultType.Success===e&&t&&t.Result&&t.Result[o.id]&&(i=!0,o.tempName(t.Result[o.id][0]),o.size(d.pInt(t.Result[o.id][1]))),i||o.error(g.getUploadErrorDescByCode(c.UploadErrorCode.FileNoUploaded))},e.downloadUrl,t),!0)},t.prototype.prepearMessageAttachments=function(e,t){if(e){var i=d.isNonEmptyArray(e.attachments())?e.attachments():[],o=0,s=i.length,n=null,r=null,a=!1;if(c.ComposeType.ForwardAsAttachment===t)this.addMessageAsAttachment(e);else for(;s>o;o++){switch(r=i[o],a=!1,t){case c.ComposeType.Reply:case c.ComposeType.ReplyAll:a=r.isLinked;break;case c.ComposeType.Forward:case c.ComposeType.Draft:case c.ComposeType.EditAsNew:a=!0}a&&(n=new R(r.download,r.fileName,r.estimatedSize,r.isInline,r.isLinked,r.cid,r.contentLocation),n.fromMessage=!0,n.cancel=this.cancelAttachmentHelper(r.download),n.waiting(!1).uploading(!0).complete(!1),this.attachments.push(n))}}},t.prototype.removeLinkedAttachments=function(){var e=s.find(this.attachments(),function(e){return e&&e.isLinked});e&&(this.attachments.remove(e),d.delegateRunOnDestroy(e))},t.prototype.setMessageAttachmentFailedDownloadText=function(){s.each(this.attachments(),function(e){e&&e.fromMessage&&e.waiting(!1).uploading(!1).complete(!0).error(g.getUploadErrorDescByCode(c.UploadErrorCode.FileNoUploaded))},this)},t.prototype.isEmptyForm=function(e){e=d.isUnd(e)?!0:!!e;var t=e?0===this.attachments().length:0===this.attachmentsInReady().length;return 0===this.to().length&&0===this.cc().length&&0===this.bcc().length&&0===this.replyTo().length&&0===this.subject().length&&t&&(!this.oEditor||""===this.oEditor.getData())},t.prototype.reset=function(){this.to(""),this.cc(""),this.bcc(""),this.replyTo(""),this.subject(""),this.requestDsn(!1),this.requestReadReceipt(!1),this.markAsImportant(!1),this.attachmentsPlace(!1),this.aDraftInfo=null,this.sInReplyTo="",this.bFromDraft=!1,this.sReferences="",this.sendError(!1),this.sendSuccessButSaveError(!1),this.savedError(!1),this.savedTime(0),this.emptyToError(!1),this.attachmentsInProcessError(!1),this.showCc(!1),this.showBcc(!1),this.showReplyTo(!1),d.delegateRunOnDestroy(this.attachments()),this.attachments([]),this.dragAndDropOver(!1),this.dragAndDropVisible(!1),this.draftFolder(""),this.draftUid(""),this.sending(!1),this.saving(!1),this.oEditor&&this.oEditor.clear(!1)},t.prototype.getAttachmentsDownloadsForUpload=function(){return s.map(s.filter(this.attachments(),function(e){return e&&""===e.tempName()}),function(e){return e.id})},t.prototype.resizerTrigger=function(){this.resizer(!this.resizer())},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(e,t,i,o){this.email=e||"",this.name=t||"",this.dkimStatus=i||"none",this.dkimValue=o||"",this.clearDuplicateName()}var o=i(1);t.newInstanceFromJson=function(e){var i=new t;return i.initByJson(e)?i:null},t.splitHelper=function(e,t){t=t||";",e=e.replace(/[\r\n]+/g,"; ").replace(/[\s]+/g," ");for(var i=0,o=e.length,s=!1,n="",r="";o>i;i++){switch(n=e.charAt(i)){case"@":s=!0;break;case" ":s&&(s=!1,r+=t)}r+=n}return r.split(t)},t.prototype.name="",t.prototype.email="",t.prototype.dkimStatus="none",t.prototype.dkimValue="",t.prototype.clear=function(){this.email="",this.name="",this.dkimStatus="none",this.dkimValue=""},t.prototype.validate=function(){return""!==this.name||""!==this.email},t.prototype.hash=function(e){return"#"+(e?"":this.name)+"#"+this.email+"#"},t.prototype.clearDuplicateName=function(){this.name===this.email&&(this.name="")},t.prototype.search=function(e){return-1<(this.name+" "+this.email).toLowerCase().indexOf(e.toLowerCase())},t.prototype.parse=function(e){this.clear(),e=o.trim(e);var t=/(?:"([^"]+)")? ?[<]?(.*?@[^>,]+)>?,? ?/g,i=t.exec(e);i?(this.name=i[1]||"",this.email=i[2]||"",this.clearDuplicateName()):/^[^@]+@[^@]+$/.test(e)&&(this.name="",this.email=e)},t.prototype.initByJson=function(e){var t=!1;return e&&"Object/Email"===e["@Object"]&&(this.name=o.trim(e.Name),this.email=o.trim(e.Email),this.dkimStatus=o.trim(e.DkimStatus||""),this.dkimValue=o.trim(e.DkimValue||""),t=""!==this.email,this.clearDuplicateName()),t},t.prototype.toLine=function(e,t,i){var s="";return""!==this.email&&(t=o.isUnd(t)?!1:!!t,i=o.isUnd(i)?!1:!!i,e&&""!==this.name?s=t?'")+'" target="_blank" tabindex="-1">'+o.encodeHtml(this.name)+" ":i?o.encodeHtml(this.name):this.name:(s=this.email,""!==this.name?t?s=o.encodeHtml('"'+this.name+'" <')+'")+'" target="_blank" tabindex="-1">'+o.encodeHtml(s)+" "+o.encodeHtml(">"):(s='"'+this.name+'" <'+s+">",i&&(s=o.encodeHtml(s))):t&&(s=''+o.encodeHtml(this.email)+" "))),s},t.prototype.mailsoParse=function(e){if(e=o.trim(e),""===e)return!1;for(var t=function(e,t,i){e+="";var o=e.length;return 0>t&&(t+=o),o="undefined"==typeof i?o:0>i?i+o:i+t,t>=e.length||0>t||t>o?!1:e.slice(t,o)},i=function(e,t,i,o){return 0>i&&(i+=e.length),o=void 0!==o?o:e.length,0>o&&(o=o+e.length-i),e.slice(0,i)+t.substr(0,o)+t.slice(o)+e.slice(i+o)},s="",n="",r="",a=!1,l=!1,c=!1,u=null,d=0,p=0,h=0;h0&&0===s.length&&(s=t(e,0,h)),l=!0,d=h);break;case">":l&&(p=h,n=t(e,d+1,p-d-1),e=i(e,"",d,p-d+1),p=0,h=0,d=0,l=!1);break;case"(":a||l||c||(c=!0,d=h);break;case")":c&&(p=h,r=t(e,d+1,p-d-1),e=i(e,"",d,p-d+1),p=0,h=0,d=0,c=!1);break;case"\\":h++}h++}return 0===n.length&&(u=e.match(/[^@\s]+@\S+/i),u&&u[0]?n=u[0]:s=e),n.length>0&&0===s.length&&0===r.length&&(s=e.replace(n,"")),n=o.trim(n).replace(/^[<]+/,"").replace(/[>]+$/,""),s=o.trim(s).replace(/^["']+/,"").replace(/["']+$/,""),r=o.trim(r).replace(/^[(]+/,"").replace(/[)]+$/,""),s=s.replace(/\\\\(.)/g,"$1"),r=r.replace(/\\\\(.)/g,"$1"),this.name=s,this.email=n,this.clearDuplicateName(),!0},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){this.email=s.observable(""),this.parentEmail=s.observable(""),this.signature=s.observable(""),this.accounts=s.observableArray([]),this.accounts.loading=s.observable(!1).extend({throttle:100}),this.computers()}var o=i(3),s=i(2),n=i(9);t.prototype.computers=function(){this.accountsEmails=s.computed(function(){return o.compact(o.map(this.accounts(),function(e){return e?e.email:null}))},this),this.accountsUnreadCount=s.computed(function(){var e=0;return e},this)},t.prototype.populate=function(){this.email(n.settingsGet("Email")),this.parentEmail(n.settingsGet("ParentEmail"))},t.prototype.isRootAccount=function(){return""===this.parentEmail()},e.exports=new t}()},function(e,t,i){!function(){"use strict";function t(){this.staticMessage=new v,this.messageList=s.observableArray([]).extend({rateLimit:0}),this.messageListCount=s.observable(0),this.messageListSearch=s.observable(""),this.messageListThreadUid=s.observable(""),this.messageListPage=s.observable(1),this.messageListPageBeforeThread=s.observable(1),this.messageListError=s.observable(""),this.messageListEndFolder=s.observable(""),this.messageListEndSearch=s.observable(""),this.messageListEndThreadUid=s.observable(""),this.messageListEndPage=s.observable(1),this.messageListLoading=s.observable(!1),this.messageListIsNotCompleted=s.observable(!1),this.messageListCompleteLoadingThrottle=s.observable(!1).extend({throttle:200}),this.messageListCompleteLoadingThrottleForAnimation=s.observable(!1).extend({specialThrottle:700}),this.messageListDisableAutoSelect=s.observable(!1).extend({falseTimeout:500}),this.selectorMessageSelected=s.observable(null),this.selectorMessageFocused=s.observable(null),this.message=s.observable(null),this.message.viewTrigger=s.observable(!1),this.messageError=s.observable(""),this.messageCurrentLoading=s.observable(!1),this.messageLoading=s.computed(function(){return this.messageCurrentLoading()},this),this.messageLoadingThrottle=s.observable(!1).extend({throttle:50}),this.messageFullScreenMode=s.observable(!1),this.messagesBodiesDom=s.observable(null),this.messageActiveDom=s.observable(null),this.computers(),this.subscribers(),this.onMessageResponse=o.bind(this.onMessageResponse,this),this.purgeMessageBodyCacheThrottle=o.throttle(this.purgeMessageBodyCache,3e4)}var o=i(3),s=i(2),n=i(11),r=i(14),a=i(5),l=i(4),c=i(17),u=i(8),d=i(1),p=i(12),h=i(6),f=i(19),m=i(24),g=i(21),b=i(33),y=i(28),S=i(15),v=i(108),w=i(85);t.prototype.computers=function(){var e=this;this.messageListEndHash=s.computed(function(){return this.messageListEndFolder()+"|"+this.messageListEndSearch()+"|"+this.messageListEndThreadUid()+"|"+this.messageListEndPage()},this),this.messageListPageCount=s.computed(function(){var e=n.Math.ceil(this.messageListCount()/y.messagesPerPage());return 0>=e?1:e},this),this.mainMessageListSearch=s.computed({read:this.messageListSearch,write:function(t){a.setHash(p.mailBox(g.currentFolderFullNameHash(),1,d.trim(t.toString()),e.messageListThreadUid()))},owner:this}),this.messageListCompleteLoading=s.computed(function(){var e=this.messageListLoading(),t=this.messageListIsNotCompleted();return e||t},this),this.isMessageSelected=s.computed(function(){return null!==this.message()},this),this.messageListChecked=s.computed(function(){return o.filter(this.messageList(),function(e){return e.checked()})},this).extend({rateLimit:0}),this.hasCheckedMessages=s.computed(function(){return 00&&(t=this.messagesBodiesDom(),t&&(t.find(".rl-cache-class").each(function(){var t=r(this);i>t.data("rl-cache-count")&&(t.addClass("rl-cache-purge"),e++)}),e>0&&o.delay(function(){t.find(".rl-cache-purge").remove()},300)))},t.prototype.initUidNextAndNewMessages=function(e,t,s){if(f.getFolderInboxName()===e&&d.isNormal(t)&&""!==t){
+if(d.isArray(s)&&03)a.displayDesktopNotification(p.notificationMailIcon(),i(31).email(),h.i18n("MESSAGE_LIST/NEW_MESSAGE_NOTIFICATION",{COUNT:r}),{Folder:"",Uid:""});else for(;r>n;n++)a.displayDesktopNotification(p.notificationMailIcon(),w.emailArrayToString(w.emailArrayFromJson(s[n].From),!1),s[n].Subject,{Folder:s[n].Folder,Uid:s[n].Uid})}f.setFolderUidNext(e,t)}},t.prototype.hideMessageBodies=function(){var e=this.messagesBodiesDom();e&&e.find(".b-text-part").hide()},t.prototype.removeMessagesFromList=function(e,t,i,s){i=d.isNormal(i)?i:"",s=d.isUnd(s)?!1:!!s,t=o.map(t,function(e){return d.pInt(e)});var n=this,r=0,l=null,c=g.trashFolder(),u=g.spamFolder(),h=this.messageList(),m=f.getFolderFromCacheList(e),b=""===i?null:f.getFolderFromCacheList(i||""),y=g.currentFolderFullNameRaw(),S=this.message(),v=y===e?o.filter(h,function(e){return e&&-10&&m.messageCountUnread(0<=m.messageCountUnread()-r?m.messageCountUnread()-r:0)),b&&(c!==b.fullNameRaw&&u!==b.fullNameRaw||(r=0),b.messageCountAll(b.messageCountAll()+t.length),r>0&&b.messageCountUnread(b.messageCountUnread()+r),b.actionBlink(!0)),0 ').insertBefore(e).on("click.rlBlockquoteSwitcher",function(){e.toggleClass("hidden-bq"),d.windowResize()}).after(" ").before(" "))},t.prototype.initBlockquoteSwitcher=function(e){if(e){var t=r("blockquote:not(.rl-bq-switcher)",e).filter(function(){return 0===r(this).parent().closest("blockquote",e).length});t&&0').text(g)).html():w&&A.isPgpEncrypted()?u.$div.append(r(' ').text(g)).html():""+b+" ",g="",u.$div.empty(),A.isPgpSigned(S),A.isPgpEncrypted(w)):b=""+b+" "):(n=!1,b=""+b+" "),p=r('
').hide().addClass("rl-cache-class"),p.data("rl-cache-count",++u.iMessageBodyCacheCount),p.html(d.findEmailAndLinks(b)).addClass("b-text-part "+(n?"html":"plain")),A.isHtml(!!n),A.hasImages(!!a),A.body=p,A.body&&C.append(A.body),A.storeDataInDom(),c&&A.showInternalImages(!0),A.hasImages()&&y.showImages()&&A.showExternalImages(!0),this.purgeMessageBodyCacheThrottle()),this.messageActiveDom(A.body),this.hideMessageBodies(),p&&(this.initOpenPgpControls(p,A),this.initBlockquoteSwitcher(p)),A.body.show()),f.initMessageFlagsFromCache(A),(A.unseen()||A.hasUnseenSubMessage())&&i(7)["default"].messageListAction(A.folderFullNameRaw,A.uid,l.MessageSetAction.SetSeen,[A]),s&&(A=this.message(),T&&A&&(A.folderFullNameRaw!==T.folderFullNameRaw||A.uid!==T.uid)?(this.selectorMessageSelected(null),1===this.messageList().length&&this.selectorMessageFocused(null)):!T&&A&&(T=o.find(this.messageList(),function(e){return e&&e.folderFullNameRaw===A.folderFullNameRaw&&e.uid===A.uid}),T&&(this.selectorMessageSelected(T),this.selectorMessageFocused(T)))),d.windowResize()))},t.prototype.selectMessage=function(e){e?(this.message(this.staticMessage.populateByMessageListItem(e)),this.populateMessageBody(this.message())):this.message(null)},t.prototype.selectMessageByFolderAndUid=function(e,t){e&&t?(this.message(this.staticMessage.populateByMessageListItem(null)),this.message().folderFullNameRaw=e,this.message().uid=t,this.populateMessageBody(this.message())):this.message(null)},t.prototype.populateMessageBody=function(e){e&&S.message(this.onMessageResponse,e.folderFullNameRaw,e.uid)&&this.messageCurrentLoading(!0)},t.prototype.onMessageResponse=function(e,t,i){this.hideMessageBodies(),this.messageCurrentLoading(!1),l.StorageResultType.Success===e&&t&&t.Result?this.setMessage(t,i):l.StorageResultType.Unload===e?(this.message(null),this.messageError("")):l.StorageResultType.Abort!==e&&(this.message(null),this.messageError(t&&t.ErrorCode?h.getNotification(t.ErrorCode):h.getNotification(l.Notification.UnknownError)))},t.prototype.calculateMessageListHash=function(e){return o.map(e,function(e){return""+e.hash+"_"+e.threadsLen()+"_"+e.flagHash()}).join("|")},t.prototype.setMessageList=function(e,t){if(e&&e.Result&&"Collection/MessageCollection"===e.Result["@Object"]&&e.Result["@Collection"]&&d.isArray(e.Result["@Collection"])){var o=0,s=0,r=0,a=0,c=[],u=null,p=null,m=null,g=0,b=i(26).momentNowUnix(),S=!1;for(r=d.pInt(e.Result.MessageResultCount),a=d.pInt(e.Result.Offset),m=f.getFolderFromCacheList(d.isNormal(e.Result.Folder)?e.Result.Folder:""),m&&!t&&(m.interval=b,f.setFolderHash(e.Result.Folder,e.Result.FolderHash),d.isNormal(e.Result.MessageCount)&&m.messageCountAll(e.Result.MessageCount),d.isNormal(e.Result.MessageUnseenCount)&&(d.pInt(m.messageCountUnread())!==d.pInt(e.Result.MessageUnseenCount)&&(S=!0),m.messageCountUnread(e.Result.MessageUnseenCount)),this.initUidNextAndNewMessages(m.fullNameRaw,e.Result.UidNext,e.Result.NewMessages)),S&&m&&f.clearMessageFlagsFromCacheByFolder(m.fullNameRaw),o=0,s=e.Result["@Collection"].length;s>o;o++)u=e.Result["@Collection"][o],u&&"Object/Message"===u["@Object"]&&(p=v.newInstanceFromJson(u),p&&(f.hasNewMessageAndRemoveFromCache(p.folderFullNameRaw,p.uid)&&5>=g&&(g++,p.newForAnimation(!0)),p.deleted(!1),t?f.initMessageFlagsFromCache(p):f.storeMessageFlagsToCache(p),c.push(p)));this.messageListCount(r),this.messageListSearch(d.isNormal(e.Result.Search)?e.Result.Search:""),this.messageListPage(n.Math.ceil(a/y.messagesPerPage()+1)),this.messageListThreadUid(d.isNormal(e.Result.ThreadUid)?d.pString(e.Result.ThreadUid):""),this.messageListEndFolder(d.isNormal(e.Result.Folder)?e.Result.Folder:""),this.messageListEndSearch(this.messageListSearch()),this.messageListEndThreadUid(this.messageListThreadUid()),this.messageListEndPage(this.messageListPage()),this.messageListDisableAutoSelect(!0),this.messageList(c),this.messageListIsNotCompleted(!1),f.clearNewMessageCache(),m&&(t||S||y.useThreads())&&i(7)["default"].folderInformation(m.fullNameRaw,c)}else this.messageListCount(0),this.messageList([]),this.messageListError(h.getNotification(e&&e.ErrorCode?e.ErrorCode:l.Notification.CantGetMessageList))},e.exports=new t}()},function(e,t,i){!function(){"use strict";function t(){this.capaOpenPGP=s.observable(!1),this.openpgp=null,this.openpgpkeys=s.observableArray([]),this.openpgpKeyring=null,this.openpgpkeysPublic=this.openpgpkeys.filter(function(e){return!(!e||e.isPrivate)}),this.openpgpkeysPrivate=this.openpgpkeys.filter(function(e){return!(!e||!e.isPrivate)})}var o=i(3),s=i(2),n=i(14),r=i(5),a=i(6),l=i(1);t.prototype.isSupported=function(){return!!this.openpgp},t.prototype.findKeyByHex=function(e,t){return o.find(e,function(e){return t&&e&&(t===e.id||-1 ').attr("title",a.i18n("MESSAGE/PGP_ENCRYPTED_MESSAGE_DESC")).on("click",t.domControlEncryptedClickHelper(this,e,c,l)):s&&(r=n('
').attr("title",a.i18n("MESSAGE/PGP_SIGNED_MESSAGE_DESC")).on("click",t.domControlSignedClickHelper(this,e,c))),r&&e.before(r).before("
"))}},e.exports=new t}()},function(e,t,i){!function(){"use strict";function t(){this.google={},this.twitter={},this.facebook={},this.dropbox={},this.google.enabled=o.observable(!1),this.google.clientID=o.observable(""),this.google.clientSecret=o.observable(""),this.google.apiKey=o.observable(""),this.google.loading=o.observable(!1),this.google.userName=o.observable(""),this.google.loggined=o.computed(function(){return""!==this.google.userName()},this),this.google.capa={},this.google.capa.auth=o.observable(!1),this.google.capa.authFast=o.observable(!1),this.google.capa.drive=o.observable(!1),this.google.capa.preview=o.observable(!1),this.google.require={},this.google.require.clientSettings=o.computed(function(){return this.google.enabled()&&(this.google.capa.auth()||this.google.capa.drive())},this),this.google.require.apiKeySettings=o.computed(function(){return this.google.enabled()&&this.google.capa.drive()},this),this.facebook.enabled=o.observable(!1),this.facebook.appID=o.observable(""),this.facebook.appSecret=o.observable(""),this.facebook.loading=o.observable(!1),this.facebook.userName=o.observable(""),this.facebook.supported=o.observable(!1),this.facebook.loggined=o.computed(function(){return""!==this.facebook.userName()},this),this.twitter.enabled=o.observable(!1),this.twitter.consumerKey=o.observable(""),this.twitter.consumerSecret=o.observable(""),this.twitter.loading=o.observable(!1),this.twitter.userName=o.observable(""),this.twitter.loggined=o.computed(function(){return""!==this.twitter.userName()},this),this.dropbox.enabled=o.observable(!1),this.dropbox.apiKey=o.observable("")}var o=i(2);t.prototype.google={},t.prototype.twitter={},t.prototype.facebook={},t.prototype.dropbox={},t.prototype.populate=function(){var e=i(9);this.google.enabled(!!e.settingsGet("AllowGoogleSocial")),this.google.clientID(e.settingsGet("GoogleClientID")),this.google.clientSecret(e.settingsGet("GoogleClientSecret")),this.google.apiKey(e.settingsGet("GoogleApiKey")),this.google.capa.auth(!!e.settingsGet("AllowGoogleSocialAuth")),this.google.capa.authFast(!!e.settingsGet("AllowGoogleSocialAuthFast")),this.google.capa.drive(!!e.settingsGet("AllowGoogleSocialDrive")),this.google.capa.preview(!!e.settingsGet("AllowGoogleSocialPreview")),this.facebook.enabled(!!e.settingsGet("AllowFacebookSocial")),this.facebook.appID(e.settingsGet("FacebookAppID")),this.facebook.appSecret(e.settingsGet("FacebookAppSecret")),this.facebook.supported(!!e.settingsGet("SupportedFacebookSocial")),this.twitter.enabled=o.observable(!!e.settingsGet("AllowTwitterSocial")),this.twitter.consumerKey=o.observable(e.settingsGet("TwitterConsumerKey")),this.twitter.consumerSecret=o.observable(e.settingsGet("TwitterConsumerSecret")),this.dropbox.enabled(!!e.settingsGet("AllowDropboxSocial")),this.dropbox.apiKey(e.settingsGet("DropboxApiKey"))},e.exports=new t}()},,function(e,t){e.exports=window.JSON},function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function n(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function r(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0,t["default"]=t.AbstractInput=void 0;var a=i(2),l=o(a),c=i(1),u=o(c),d=i(4),p=i(16),h=function(e){function t(i){s(this,t);var o=n(this,e.call(this));return o.value=i.value||"",o.size=i.size||0,o.label=i.label||"",o.preLabel=i.preLabel||"",o.enable=u["default"].isUnd(i.enable)?!0:i.enable,o.trigger=i.trigger&&i.trigger.subscribe?i.trigger:null,o.placeholder=i.placeholder||"",o.labeled=!u["default"].isUnd(i.label),o.preLabeled=!u["default"].isUnd(i.preLabel),o.triggered=!u["default"].isUnd(i.trigger)&&!!o.trigger,o.classForTrigger=l["default"].observable(""),o.className=l["default"].computed(function(){var e=l["default"].unwrap(o.size),t=o.trigger?" "+u["default"].trim("settings-saved-trigger-input "+o.classForTrigger()):"";return(e>0?"span"+e:"")+t},o),!u["default"].isUnd(i.width)&&i.element&&i.element.find("input,select,textarea").css("width",i.width),o.disposable.push(o.className),o.trigger&&(o.setTriggerState(o.trigger()),o.disposable.push(o.trigger.subscribe(o.setTriggerState,o))),o}return r(t,e),t.prototype.setTriggerState=function(e){switch(u["default"].pInt(e)){case d.SaveSettingsStep.TrueResult:this.classForTrigger("success");break;case d.SaveSettingsStep.FalseResult:this.classForTrigger("error");break;default:this.classForTrigger("")}},t}(p.AbstractComponent);t.AbstractInput=h,t["default"]=h},function(e,t,i){"use strict";function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function s(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function n(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var r=i(16),a=i(46),l=function(e){function t(){return o(this,t),s(this,e.apply(this,arguments))}return n(t,e),t}(a.AbstracCheckbox);e.exports=(0,r.componentExportHelper)(l,"CheckboxComponent")},function(e,t,i){!function(){"use strict";function t(e,t){this.sScreenName=e,this.aViewModels=n.isArray(t)?t:[]}var o=i(3),s=i(49),n=i(1);t.prototype.oCross=null,t.prototype.sScreenName="",t.prototype.aViewModels=[],t.prototype.viewModels=function(){return this.aViewModels},t.prototype.screenName=function(){return this.sScreenName},t.prototype.routes=function(){return null},t.prototype.__cross=function(){return this.oCross},t.prototype.__start=function(){var e=this.routes(),t=null,i=null;n.isNonEmptyArray(e)&&(i=o.bind(this.onRoute||n.emptyFunction,this),t=s.create(),o.each(e,function(e){t.addRoute(e[0],i).rules=e[1]}),this.oCross=t)},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){this.languages=o.observableArray([]),this.languagesAdmin=o.observableArray([]),this.language=o.observable("").extend({limitedList:this.languages}),this.languageAdmin=o.observable("").extend({limitedList:this.languagesAdmin}),this.userLanguage=o.observable(""),this.userLanguageAdmin=o.observable("")}var o=i(2),s=i(1),n=i(9);t.prototype.populate=function(){var e=n.appSettingsGet("languages"),t=n.appSettingsGet("languagesAdmin");this.languages(s.isArray(e)?e:[]),this.languagesAdmin(s.isArray(t)?t:[]),this.language(n.settingsGet("Language")),this.languageAdmin(n.settingsGet("LanguageAdmin")),this.userLanguage(n.settingsGet("UserLanguage")),this.userLanguageAdmin(n.settingsGet("UserLanguageAdmin"))},e.exports=new t}()},function(e,t,i){!function(){"use strict";function t(){r.call(this)}var o=i(11),s=i(3),n=i(112),r=i(111);s.extend(t.prototype,r.prototype),t.prototype.foldersReload=function(e){return this.abort("Folders").postRequest("Folders",e).then(function(e){return n.foldersList(e.Result),n.foldersAdditionalParameters(e.Result),!0})},t.prototype._folders_timeout_=0,t.prototype.foldersReloadWithTimeout=function(e){this.setTrigger(e,!0);var t=this;o.clearTimeout(this._folders_timeout_),this._folders_timeout_=o.setTimeout(function(){t.foldersReload(e)},500)},t.prototype.folderDelete=function(e,t){return this.postRequest("FolderDelete",t,{Folder:e})},t.prototype.folderCreate=function(e,t,i){return this.postRequest("FolderCreate",i,{Folder:e,Parent:t})},t.prototype.folderRename=function(e,t,i){return this.postRequest("FolderRename",i,{Folder:e,NewFolderName:t})},t.prototype.attachmentsActions=function(e,t,i){return this.postRequest("AttachmentsActions",i,{Do:e,Hashes:t})},t.prototype.welcomeClose=function(){return this.postRequest("WelcomeClose")},e.exports=new t}()},function(e,t,i){!function(){"use strict";function t(){this.themes=o.observableArray([]),this.themeBackgroundName=o.observable(""),this.themeBackgroundHash=o.observable(""),this.theme=o.observable("").extend({limitedList:this.themes})}var o=i(2),s=i(1),n=i(9);t.prototype.populate=function(){var e=n.appSettingsGet("themes");this.themes(s.isArray(e)?e:[]),this.theme(n.settingsGet("Theme")),this.themeBackgroundName(n.settingsGet("UserBackgroundName")),this.themeBackgroundHash(n.settingsGet("UserBackgroundHash"))},e.exports=new t}()},function(e,t,i){!function(){"use strict";function t(){u.call(this,"Popups","PopupsAsk"),this.askDesc=s.observable(""),this.yesButton=s.observable(""),this.noButton=s.observable(""),this.yesFocus=s.observable(!1),this.noFocus=s.observable(!1),this.fYesAction=null,this.fNoAction=null,this.bFocusYesOnShow=!0,this.bDisabeCloseOnEsc=!0,this.sDefaultKeyScope=r.KeyState.PopupAsk,c.constructorEnd(this)}var o=i(3),s=i(2),n=i(18),r=i(4),a=i(1),l=i(6),c=i(5),u=i(10);c.extendAsViewModel(["View/Popup/Ask","PopupsAskViewModel"],t),o.extend(t.prototype,u.prototype),t.prototype.clearPopup=function(){this.askDesc(""),this.yesButton(l.i18n("POPUPS_ASK/BUTTON_YES")),this.noButton(l.i18n("POPUPS_ASK/BUTTON_NO")),this.yesFocus(!1),this.noFocus(!1),this.fYesAction=null,this.fNoAction=null},t.prototype.yesClick=function(){this.cancelCommand(),a.isFunc(this.fYesAction)&&this.fYesAction.call(null)},t.prototype.noClick=function(){this.cancelCommand(),a.isFunc(this.fNoAction)&&this.fNoAction.call(null)},t.prototype.onShow=function(e,t,i,o,s,n){this.clearPopup(),this.fYesAction=t||null,this.fNoAction=i||null,this.askDesc(e||""),o&&this.yesButton(o),o&&this.yesButton(s),this.bFocusYesOnShow=a.isUnd(n)?!0:!!n},t.prototype.onShowWithDelay=function(){this.bFocusYesOnShow&&this.yesFocus(!0)},t.prototype.onBuild=function(){n("tab, shift+tab, right, left",r.KeyState.PopupAsk,o.bind(function(){return this.yesFocus()?this.noFocus(!0):this.yesFocus(!0),!1},this)),n("esc",r.KeyState.PopupAsk,o.bind(function(){return this.noClick(),!1},this))},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){a.call(this,"Popups","PopupsLanguages");var e=this;this.fLang=null,this.userLanguage=s.observable(""),this.langs=s.observableArray([]),this.languages=s.computed(function(){var t=e.userLanguage();return o.map(e.langs(),function(e){return{key:e,user:e===t,selected:s.observable(!1),fullName:n.convertLangName(e)}})}),this.langs.subscribe(function(){this.setLanguageSelection()},this),r.constructorEnd(this)}var o=i(3),s=i(2),n=i(1),r=i(5),a=i(10);r.extendAsViewModel(["View/Popup/Languages","PopupsLanguagesViewModel"],t),o.extend(t.prototype,a.prototype),t.prototype.languageTooltipName=function(e){var t=n.convertLangName(e,!0);return n.convertLangName(e,!1)===t?"":t},t.prototype.setLanguageSelection=function(){var e=this.fLang?s.unwrap(this.fLang):"";o.each(this.languages(),function(t){t.selected(t.key===e)})},t.prototype.onBeforeShow=function(){this.fLang=null,this.userLanguage(""),this.langs([])},t.prototype.onShow=function(e,t,i){this.fLang=e,this.userLanguage(i||""),this.langs(t)},t.prototype.changeLanguage=function(e){this.fLang&&this.fLang(e),this.cancelCommand()},e.exports=t}()},function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0,t["default"]=t.HtmlEditor=void 0;var n=i(13),r=i(8),a=o(r),l=i(9),c=o(l),u=function(){function e(t){var i=arguments.length<=1||void 0===arguments[1]?null:arguments[1],o=arguments.length<=2||void 0===arguments[2]?null:arguments[2],r=arguments.length<=3||void 0===arguments[3]?null:arguments[3];s(this,e),this.editor=null,this.$element=null,this.blurTimer=0,this.onBlur=null,this.onReady=null,this.onModeChange=null,this.__inited=null,this.onBlur=i,this.onReady=o,this.onModeChange=r,this.$element=(0,n.$)(t),this.resize=n._.throttle(n._.bind(this.resize,this),100),this.__inited=!1,this.init()}return e.prototype.blurTrigger=function(){var e=this;this.onBlur&&(n.window.clearTimeout(this.blurTimer),this.blurTimer=n.window.setTimeout(function(){e.onBlur()},200))},e.prototype.focusTrigger=function(){this.onBlur&&n.window.clearTimeout(this.blurTimer)},e.prototype.isHtml=function(){return this.editor?"wysiwyg"===this.editor.mode:!1},e.prototype.setSignature=function(e,t,i){this.editor&&this.editor.execCommand("insertSignature",{isHtml:t,insertBefore:i,signature:e})},e.prototype.checkDirty=function(){return this.editor?this.editor.checkDirty():!1},e.prototype.resetDirty=function(){this.editor&&this.editor.resetDirty()},e.prototype.clearSignatureSigns=function(e){return e.replace(/(\u200C|\u0002)/g,"")},e.prototype.getData=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0],t=arguments.length<=1||void 0===arguments[1]?!1:arguments[1],i="";if(this.editor){try{i="plain"===this.editor.mode&&this.editor.plugins.plain&&this.editor.__plain?this.editor.__plain.getRawData():e?''+this.editor.getData()+"
":this.editor.getData()}catch(o){}t&&(i=this.clearSignatureSigns(i))}return i},e.prototype.getDataWithHtmlMark=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0],t=arguments.length<=1||void 0===arguments[1]?!1:arguments[1];return(this.isHtml()?":HTML:":"")+this.getData(e,t)},e.prototype.modeToggle=function(e,t){if(this.editor){try{e?"plain"===this.editor.mode&&this.editor.setMode("wysiwyg"):"wysiwyg"===this.editor.mode&&this.editor.setMode("plain")}catch(i){}t&&this.resize()}},e.prototype.setHtmlOrPlain=function(e,t){":HTML:"===e.substr(0,6)?this.setHtml(e.substr(6),t):this.setPlain(e,t)},e.prototype.setHtml=function(e,t){if(this.editor&&this.__inited){this.modeToggle(!0),e=e.replace(/]*><\/p>/gi,"");try{this.editor.setData(e)}catch(i){}t&&this.focus()}},e.prototype.replaceHtml=function(e,t){if(this.editor&&this.__inited&&"wysiwyg"===this.editor.mode)try{this.editor.setData(this.editor.getData().replace(e,t))}catch(i){}},e.prototype.setPlain=function(e,t){if(this.editor&&this.__inited){if(this.modeToggle(!1),"plain"===this.editor.mode&&this.editor.plugins.plain&&this.editor.__plain)this.editor.__plain.setRawData(e);else try{this.editor.setData(e)}catch(i){}t&&this.focus()}},e.prototype.init=function(){var e=this;if(this.$element&&this.$element[0]&&!this.editor){var t=function(){var t=a["default"].oHtmlEditorDefaultConfig,i=c["default"].settingsGet("Language"),o=!!c["default"].appSettingsGet("allowHtmlEditorSourceButton"),s=!!c["default"].appSettingsGet("allowHtmlEditorBitiButtons");!o&&s||t.toolbarGroups.__cfgInited||(t.toolbarGroups.__cfgInited=!0,o&&(t.removeButtons=t.removeButtons.replace(",Source","")),s||(t.removePlugins+=(t.removePlugins?",":"")+"bidi")),t.enterMode=n.window.CKEDITOR.ENTER_BR,t.shiftEnterMode=n.window.CKEDITOR.ENTER_P,t.language=a["default"].oHtmlEditorLangsMap[i]||"en",n.window.CKEDITOR.env&&(n.window.CKEDITOR.env.isCompatible=!0),e.editor=n.window.CKEDITOR.appendTo(e.$element[0],t),e.editor.on("key",function(e){return e&&e.data&&9===e.data.keyCode?!1:void 0}),e.editor.on("blur",function(){e.blurTrigger()}),e.editor.on("mode",function(){e.blurTrigger(),e.onModeChange&&e.onModeChange("plain"!==e.editor.mode)}),e.editor.on("focus",function(){e.focusTrigger()}),n.window.FileReader&&e.editor.on("drop",function(t){if(0 ')},r.readAsDataURL(i),t.data.dataTransfer.setData("text/html",s)}}}),e.editor.on("instanceReady",function(){e.editor.removeMenuItem&&(e.editor.removeMenuItem("cut"),e.editor.removeMenuItem("copy"),e.editor.removeMenuItem("paste")),e.__resizable=!0,e.__inited=!0,e.resize(),e.onReady&&e.onReady()})};n.window.CKEDITOR?t():n.window.__initEditor=t}},e.prototype.focus=function(){if(this.editor)try{this.editor.focus()}catch(e){}},e.prototype.hasFocus=function(){if(this.editor)try{return!!this.editor.focusManager.hasFocus}catch(e){}return!1},e.prototype.blur=function(){if(this.editor)try{this.editor.focusManager.blur(!0)}catch(e){}},e.prototype.resize=function(){if(this.editor&&this.__resizable)try{this.editor.resize(this.$element.width(),this.$element.innerHeight())}catch(e){}},e.prototype.setReadOnly=function(e){if(this.editor)try{this.editor.setReadOnly(!!e)}catch(t){}},e.prototype.clear=function(e){
+this.setHtml("",e)},e}();t.HtmlEditor=u,t["default"]=u,e.exports=u},function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function n(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function r(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0,t["default"]=t.AbstracCheckbox=void 0;var a=i(2),l=o(a),c=i(1),u=o(c),d=i(16),p=function(e){function t(){var i=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];s(this,t);var o=n(this,e.call(this));return o.value=i.value,!u["default"].isUnd(o.value)&&o.value.subscribe||(o.value=l["default"].observable(u["default"].isUnd(o.value)?!1:!!o.value)),o.enable=i.enable,!u["default"].isUnd(o.enable)&&o.enable.subscribe||(o.enable=l["default"].observable(u["default"].isUnd(o.enable)?!0:!!o.enable)),o.disable=i.disable,!u["default"].isUnd(o.disable)&&o.disable.subscribe||(o.disable=l["default"].observable(u["default"].isUnd(o.disable)?!1:!!o.disable)),o.label=i.label||"",o.inline=u["default"].isUnd(i.inline)?!1:i.inline,o.readOnly=u["default"].isUnd(i.readOnly)?!1:!!i.readOnly,o.inverted=u["default"].isUnd(i.inverted)?!1:!!i.inverted,o.labeled=!u["default"].isUnd(i.label),o.labelAnimated=!!i.labelAnimated,o}return r(t,e),t.prototype.click=function(){this.readOnly||!this.enable()||this.disable()||this.value(!this.value())},t}(d.AbstractComponent);t.AbstracCheckbox=p,t["default"]=p},function(e,t,i){"use strict";function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var s=i(13),n=i(163),r=i(164),a=function(){function e(){o(this,e);var t=s._.find([r.LocalStorageDriver,n.CookieDriver],function(e){return e&&e.supported()});this.driver=t?new t:null}return e.prototype.set=function(e,t){return this.driver?this.driver.set("p"+e,t):!1},e.prototype.get=function(e){return this.driver?this.driver.get("p"+e):null},e}();e.exports=new a},function(e,t){e.exports=window.Q},function(e,t){e.exports=window.crossroads},,function(e,t,i){!function(){"use strict";function t(){this.contacts=o.observableArray([]),this.contacts.loading=o.observable(!1).extend({throttle:200}),this.contacts.importing=o.observable(!1).extend({throttle:200}),this.contacts.syncing=o.observable(!1).extend({throttle:200}),this.contacts.exportingVcf=o.observable(!1).extend({throttle:200}),this.contacts.exportingCsv=o.observable(!1).extend({throttle:200}),this.allowContactsSync=o.observable(!1),this.enableContactsSync=o.observable(!1),this.contactsSyncUrl=o.observable(""),this.contactsSyncUser=o.observable(""),this.contactsSyncPass=o.observable("")}var o=i(2),s=i(9);t.prototype.populate=function(){this.allowContactsSync(!!s.settingsGet("ContactsSyncIsAllowed")),this.enableContactsSync(!!s.settingsGet("EnableContactsSync")),this.contactsSyncUrl(s.settingsGet("ContactsSyncUrl")),this.contactsSyncUser(s.settingsGet("ContactsSyncUser")),this.contactsSyncPass(s.settingsGet("ContactsSyncPassword"))},e.exports=new t}()},function(e,t,i){!function(){"use strict";function t(){h.call(this,"Popups","PopupsFolderSystem"),l.initOnStartOrLangChange(function(){this.sChooseOnText=l.i18n("POPUPS_SYSTEM_FOLDERS/SELECT_CHOOSE_ONE"),this.sUnuseText=l.i18n("POPUPS_SYSTEM_FOLDERS/SELECT_UNUSE_NAME")},this),this.notification=s.observable(""),this.folderSelectList=s.computed(function(){return a.folderListOptionsBuilder([],c.folderList(),c.folderListSystemNames(),[["",this.sChooseOnText],[r.UNUSED_OPTION_VALUE,this.sUnuseText]],null,null,null,null,null,!0)},this);var e=null,t=null;this.sentFolder=c.sentFolder,this.draftFolder=c.draftFolder,this.spamFolder=c.spamFolder,this.trashFolder=c.trashFolder,this.archiveFolder=c.archiveFolder,e=o.debounce(function(){u.settingsSet("SentFolder",c.sentFolder()),u.settingsSet("DraftFolder",c.draftFolder()),u.settingsSet("SpamFolder",c.spamFolder()),u.settingsSet("TrashFolder",c.trashFolder()),u.settingsSet("ArchiveFolder",c.archiveFolder()),d.saveSystemFolders(a.emptyFunction,{SentFolder:c.sentFolder(),DraftFolder:c.draftFolder(),SpamFolder:c.spamFolder(),TrashFolder:c.trashFolder(),ArchiveFolder:c.archiveFolder(),NullFolder:"NullFolder"})},1e3),t=function(){u.settingsSet("SentFolder",c.sentFolder()),u.settingsSet("DraftFolder",c.draftFolder()),u.settingsSet("SpamFolder",c.spamFolder()),u.settingsSet("TrashFolder",c.trashFolder()),u.settingsSet("ArchiveFolder",c.archiveFolder()),e()},c.sentFolder.subscribe(t),c.draftFolder.subscribe(t),c.spamFolder.subscribe(t),c.trashFolder.subscribe(t),c.archiveFolder.subscribe(t),this.defautOptionsAfterRender=a.defautOptionsAfterRender,p.constructorEnd(this)}var o=i(3),s=i(2),n=i(4),r=i(17),a=i(1),l=i(6),c=i(21),u=i(9),d=i(15),p=i(5),h=i(10);p.extendAsViewModel(["View/Popup/FolderSystem","PopupsFolderSystemViewModel"],t),o.extend(t.prototype,h.prototype),t.prototype.sChooseOnText="",t.prototype.sUnuseText="",t.prototype.onShow=function(e){var t="";switch(e=a.isUnd(e)?n.SetSystemFoldersNotification.None:e){case n.SetSystemFoldersNotification.Sent:t=l.i18n("POPUPS_SYSTEM_FOLDERS/NOTIFICATION_SENT");break;case n.SetSystemFoldersNotification.Draft:t=l.i18n("POPUPS_SYSTEM_FOLDERS/NOTIFICATION_DRAFTS");break;case n.SetSystemFoldersNotification.Spam:t=l.i18n("POPUPS_SYSTEM_FOLDERS/NOTIFICATION_SPAM");break;case n.SetSystemFoldersNotification.Trash:t=l.i18n("POPUPS_SYSTEM_FOLDERS/NOTIFICATION_TRASH");break;case n.SetSystemFoldersNotification.Archive:t=l.i18n("POPUPS_SYSTEM_FOLDERS/NOTIFICATION_ARCHIVE")}this.notification(t)},e.exports=t}()},function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var n=i(13),r=i(2),a=o(r),l=function c(){var e=this;s(this,c),this.identities=a["default"].observableArray([]),this.identities.loading=a["default"].observable(!1).extend({throttle:100}),this.identitiesIDS=a["default"].computed(function(){return n._.compact(n._.map(e.identities(),function(e){return e?e.id:null}))},this)};e.exports=new l},function(e,t,i){!function(){"use strict";var t=i(11),o=t.Opentip;o.styles.rainloop={"extends":"standard",fixed:!0,target:!0,delay:.2,hideDelay:0,hideEffect:"fade",hideEffectDuration:.2,showEffect:"fade",showEffectDuration:.2,showOn:"mouseover click",removeElementsOnHide:!0,background:"#fff",shadow:!1,borderColor:"#999",borderRadius:2,borderWidth:1},o.styles.rainloopTip={"extends":"rainloop",delay:.4,group:"rainloopTips"},o.styles.rainloopErrorTip={"extends":"rainloop",className:"rainloopErrorTip"},e.exports=o}()},function(e,t,i){!function(){"use strict";function t(){this.oRequests={}}var o=i(11),s=i(3),n=i(14),r=i(17),a=i(4),l=i(8),c=i(1),u=i(23),d=i(12),p=i(9);t.prototype.oRequests={},t.prototype.defaultResponse=function(e,t,i,o,n,d){var p=function(){a.StorageResultType.Success!==i&&l.bUnload&&(i=a.StorageResultType.Unload),a.StorageResultType.Success===i&&o&&!o.Result?(o&&-1(new o.Date).getTime()-f),g&&l.oRequests[g]&&(l.oRequests[g].__aborted&&(s="abort"),l.oRequests[g]=null),l.defaultResponse(e,g,s,i,n,t)}),g&&0").addClass("rl-settings-view-model").hide(),p.appendTo(d),i.viewModelDom=p,i.__rlSettingsData=u.__rlSettingsData,u.__dom=p,u.__builded=!0,u.__vm=i,n.applyBindingAccessorsToNode(p[0],{translatorInit:!0,template:function(){return{name:u.__rlSettingsData.Template}}},i),a.delegateRun(i,"onBuild",[p])):a.log("Cannot find sub settings view model position: SettingsSubScreen")),i&&o.defer(function(){t.oCurrentSubScreen&&(a.delegateRun(t.oCurrentSubScreen,"onHide"),t.oCurrentSubScreen.viewModelDom.hide()),t.oCurrentSubScreen=i,t.oCurrentSubScreen&&(a.delegateRun(t.oCurrentSubScreen,"onBeforeShow"),t.oCurrentSubScreen.viewModelDom.show(),a.delegateRun(t.oCurrentSubScreen,"onShow"),a.delegateRun(t.oCurrentSubScreen,"onShowWithDelay",[],200),o.each(t.menu(),function(e){e.selected(i&&i.__rlSettingsData&&e.route===i.__rlSettingsData.Route)}),s("#rl-content .b-settings .b-content .content").scrollTop(0)),a.windowResize()})):c.setHash(l.settings(),!1,!0)},t.prototype.onHide=function(){this.oCurrentSubScreen&&this.oCurrentSubScreen.viewModelDom&&(a.delegateRun(this.oCurrentSubScreen,"onHide"),this.oCurrentSubScreen.viewModelDom.hide())},t.prototype.onBuild=function(){o.each(r.aViewModels.settings,function(e){e&&e.__rlSettingsData&&!o.find(r.aViewModels["settings-removed"],function(t){return t&&t===e})&&this.menu.push({route:e.__rlSettingsData.Route,label:e.__rlSettingsData.Label,selected:n.observable(!1),disabled:!!o.find(r.aViewModels["settings-disabled"],function(t){return t&&t===e})})},this),this.oViewModelPlace=s("#rl-content #rl-settings-subscreen")},t.prototype.routes=function(){var e=o.find(r.aViewModels.settings,function(e){return e&&e.__rlSettingsData&&e.__rlSettingsData.IsDefault}),t=e?e.__rlSettingsData.Route:"general",i={subname:/^(.*)$/,normalize_:function(e,i){return i.subname=a.isUnd(i.subname)?t:a.pString(i.subname),[i.subname]}};return[["{subname}/",i],["{subname}",i],["",i]]},e.exports=t}()},,,,function(e,t,i){!function(){"use strict";function t(){var e=this;this.enableSoundNotification=s.observable(!1),this.soundNotificationIsSupported=s.observable(!1),this.allowDesktopNotification=s.observable(!1),this.desktopNotificationPermissions=s.computed(function(){this.allowDesktopNotification();var e=this.notificationClass(),t=n.DesktopNotification.NotSupported;if(e&&e.permission)switch(e.permission.toLowerCase()){case"granted":t=n.DesktopNotification.Allowed;break;case"denied":t=n.DesktopNotification.Denied;break;case"default":t=n.DesktopNotification.NotAllowed}else o.webkitNotifications&&o.webkitNotifications.checkPermission&&(t=o.webkitNotifications.checkPermission());return t},this).extend({notify:"always"}),this.enableDesktopNotification=s.computed({owner:this,read:function(){return this.allowDesktopNotification()&&n.DesktopNotification.Allowed===this.desktopNotificationPermissions()},write:function(t){if(t){var i=this.notificationClass(),o=this.desktopNotificationPermissions();i&&n.DesktopNotification.Allowed===o?this.allowDesktopNotification(!0):i&&n.DesktopNotification.NotAllowed===o?i.requestPermission(function(){e.allowDesktopNotification.valueHasMutated(),n.DesktopNotification.Allowed===e.desktopNotificationPermissions()?e.allowDesktopNotification()?e.allowDesktopNotification.valueHasMutated():e.allowDesktopNotification(!0):e.allowDesktopNotification()?e.allowDesktopNotification(!1):e.allowDesktopNotification.valueHasMutated()}):this.allowDesktopNotification(!1)}else this.allowDesktopNotification(!1)}}).extend({notify:"always"}),this.enableDesktopNotification.valueHasMutated||(this.enableDesktopNotification.valueHasMutated=function(){e.allowDesktopNotification.valueHasMutated()}),this.computers(),this.initNotificationPlayer()}var o=i(11),s=i(2),n=i(4),r=i(25),a=i(65),l=i(9);t.prototype.computers=function(){this.isDesktopNotificationSupported=s.computed(function(){return n.DesktopNotification.NotSupported!==this.desktopNotificationPermissions()},this),this.isDesktopNotificationDenied=s.computed(function(){return n.DesktopNotification.NotSupported===this.desktopNotificationPermissions()||n.DesktopNotification.Denied===this.desktopNotificationPermissions()},this)},t.prototype.initNotificationPlayer=function(){a&&a.supportedNotification?this.soundNotificationIsSupported(!0):(this.enableSoundNotification(!1),this.soundNotificationIsSupported(!1))},t.prototype.playSoundNotification=function(e){a&&a.supportedNotification&&(e?!0:this.enableSoundNotification())&&a.playNotification()},t.prototype.displayDesktopNotification=function(e,t,i,s){if(this.enableDesktopNotification()){var n=this.notificationClass(),a=n?new n(t,{body:i,icon:e}):null;a&&(a.show&&a.show(),s&&(a.onclick=function(){o.focus(),s.Folder&&s.Uid&&r.pub("mailbox.message.show",[s.Folder,s.Uid])}),o.setTimeout(function(e){return function(){e.cancel?e.cancel():e.close&&e.close()}}(a),7e3))}},t.prototype.populate=function(){this.enableSoundNotification(!!l.settingsGet("SoundNotification")),this.enableDesktopNotification(!!l.settingsGet("DesktopNotifications"))},t.prototype.notificationClass=function(){return o.Notification&&o.Notification.requestPermission?o.Notification:null},e.exports=new t}()},function(e,t,i){!function(){"use strict";function t(){u.call(this,"Popups","PopupsAccount"),this.isNew=s.observable(!0),this.email=s.observable(""),this.password=s.observable(""),this.emailError=s.observable(!1),this.passwordError=s.observable(!1),this.email.subscribe(function(){this.emailError(!1)},this),this.password.subscribe(function(){this.passwordError(!1)},this),this.submitRequest=s.observable(!1),this.submitError=s.observable(""),this.submitErrorAdditional=s.observable(""),this.emailFocus=s.observable(!1),this.addAccountCommand=r.createCommand(this,function(){return this.emailError(""===r.trim(this.email())),this.passwordError(""===r.trim(this.password())),this.emailError()||this.passwordError()?!1:(this.submitRequest(!0),l.accountSetup(o.bind(function(e,t){this.submitRequest(!1),n.StorageResultType.Success===e&&t?t.Result?(i(7)["default"].accountsAndIdentities(),this.cancelCommand()):(this.submitError(t.ErrorCode?a.getNotification(t.ErrorCode):a.getNotification(n.Notification.UnknownError)),t.ErrorMessageAdditional&&this.submitErrorAdditional(t.ErrorMessageAdditional)):(this.submitError(a.getNotification(n.Notification.UnknownError)),this.submitErrorAdditional(""))},this),this.email(),this.password(),this.isNew()),!0)},function(){return!this.submitRequest()}),c.constructorEnd(this)}var o=i(3),s=i(2),n=i(4),r=i(1),a=i(6),l=i(15),c=i(5),u=i(10);c.extendAsViewModel(["View/Popup/Account","View/Popup/AddAccount","PopupsAddAccountViewModel"],t),o.extend(t.prototype,u.prototype),t.prototype.clearPopup=function(){this.isNew(!0),this.email(""),this.password(""),this.emailError(!1),this.passwordError(!1),this.submitRequest(!1),this.submitError(""),this.submitErrorAdditional("")},t.prototype.onShow=function(e){this.clearPopup(),e&&e.canBeEdit()&&(this.isNew(!1),this.email(e.email))},t.prototype.onShowWithDelay=function(){this.emailFocus(!0)},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){T.call(this,"Popups","PopupsContacts");var e=this,t=function(t){t&&0=e?1:e},this),this.contactsPagenator=r.computed(d.computedPagenatorHelper(this.contactsPage,this.contactsPageCount)),this.emptySelection=r.observable(!0),this.viewClearSearch=r.observable(!1),this.viewID=r.observable(""),this.viewReadOnly=r.observable(!1),this.viewProperties=r.observableArray([]),this.viewSaveTrigger=r.observable(l.SaveSettingsStep.Idle),this.viewPropertiesNames=this.viewProperties.filter(function(e){return-1=o&&(this.bDropPageAfterDelete=!0),s.delay(function(){s.each(n,function(e){t.remove(e),d.delegateRunOnDestroy(e)})},500))},t.prototype.deleteSelectedContacts=function(){00?o:0),t.contactsCount(o),d.delegateRunOnDestroy(t.contacts()),t.contacts(n),t.contacts.loading(!1),t.viewClearSearch(""!==t.search())},i,c.CONTACTS_PER_PAGE,this.search())},t.prototype.onBuild=function(e){this.oContentVisible=n(".b-list-content",e),this.oContentScrollable=n(".content",this.oContentVisible),this.selector.init(this.oContentVisible,this.oContentScrollable,l.KeyState.ContactList);var t=this;a("delete",l.KeyState.ContactList,function(){return t.deleteCommand(),!1}),a("c, w",l.KeyState.ContactList,function(){return t.newMessageCommand(),!1}),e.on("click",".e-pagenator .e-page",function(){var e=r.dataFor(this);e&&(t.contactsPage(d.pInt(e.value)),t.reloadContactList())}),this.initUploader()},t.prototype.onShow=function(e,t){this.bBackToCompose=d.isUnd(e)?!1:!!e,this.sLastComposeFocusedField=d.isUnd(t)?"":t,C.routeOff(),this.reloadContactList(!0)},t.prototype.onHide=function(){C.routeOn(),this.currentContact(null),this.emptySelection(!0),this.search(""),this.contactsCount(0),d.delegateRunOnDestroy(this.contacts()),this.contacts([]),this.sLastComposeFocusedField="",this.bBackToCompose&&(this.bBackToCompose=!1,b.capa(l.Capa.Composer)&&C.showScreenPopup(i(29)))},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){d.call(this,"Popups","PopupsIdentity");var e=this;this.id="",this.edit=s.observable(!1),this.owner=s.observable(!1),this.email=s.observable("").validateEmail(),this.email.focused=s.observable(!1),this.name=s.observable(""),this.name.focused=s.observable(!1),this.replyTo=s.observable("").validateSimpleEmail(),this.replyTo.focused=s.observable(!1),this.bcc=s.observable("").validateSimpleEmail(),this.bcc.focused=s.observable(!1),this.signature=s.observable(""),this.signatureInsertBefore=s.observable(!1),this.showBcc=s.observable(!1),this.showReplyTo=s.observable(!1),this.submitRequest=s.observable(!1),this.submitError=s.observable(""),this.bcc.subscribe(function(t){!1===e.showBcc()&&0 ').appendTo("body"),u["default"].$win.on("error",function(e){e&&e.originalEvent&&e.originalEvent.message&&-1===f["default"].inArray(e.originalEvent.message,["Script error.","Uncaught Error: Error calling method on NPObject."])&&i.jsError(f["default"].emptyFunction,e.originalEvent.message,e.originalEvent.filename,e.originalEvent.lineno,l.window.location&&l.window.location.toString?l.window.location.toString():"",u["default"].$html.attr("class"),f["default"].microtime()-u["default"].startMicrotime)}),u["default"].$win.on("resize",function(){y["default"].pub("window.resize")}),y["default"].sub("window.resize",l._.throttle(function(){var e=u["default"].$win.height(),t=u["default"].$win.height();u["default"].$win.__sizes[0]===e&&u["default"].$win.__sizes[1]===t||(u["default"].$win.__sizes[0]=e,u["default"].$win.__sizes[1]=t,y["default"].pub("window.resize.real"))},50)),u["default"].$doc.on("keydown",function(e){e&&e.ctrlKey&&u["default"].$html.addClass("rl-ctrl-key-pressed")}).on("keyup",function(e){e&&!e.ctrlKey&&u["default"].$html.removeClass("rl-ctrl-key-pressed")}),u["default"].$doc.on("mousemove keypress click",l._.debounce(function(){y["default"].pub("rl.auto-logout-refresh")},5e3)),(0,l.key)("esc, enter",p.KeyState.All,l._.bind(function(){f["default"].detectDropdownVisibility()},o)),o}return a(t,e),t.prototype.remote=function(){return null},t.prototype.data=function(){return null},t.prototype.getApplicationConfiguration=function(e,t){return this.applicationConfiguration[e]||t},t.prototype.download=function(e){if(u["default"].sUserAgent&&(u["default"].sUserAgent.indexOf("chrome")>-1||u["default"].sUserAgent.indexOf("chrome")>-1)){var t=l.window.document.createElement("a");if(t.href=e,l.window.document&&l.window.document.createEvent){var i=l.window.document.createEvent.MouseEvents;if(i&&i.initEvent&&t.dispatchEvent)return i.initEvent("click",!0,!0),t.dispatchEvent(i),!0}}return u["default"].bMobileDevice?(l.window.open(e,"_self"),l.window.focus()):this.iframe.attr("src",e),!0},t.prototype.googlePreviewSupported=function(){return null===this.googlePreviewSupportedCache&&(this.googlePreviewSupportedCache=!!C["default"].settingsGet("AllowGoogleSocial")&&!!C["default"].settingsGet("AllowGoogleSocialPreview")),this.googlePreviewSupportedCache},t.prototype.setWindowTitle=function(e){e=f["default"].isNormal(e)&&0<\/b><\/x-script>/i,""):"",a?(i.element.text(""),i.element.replaceWith((0,r.$)(a).text(i.component.templateNodes[0]&&i.component.templateNodes[0].nodeValue?i.component.templateNodes[0].nodeValue:""))):i.element.remove()}return n}return n(t,e),t}(a.AbstractComponent);e.exports=(0,a.componentExportHelper)(l,"ScriptComponent")},function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function n(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function r(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var a=i(1),l=o(a),c=i(6),u=o(c),d=i(16),p=i(37),h=function(e){function t(i){s(this,t);var o=n(this,e.call(this,i));return o.options=i.options||"",o.optionsText=i.optionsText||null,o.optionsValue=i.optionsValue||null,o.optionsCaption=i.optionsCaption||null,o.optionsCaption&&(o.optionsCaption=u["default"].i18n(o.optionsCaption)),o.defautOptionsAfterRender=l["default"].defautOptionsAfterRender,o}return r(t,e),t}(p.AbstractInput);e.exports=(0,d.componentExportHelper)(h,"SelectComponent")},function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function n(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function r(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var a=i(1),l=o(a),c=i(16),u=i(37),d=function(e){function t(i){s(this,t);var o=n(this,e.call(this,i));return o.rows=i.rows||5,o.spellcheck=l["default"].isUnd(i.spellcheck)?!1:!!i.spellcheck,o}return r(t,e),t}(u.AbstractInput);e.exports=(0,c.componentExportHelper)(d,"TextAreaComponent")},function(e,t){"use strict";function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var o=function(){function e(){i(this,e)}return e.prototype.bootstart=function(){},e}();t.AbstractBoot=o,t["default"]=o},function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0,t["default"]=t.AbstractAppStore=void 0;var n=i(2),r=o(n),a=i(8),l=o(a),c=i(9),u=o(c),d=function(){function e(){s(this,e),this.allowLanguagesOnSettings=r["default"].observable(!0),this.allowLanguagesOnLogin=r["default"].observable(!0),this.interfaceAnimation=r["default"].observable(!0),this.interfaceAnimation.subscribe(function(e){var t=l["default"].bMobileDevice||!e;l["default"].$html.toggleClass("rl-anim",!t).toggleClass("no-rl-anim",t)}),this.interfaceAnimation.valueHasMutated(),this.prem=r["default"].observable(!1),this.community=r["default"].observable(!0)}return e.prototype.populate=function(){this.allowLanguagesOnLogin(!!u["default"].settingsGet("AllowLanguagesOnLogin")),this.allowLanguagesOnSettings(!!u["default"].settingsGet("AllowLanguagesOnSettings")),this.interfaceAnimation(!!u["default"].settingsGet("InterfaceAnimation")),this.prem(!!u["default"].settingsGet("PremType")),this.community(!!u["default"].settingsGet("Community"))},e}();t.AbstractAppStore=d,t["default"]=d},function(e,t,i){"use strict";t.__esModule=!0,t["default"]=function(e){var t=i(11),o=i(3),s=i(14),n=i(8),r=i(23),a=i(1),l=i(4),c=i(6),u=i(30);n.__APP__=e,n.$win.keydown(a.kill_CtrlA_CtrlS).unload(function(){n.bUnload=!0}),n.$html.addClass(n.bMobileDevice?"mobile":"no-mobile").on("click.dropdown.data-api",function(){a.detectDropdownVisibility()}),t.rl=t.rl||{},t.rl.i18n=o.bind(c.i18n,c),t.rl.addHook=o.bind(r.addHook,r),t.rl.settingsGet=o.bind(r.mainSettingsGet,r),t.rl.createCommand=a.createCommand,t.rl.addSettingsViewModel=o.bind(r.addSettingsViewModel,r),t.rl.pluginRemoteRequest=o.bind(r.remoteRequest,r),t.rl.pluginSettingsGet=o.bind(r.settingsGet,r),t.rl.EmailModel=u,t.rl.Enums=l,t.__APP_BOOT=function(i){s(o.delay(function(){s("#rl-check").is(":visible")||n.$html.addClass("no-css"),s("#rl-check").remove(),t.rainloopTEMPLATES&&t.rainloopTEMPLATES[0]?(s("#rl-templates").html(t.rainloopTEMPLATES[0]),o.delay(function(){e.bootstart(),n.$html.removeClass("no-js rl-booted-trigger").addClass("rl-booted")},10)):i(!1),t.__APP_BOOT=null},10))}}},function(e,t){e.exports=window.Autolinker},function(e,t){e.exports=window.JSEncrypt},function(e,t){e.exports=window.Jua},function(e,t){e.exports=window.hasher},function(e,t){e.exports=window.moment},function(e,t){e.exports=window.rainloopProgressJs},function(e,t){e.exports=window.ssm},function(e,t,i){!function(){"use strict";function t(){}var o=i(1),s=i(30);t.prototype.emailArrayToString=function(e,t,i){var s=[],n=0,r=0;if(o.isNonEmptyArray(e))for(n=0,r=e.length;r>n;n++)s.push(e[n].toLine(t,i));return s.join(", ")},t.prototype.emailArrayToStringClear=function(e){var t=[],i=0,s=0;if(o.isNonEmptyArray(e))for(i=0,s=e.length;s>i;i++)e[i]&&e[i].email&&""!==e[i].name&&t.push(e[i].email);return t.join(", ")},t.prototype.emailArrayFromJson=function(e){var t=0,i=0,n=null,r=[];if(o.isNonEmptyArray(e))for(t=0,i=e.length;i>t;t++)n=s.newInstanceFromJson(e[t]),n&&r.push(n);return r},t.prototype.replyHelper=function(e,t,i){if(e&&0s;s++)o.isUnd(t[e[s].email])&&(t[e[s].email]=!0,i.push(e[s]))},e.exports=new t}()},function(e,t,i){!function(){"use strict";function t(){d.call(this,"AttachmentModel"),this.checked=n.observable(!1),this.mimeType="",this.fileName="",this.fileNameExt="",this.fileType=r.FileType.Unknown,this.estimatedSize=0,this.friendlySize="",this.isInline=!1,this.isLinked=!1,this.isThumbnail=!1,this.cid="",this.cidWithOutTags="",this.contentLocation="",this.download="",this.folder="",this.uid="",this.mimeIndex="",this.framed=!1}var o=i(11),s=i(3),n=i(2),r=i(4),a=i(8),l=i(1),c=i(12),u=i(65),d=i(27);s.extend(t.prototype,d.prototype),t.newInstanceFromJson=function(e){var i=new t;return i.initByJson(e)?i:null},t.prototype.mimeType="",t.prototype.fileName="",t.prototype.fileType="",t.prototype.fileNameExt="",t.prototype.estimatedSize=0,t.prototype.friendlySize="",t.prototype.isInline=!1,t.prototype.isLinked=!1,t.prototype.isThumbnail=!1,t.prototype.cid="",t.prototype.cidWithOutTags="",t.prototype.contentLocation="",t.prototype.download="",t.prototype.folder="",t.prototype.uid="",t.prototype.mimeIndex="",t.prototype.framed=!1,t.prototype.initByJson=function(e){var i=!1;return e&&"Object/Attachment"===e["@Object"]&&(this.mimeType=l.trim((e.MimeType||"").toLowerCase()),this.fileName=l.trim(e.FileName),this.estimatedSize=l.pInt(e.EstimatedSize),this.isInline=!!e.IsInline,this.isLinked=!!e.IsLinked,this.isThumbnail=!!e.IsThumbnail,this.cid=e.CID,this.contentLocation=e.ContentLocation,this.download=e.Download,this.folder=e.Folder,this.uid=e.Uid,this.mimeIndex=e.MimeIndex,this.framed=!!e.Framed,this.friendlySize=l.friendlySize(this.estimatedSize),this.cidWithOutTags=this.cid.replace(/^<+/,"").replace(/>+$/,""),this.fileNameExt=l.getFileExtension(this.fileName),this.fileType=t.staticFileType(this.fileNameExt,this.mimeType),i=!0),i},t.prototype.isImage=function(){return r.FileType.Image===this.fileType},t.prototype.isMp3=function(){return r.FileType.Audio===this.fileType&&"mp3"===this.fileNameExt},t.prototype.isOgg=function(){return r.FileType.Audio===this.fileType&&("oga"===this.fileNameExt||"ogg"===this.fileNameExt)},t.prototype.isWav=function(){return r.FileType.Audio===this.fileType&&"wav"===this.fileNameExt},t.prototype.hasThumbnail=function(){return this.isThumbnail},t.prototype.isText=function(){return r.FileType.Text===this.fileType||r.FileType.Eml===this.fileType||r.FileType.Certificate===this.fileType||r.FileType.Html===this.fileType||r.FileType.Code===this.fileType},t.prototype.isPdf=function(){return r.FileType.Pdf===this.fileType},t.prototype.isFramed=function(){return this.framed&&a.__APP__&&a.__APP__.googlePreviewSupported()&&!(this.isPdf()&&a.bAllowPdfPreview)&&!this.isText()&&!this.isImage()},t.prototype.hasPreview=function(){return this.isImage()||this.isPdf()&&a.bAllowPdfPreview||this.isText()||this.isFramed()},t.prototype.hasPreplay=function(){return u.supportedMp3&&this.isMp3()||u.supportedOgg&&this.isOgg()||u.supportedWav&&this.isWav()},t.prototype.linkDownload=function(){return c.attachmentDownload(this.download)},t.prototype.linkPreview=function(){return c.attachmentPreview(this.download)},t.prototype.linkThumbnail=function(){return this.hasThumbnail()?c.attachmentThumbnailPreview(this.download):""},t.prototype.linkThumbnailPreviewStyle=function(){var e=this.linkThumbnail();return""===e?"":"background:url("+e+")"},t.prototype.linkFramed=function(){return c.attachmentFramed(this.download)},t.prototype.linkPreviewAsPlain=function(){return c.attachmentPreviewAsPlain(this.download)},t.prototype.linkPreviewMain=function(){var e="";switch(!0){case this.isImage():case this.isPdf()&&a.bAllowPdfPreview:e=this.linkPreview();break;case this.isText():e=this.linkPreviewAsPlain();break;case this.isFramed():e=this.linkFramed()}return e},t.prototype.generateTransferDownloadUrl=function(){var e=this.linkDownload();return"http"!==e.substr(0,4)&&(e=o.location.protocol+"//"+o.location.host+o.location.pathname+e),this.mimeType+":"+this.fileName+":"+e},t.prototype.eventDragStart=function(e,t){var i=t.originalEvent||t;return e&&i&&i.dataTransfer&&i.dataTransfer.setData&&i.dataTransfer.setData("DownloadURL",this.generateTransferDownloadUrl()),!0},t.staticFileType=s.memoize(function(e,t){e=l.trim(e).toLowerCase(),t=l.trim(t).toLowerCase();var i=r.FileType.Unknown,o=t.split("/");switch(!0){case"image"===o[0]||-10?o.Math.ceil(t/e*100):0},this)}var o=i(11),s=i(2);t.prototype.populateData=function(e,t){this.quota(1024*e),this.usage(1024*t)},e.exports=new t}()},function(e,t,i){!function(){"use strict";function t(){this.templates=s.observableArray([]),this.templates.loading=s.observable(!1).extend({throttle:100}),this.templatesNames=s.observableArray([]).extend({throttle:1e3}),this.templatesNames.skipFirst=!0,this.subscribers()}var o=i(3),s=i(2);t.prototype.subscribers=function(){this.templates.subscribe(function(e){this.templatesNames(o.compact(o.map(e,function(e){return e?e.name:null})))},this)},e.exports=new t}()},,function(e,t,i){!function(){"use strict";function t(){p.call(this,"Popups","PopupsFilter"),this.isNew=s.observable(!0),this.modules=c.modules,this.fTrueCallback=null,this.filter=s.observable(null),this.allowMarkAsRead=s.observable(!1),this.defautOptionsAfterRender=a.defautOptionsAfterRender,this.folderSelectList=u.folderMenuForFilters,this.selectedFolderValue=s.observable(""),this.selectedFolderValue.subscribe(function(){this.filter()&&this.filter().actionValue.error(!1)},this),this.saveFilter=a.createCommand(this,function(){if(this.filter()){if(n.FiltersAction.MoveTo===this.filter().actionType()&&this.filter().actionValue(this.selectedFolderValue()),!this.filter().verify())return!1;this.fTrueCallback&&this.fTrueCallback(this.filter()),this.modalVisibility()&&a.delegateRun(this,"closeCommand")}return!0}),this.actionTypeOptions=s.observableArray([]),this.fieldOptions=s.observableArray([]),this.typeOptions=s.observableArray([]),this.typeOptionsSize=s.observableArray([]),l.initOnStartOrLangChange(this.populateOptions,this),this.modules.subscribe(this.populateOptions,this),d.constructorEnd(this)}var o=i(3),s=i(2),n=i(4),r=i(8),a=i(1),l=i(6),c=i(90),u=i(21),d=i(5),p=i(10);d.extendAsViewModel(["View/Popup/Filter","PopupsFilterViewModel"],t),o.extend(t.prototype,p.prototype),t.prototype.populateOptions=function(){this.actionTypeOptions([]);var e=this.modules();e&&(e.markasread&&this.allowMarkAsRead(!0),e.moveto&&this.actionTypeOptions.push({id:n.FiltersAction.MoveTo,name:l.i18n("POPUPS_FILTER/SELECT_ACTION_MOVE_TO")}),e.redirect&&this.actionTypeOptions.push({id:n.FiltersAction.Forward,name:l.i18n("POPUPS_FILTER/SELECT_ACTION_FORWARD_TO")}),e.reject&&this.actionTypeOptions.push({id:n.FiltersAction.Reject,name:l.i18n("POPUPS_FILTER/SELECT_ACTION_REJECT")}),e.vacation&&this.actionTypeOptions.push({id:n.FiltersAction.Vacation,name:l.i18n("POPUPS_FILTER/SELECT_ACTION_VACATION_MESSAGE")})),this.actionTypeOptions.push({id:n.FiltersAction.Discard,name:l.i18n("POPUPS_FILTER/SELECT_ACTION_DISCARD")}),this.fieldOptions([{id:n.FilterConditionField.From,name:l.i18n("POPUPS_FILTER/SELECT_FIELD_FROM")},{id:n.FilterConditionField.Recipient,name:l.i18n("POPUPS_FILTER/SELECT_FIELD_RECIPIENTS")},{id:n.FilterConditionField.Subject,name:l.i18n("POPUPS_FILTER/SELECT_FIELD_SUBJECT")},{id:n.FilterConditionField.Size,name:l.i18n("POPUPS_FILTER/SELECT_FIELD_SIZE")},{id:n.FilterConditionField.Header,name:l.i18n("POPUPS_FILTER/SELECT_FIELD_HEADER")}]),this.typeOptions([{id:n.FilterConditionType.Contains,name:l.i18n("POPUPS_FILTER/SELECT_TYPE_CONTAINS")},{id:n.FilterConditionType.NotContains,name:l.i18n("POPUPS_FILTER/SELECT_TYPE_NOT_CONTAINS")},{id:n.FilterConditionType.EqualTo,name:l.i18n("POPUPS_FILTER/SELECT_TYPE_EQUAL_TO")},{id:n.FilterConditionType.NotEqualTo,name:l.i18n("POPUPS_FILTER/SELECT_TYPE_NOT_EQUAL_TO")}]),this.typeOptionsSize([{id:n.FilterConditionType.Over,name:l.i18n("POPUPS_FILTER/SELECT_TYPE_OVER")},{id:n.FilterConditionType.Under,name:l.i18n("POPUPS_FILTER/SELECT_TYPE_UNDER")}])},t.prototype.removeCondition=function(e){this.filter()&&this.filter().removeCondition(e)},t.prototype.clearPopup=function(){this.isNew(!0),this.fTrueCallback=null,this.filter(null)},t.prototype.onShow=function(e,t,i){this.clearPopup(),this.fTrueCallback=t,this.filter(e),e&&this.selectedFolderValue(e.actionValue()),this.isNew(!i),!i&&e&&e.name.focused(!0)},t.prototype.onShowWithDelay=function(){this.isNew()&&this.filter()&&!r.bMobile&&this.filter().name.focused(!0)},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){p.call(this,"Popups","PopupsFolderCreate"),this.folderName=s.observable(""),this.folderName.focused=s.observable(!1),this.selectedParentValue=s.observable(r.UNUSED_OPTION_VALUE),this.parentFolderSelectList=s.computed(function(){var e=[],t=null,i=null,o=c.folderList(),s=function(e){return e?e.isSystemFolder()?e.name()+" "+e.manageFolderSystemName():e.name():""};return e.push(["",""]),""!==c.namespace&&(t=function(e){return c.namespace!==e.fullNameRaw.substr(0,c.namespace.length)}),l.folderListOptionsBuilder([],o,[],e,null,t,i,s)},this),this.createFolder=l.createCommand(this,function(){var e=this.selectedParentValue();""===e&&1 li"),s=i&&("tab"===i.shortcut||"right"===i.shortcut),n=o.index(o.filter(".active"));return!s&&n>0?n--:s&&n0&&-10)return i.newSelectPosition(o,n.key.shift),!1}}))},e.prototype.autoSelect=function(){return!!(this.oCallbacks.onAutoSelect||this.emptyTrueFunction)()},e.prototype.doUpUpOrDownDown=function(e){(this.oCallbacks.onUpUpOrDownDown||this.emptyTrueFunction)(!!e)},e.prototype.getItemUid=function(e){var t="",i=this.oCallbacks.onItemGetUid||null;return i&&e&&(t=i(e)),t.toString()},e.prototype.newSelectPosition=function(e,t,i){var o=0,s=10,r=!1,a=!1,c=null,u=this.list(),d=u?u.length:0,p=this.focusedItem();if(d>0)if(p){if(p)if(l.EventKeyCode.Down===e||l.EventKeyCode.Up===e||l.EventKeyCode.Insert===e||l.EventKeyCode.Space===e)n._.each(u,function(t){if(!a)switch(e){case l.EventKeyCode.Up:p===t?a=!0:c=t;break;case l.EventKeyCode.Down:case l.EventKeyCode.Insert:r?(c=t,a=!0):p===t&&(r=!0)}}),c||l.EventKeyCode.Down!==e&&l.EventKeyCode.Up!==e||this.doUpUpOrDownDown(l.EventKeyCode.Up===e);else if(l.EventKeyCode.Home===e||l.EventKeyCode.End===e)l.EventKeyCode.Home===e?c=u[0]:l.EventKeyCode.End===e&&(c=u[u.length-1]);else if(l.EventKeyCode.PageDown===e){for(;d>o;o++)if(p===u[o]){o+=s,o=o>d-1?d-1:o,c=u[o];break}}else if(l.EventKeyCode.PageUp===e)for(o=d;o>=0;o--)if(p===u[o]){o-=s,o=0>o?0:o,c=u[o];break}}else l.EventKeyCode.Down===e||l.EventKeyCode.Insert===e||l.EventKeyCode.Space===e||l.EventKeyCode.Home===e||l.EventKeyCode.PageUp===e?c=u[0]:l.EventKeyCode.Up!==e&&l.EventKeyCode.End!==e&&l.EventKeyCode.PageDown!==e||(c=u[u.length-1]);c?(this.focusedItem(c),p&&(t?l.EventKeyCode.Up!==e&&l.EventKeyCode.Down!==e||p.checked(!p.checked()):l.EventKeyCode.Insert!==e&&l.EventKeyCode.Space!==e||p.checked(!p.checked())),!this.autoSelect()&&!i||this.isListChecked()||l.EventKeyCode.Space===e||this.selectedItem(c),this.scrollToFocused()):p&&(!t||l.EventKeyCode.Up!==e&&l.EventKeyCode.Down!==e?l.EventKeyCode.Insert!==e&&l.EventKeyCode.Space!==e||p.checked(!p.checked()):p.checked(!p.checked()),this.focusedItem(p))},e.prototype.scrollToFocused=function(){if(!this.oContentVisible||!this.oContentScrollable)return!1;
+var e=20,t=this.list(),i=(0,n.$)(this.sItemFocusedSelector,this.oContentScrollable),o=i.position(),s=this.oContentVisible.height(),r=i.outerHeight();return t&&t[0]&&t[0].focused()?(this.oContentScrollable.scrollTop(0),!0):o&&(o.top<0||o.top+r>s)?(this.oContentScrollable.scrollTop(o.top<0?this.oContentScrollable.scrollTop()+o.top-e:this.oContentScrollable.scrollTop()+o.top-s+r+e),!0):!1},e.prototype.scrollToTop=function(){var e=arguments.length<=0||void 0===arguments[0]?!1:arguments[0];return this.oContentVisible&&this.oContentScrollable?(e||50>this.oContentScrollable.scrollTop()?this.oContentScrollable.scrollTop(0):this.oContentScrollable.stop().animate({scrollTop:0},200),!0):!1},e.prototype.eventClickFunction=function(e,t){var i=0,o=0,s=!1,n=!1,r=[],a=!1,l=null,c="",u=this.getItemUid(e);if(t&&t.shiftKey&&""!==u&&""!==this.sLastUid&&u!==this.sLastUid)for(r=this.list(),a=e.checked(),i=0,o=r.length;o>i;i++)l=r[i],c=this.getItemUid(l),s=!1,c!==this.sLastUid&&c!==u||(s=!0),s&&(n=!n),(n||s)&&l.checked(a);this.sLastUid=""===u?"":u},e.prototype.on=function(e,t){this.oCallbacks[e]=t},e.prototype.selectMessageItem=function(e){this.focusedItem(e),this.selectedItem(e),this.scrollToFocused()},e}();t.Selector=d,t["default"]=d,e.exports=d},function(e,t,i){!function(){"use strict";function t(e,t,i){r.call(this,"AccountModel"),this.email=e,this.count=s.observable(i||0),this.deleteAccess=s.observable(!1),this.canBeDeleted=s.observable(n.isUnd(t)?!0:!!t),this.canBeEdit=this.canBeDeleted}var o=i(3),s=i(2),n=i(1),r=i(27);o.extend(t.prototype,r.prototype),t.prototype.email="",t.prototype.changeAccountLink=function(){return i(12).change(this.email)},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(e,t,i,o,r,l,c){a.call(this,"ComposeAttachmentModel"),this.id=e,this.isInline=n.isUnd(o)?!1:!!o,this.isLinked=n.isUnd(r)?!1:!!r,this.CID=n.isUnd(l)?"":l,this.contentLocation=n.isUnd(c)?"":c,this.fromMessage=!1,this.fileName=s.observable(t),this.size=s.observable(n.isUnd(i)?null:i),this.tempName=s.observable(""),this.progress=s.observable(0),this.error=s.observable(""),this.waiting=s.observable(!0),this.uploading=s.observable(!1),this.enabled=s.observable(!0),this.complete=s.observable(!1),this.progressText=s.computed(function(){var e=this.progress();return 0===e?"":""+(e>98?100:e)+"%"},this),this.progressStyle=s.computed(function(){var e=this.progress();return 0===e?"":"width:"+(e>98?100:e)+"%"},this),this.title=s.computed(function(){var e=this.error();return""!==e?e:this.fileName()},this),this.friendlySize=s.computed(function(){var e=this.size();return null===e?"":n.friendlySize(this.size())},this),this.mimeType=s.computed(function(){return n.mimeContentType(this.fileName())},this),this.fileExt=s.computed(function(){return n.getFileExtension(this.fileName())},this),this.regDisposables([this.progressText,this.progressStyle,this.title,this.friendlySize,this.mimeType,this.fileExt])}var o=i(3),s=i(2),n=i(1),r=i(86),a=i(27);o.extend(t.prototype,a.prototype),t.prototype.id="",t.prototype.isInline=!1,t.prototype.isLinked=!1,t.prototype.CID="",t.prototype.contentLocation="",t.prototype.fromMessage=!1,t.prototype.cancel=n.emptyFunction,t.prototype.initByUploadJson=function(e){var t=!1;return e&&(this.fileName(e.Name),this.size(n.isUnd(e.Size)?0:n.pInt(e.Size)),this.tempName(n.isUnd(e.TempName)?"":e.TempName),this.isInline=!1,t=!0),t},t.prototype.iconClass=function(){return r.staticIconClass(r.staticFileType(this.fileExt(),this.mimeType()))[0]},t.prototype.iconText=function(){return r.staticIconClass(r.staticFileType(this.fileExt(),this.mimeType()))[1]},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){l.call(this,"ContactModel"),this.idContact=0,this.display="",this.properties=[],this.readOnly=!1,this.focused=s.observable(!1),this.selected=s.observable(!1),this.checked=s.observable(!1),this.deleted=s.observable(!1)}var o=i(3),s=i(2),n=i(4),r=i(1),a=i(12),l=i(27);o.extend(t.prototype,l.prototype),t.prototype.getNameAndEmailHelper=function(){var e="",t="";return r.isNonEmptyArray(this.properties)&&o.each(this.properties,function(i){i&&(n.ContactPropertyType.FirstName===i[0]?e=r.trim(i[1]+" "+e):n.ContactPropertyType.LastName===i[0]?e=r.trim(e+" "+i[1]):""===t&&n.ContactPropertyType.Email===i[0]&&(t=i[1]))},this),""===t?null:[t,e]},t.prototype.parse=function(e){var t=!1;return e&&"Object/Contact"===e["@Object"]&&(this.idContact=r.pInt(e.IdContact),this.display=r.pString(e.Display),this.readOnly=!!e.ReadOnly,r.isNonEmptyArray(e.Properties)&&o.each(e.Properties,function(e){e&&e.Type&&r.isNormal(e.Value)&&r.isNormal(e.TypeStr)&&this.properties.push([r.pInt(e.Type),r.pString(e.Value),r.pString(e.TypeStr)])},this),t=!0),t},t.prototype.srcAttr=function(){return a.emptyContactPic()},t.prototype.generateUid=function(){return""+this.idContact},t.prototype.lineAsCss=function(){var e=[];return this.deleted()&&e.push("deleted"),this.selected()&&e.push("selected"),this.checked()&&e.push("checked"),this.focused()&&e.push("focused"),e.join(" ")},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(e,t,i,o,c){l.call(this,"ContactPropertyModel"),this.type=s.observable(r.isUnd(e)?n.ContactPropertyType.Unknown:e),this.typeStr=s.observable(r.isUnd(t)?"":t),this.focused=s.observable(r.isUnd(o)?!1:!!o),this.value=s.observable(r.pString(i)),this.placeholder=s.observable(c||""),this.placeholderValue=s.computed(function(){var e=this.placeholder();return e?a.i18n(e):""},this),this.largeValue=s.computed(function(){return n.ContactPropertyType.Note===this.type()},this),this.regDisposables([this.placeholderValue,this.largeValue])}var o=i(3),s=i(2),n=i(4),r=i(1),a=i(6),l=i(27);o.extend(t.prototype,l.prototype),e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){a.call(this,"FilterConditionModel"),this.field=s.observable(n.FilterConditionField.From),this.type=s.observable(n.FilterConditionType.Contains),this.value=s.observable(""),this.value.error=s.observable(!1),this.valueSecond=s.observable(""),this.valueSecond.error=s.observable(!1),this.template=s.computed(function(){var e="";switch(this.field()){case n.FilterConditionField.Size:e="SettingsFiltersConditionSize";break;case n.FilterConditionField.Header:e="SettingsFiltersConditionMore";break;default:e="SettingsFiltersConditionDefault"}return e},this),this.field.subscribe(function(){this.value(""),this.valueSecond("")},this),this.regDisposables([this.template])}var o=i(3),s=i(2),n=i(4),r=i(1),a=i(27);o.extend(t.prototype,a.prototype),t.prototype.verify=function(){return""===this.value()?(this.value.error(!0),!1):n.FilterConditionField.Header===this.field()&&""===this.valueSecond()?(this.valueSecond.error(!0),!1):!0},t.prototype.parse=function(e){return e&&e.Field&&e.Type?(this.field(r.pString(e.Field)),this.type(r.pString(e.Type)),this.value(r.pString(e.Value)),this.valueSecond(r.pString(e.ValueSecond)),!0):!1},t.prototype.toJson=function(){return{Field:this.field(),Type:this.type(),Value:this.value(),ValueSecond:this.valueSecond()}},t.prototype.cloneSelf=function(){var e=new t;return e.field(this.field()),e.type(this.type()),e.value(this.value()),e.valueSecond(this.valueSecond()),e},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){u.call(this,"FolderModel"),this.name=s.observable(""),this.fullName="",this.fullNameRaw="",this.fullNameHash="",this.delimiter="",this.namespace="",this.deep=0,this.interval=0,this.selectable=!1,this.existen=!0,this.type=s.observable(n.FolderType.User),this.focused=s.observable(!1),this.selected=s.observable(!1),this.edited=s.observable(!1),this.collapsed=s.observable(!0),this.subScribed=s.observable(!0),this.checkable=s.observable(!1),this.subFolders=s.observableArray([]),this.deleteAccess=s.observable(!1),this.actionBlink=s.observable(!1).extend({falseTimeout:1e3}),this.nameForEdit=s.observable(""),this.privateMessageCountAll=s.observable(0),this.privateMessageCountUnread=s.observable(0),this.collapsedPrivate=s.observable(!0)}var o=i(3),s=i(2),n=i(4),r=i(1),a=i(25),l=i(6),c=i(19),u=i(27);o.extend(t.prototype,u.prototype),t.newInstanceFromJson=function(e){var i=new t;return i.initByJson(e)?i.initComputed():null},t.prototype.initComputed=function(){var e=c.getFolderInboxName();return this.isInbox=s.computed(function(){return n.FolderType.Inbox===this.type()},this),this.hasSubScribedSubfolders=s.computed(function(){return!!o.find(this.subFolders(),function(e){return(e.subScribed()||e.hasSubScribedSubfolders())&&!e.isSystemFolder()})},this),this.canBeEdited=s.computed(function(){return n.FolderType.User===this.type()&&this.existen&&this.selectable},this),this.visible=s.computed(function(){var e=this.subScribed(),t=this.hasSubScribedSubfolders();return e||t&&(!this.existen||!this.selectable)},this),this.isSystemFolder=s.computed(function(){return n.FolderType.User!==this.type()},this),this.hidden=s.computed(function(){var e=this.isSystemFolder(),t=this.hasSubScribedSubfolders();return e&&!t||!this.selectable&&!t},this),this.selectableForFolderList=s.computed(function(){return!this.isSystemFolder()&&this.selectable},this),this.messageCountAll=s.computed({read:this.privateMessageCountAll,write:function(e){r.isPosNumeric(e,!0)?this.privateMessageCountAll(e):this.privateMessageCountAll.valueHasMutated()},owner:this}).extend({notify:"always"}),this.messageCountUnread=s.computed({read:this.privateMessageCountUnread,write:function(e){r.isPosNumeric(e,!0)?this.privateMessageCountUnread(e):this.privateMessageCountUnread.valueHasMutated()},owner:this}).extend({notify:"always"}),this.printableUnreadCount=s.computed(function(){var e=this.messageCountAll(),t=this.messageCountUnread(),i=this.type();if(e>0){if(n.FolderType.Draft===i)return""+e;if(t>0&&n.FolderType.Trash!==i&&n.FolderType.Archive!==i&&n.FolderType.SentItems!==i)return""+t}return""},this),this.canBeDeleted=s.computed(function(){var t=this.isSystemFolder();return!t&&0===this.subFolders().length&&e!==this.fullNameRaw},this),this.canBeSubScribed=s.computed(function(){return!this.isSystemFolder()&&this.selectable&&e!==this.fullNameRaw},this),this.canBeChecked=this.canBeSubScribed,this.localName=s.computed(function(){l.trigger();var e=this.type(),t=this.name();if(this.isSystemFolder())switch(e){case n.FolderType.Inbox:t=l.i18n("FOLDER_LIST/INBOX_NAME");break;case n.FolderType.SentItems:t=l.i18n("FOLDER_LIST/SENT_NAME");break;case n.FolderType.Draft:t=l.i18n("FOLDER_LIST/DRAFTS_NAME");break;case n.FolderType.Spam:t=l.i18n("FOLDER_LIST/SPAM_NAME");break;case n.FolderType.Trash:t=l.i18n("FOLDER_LIST/TRASH_NAME");break;case n.FolderType.Archive:t=l.i18n("FOLDER_LIST/ARCHIVE_NAME")}return t},this),this.manageFolderSystemName=s.computed(function(){l.trigger();var e="",t=this.type(),i=this.name();if(this.isSystemFolder())switch(t){case n.FolderType.Inbox:e="("+l.i18n("FOLDER_LIST/INBOX_NAME")+")";break;case n.FolderType.SentItems:e="("+l.i18n("FOLDER_LIST/SENT_NAME")+")";break;case n.FolderType.Draft:e="("+l.i18n("FOLDER_LIST/DRAFTS_NAME")+")";break;case n.FolderType.Spam:e="("+l.i18n("FOLDER_LIST/SPAM_NAME")+")";break;case n.FolderType.Trash:e="("+l.i18n("FOLDER_LIST/TRASH_NAME")+")";break;case n.FolderType.Archive:e="("+l.i18n("FOLDER_LIST/ARCHIVE_NAME")+")"}return(""!==e&&"("+i+")"===e||"(inbox)"===e.toLowerCase())&&(e=""),e},this),this.collapsed=s.computed({read:function(){return!this.hidden()&&this.collapsedPrivate()},write:function(e){this.collapsedPrivate(e)},owner:this}),this.hasUnreadMessages=s.computed(function(){return 0t;t++)o=d.newInstanceFromJson(e["@Collection"][t]),o&&(""!==o.cidWithOutTags&&0 +$/,""),t=s.find(i,function(t){return e===t.cidWithOutTags})),t||null},t.prototype.findAttachmentByContentLocation=function(e){var t=null,i=this.attachments();return l.isNonEmptyArray(i)&&(t=s.find(i,function(t){return e===t.contentLocation})),t||null},t.prototype.messageId=function(){return this.sMessageId},t.prototype.inReplyTo=function(){return this.sInReplyTo},t.prototype.references=function(){return this.sReferences},t.prototype.fromAsSingleEmail=function(){return l.isArray(this.from)&&this.from[0]?this.from[0].email:""},t.prototype.viewLink=function(){return u.messageViewLink(this.requestHash)},t.prototype.downloadLink=function(){return u.messageDownloadLink(this.requestHash)},t.prototype.replyEmails=function(e,t){var i=[],o=l.isUnd(e)?{}:e;return p.replyHelper(this.replyTo,o,i),0===i.length&&p.replyHelper(this.from,o,i),0!==i.length||t?i:this.replyEmails({},!0)},t.prototype.replyAllEmails=function(e,t){var i=[],o=[],s=[],n=l.isUnd(e)?{}:e;return p.replyHelper(this.replyTo,n,o),0===o.length&&p.replyHelper(this.from,n,o),p.replyHelper(this.to,n,o),p.replyHelper(this.cc,n,s),0!==o.length||t?[o,s]:(i=this.replyAllEmails({},!0),[i[0],s])},t.prototype.textBodyToString=function(){return this.body?this.body.html():""},t.prototype.attachmentsToStringLine=function(){var e=s.map(this.attachments(),function(e){return e.fileName+" ("+e.friendlySize+")"});return e&&0=0&&o&&!s&&i.attr("src",o)}),e&&o.setTimeout(function(){t.print()},100))})},t.prototype.printMessage=function(){this.viewPopupMessage(!0)},t.prototype.generateUid=function(){return this.folderFullNameRaw+"/"+this.uid},t.prototype.populateByMessageListItem=function(e){return e&&(this.folderFullNameRaw=e.folderFullNameRaw,this.uid=e.uid,this.hash=e.hash,this.requestHash=e.requestHash,this.subject(e.subject())),this.subjectPrefix(this.subjectPrefix()),this.subjectSuffix(this.subjectSuffix()),e&&(this.size(e.size()),this.dateTimeStampInUTC(e.dateTimeStampInUTC()),this.priority(e.priority()),this.proxy=e.proxy,this.fromEmailString(e.fromEmailString()),this.fromClearEmailString(e.fromClearEmailString()),this.toEmailsString(e.toEmailsString()),this.toClearEmailsString(e.toClearEmailsString()),this.emails=e.emails,this.from=e.from,this.to=e.to,this.cc=e.cc,this.bcc=e.bcc,this.replyTo=e.replyTo,this.deliveredTo=e.deliveredTo,this.unseen(e.unseen()),this.flagged(e.flagged()),this.answered(e.answered()),this.forwarded(e.forwarded()),this.isReadReceipt(e.isReadReceipt()),this.deletedMark(e.deletedMark()),this.priority(e.priority()),this.selected(e.selected()),this.checked(e.checked()),this.hasAttachments(e.hasAttachments()),this.attachmentsSpecData(e.attachmentsSpecData())),this.body=null,this.aDraftInfo=[],this.sMessageId="",this.sInReplyTo="",this.sReferences="",e&&this.threads(e.threads()),this.computeSenderEmail(),this},t.prototype.showExternalImages=function(e){if(this.body&&this.body.data("rl-has-images")){var t="";e=l.isUnd(e)?!1:e,this.hasImages(!1),this.body.data("rl-has-images",!1),t=this.proxy?"data-x-additional-src":"data-x-src",n("["+t+"]",this.body).each(function(){e&&n(this).is("img")?n(this).addClass("lazy").attr("data-original",n(this).attr(t)).removeAttr(t):n(this).attr("src",n(this).attr(t)).removeAttr(t)}),t=this.proxy?"data-x-additional-style-url":"data-x-style-url",n("["+t+"]",this.body).each(function(){var e=l.trim(n(this).attr("style"));e=""===e?"":";"===e.substr(-1)?e+" ":e+"; ",n(this).attr("style",e+n(this).attr(t)).removeAttr(t)}),e&&(n("img.lazy",this.body).addClass("lazy-inited").lazyload({threshold:400,effect:"fadeIn",skip_invisible:!1,container:n(".RL-MailMessageView .messageView .messageItem .content")[0]}),c.$win.resize()),l.windowResize(500)}},t.prototype.showInternalImages=function(e){if(this.body&&!this.body.data("rl-init-internal-images")){this.body.data("rl-init-internal-images",!0),e=l.isUnd(e)?!1:e;var t=this;n("[data-x-src-cid]",this.body).each(function(){var i=t.findAttachmentByCid(n(this).attr("data-x-src-cid"));i&&i.download&&(e&&n(this).is("img")?n(this).addClass("lazy").attr("data-original",i.linkPreview()):n(this).attr("src",i.linkPreview()))}),n("[data-x-src-location]",this.body).each(function(){var i=t.findAttachmentByContentLocation(n(this).attr("data-x-src-location"));i||(i=t.findAttachmentByCid(n(this).attr("data-x-src-location"))),i&&i.download&&(e&&n(this).is("img")?n(this).addClass("lazy").attr("data-original",i.linkPreview()):n(this).attr("src",i.linkPreview()))}),n("[data-x-style-cid]",this.body).each(function(){var e="",i="",o=t.findAttachmentByCid(n(this).attr("data-x-style-cid"));o&&o.linkPreview&&(i=n(this).attr("data-x-style-cid-name"),""!==i&&(e=l.trim(n(this).attr("style")),e=""===e?"":";"===e.substr(-1)?e+" ":e+"; ",n(this).attr("style",e+i+": url('"+o.linkPreview()+"')")))}),e&&!function(e,t){s.delay(function(){e.addClass("lazy-inited").lazyload({threshold:400,effect:"fadeIn",skip_invisible:!1,container:t})},300)}(n("img.lazy",t.body),n(".RL-MailMessageView .messageView .messageItem .content")[0]),l.windowResize(500)}},t.prototype.storeDataInDom=function(){this.body&&(this.body.data("rl-is-html",!!this.isHtml()),this.body.data("rl-has-images",!!this.hasImages()))},t.prototype.fetchDataFromDom=function(){this.body&&(this.isHtml(!!this.body.data("rl-is-html")),this.hasImages(!!this.body.data("rl-has-images")))},t.prototype.replacePlaneTextBody=function(e){this.body&&this.body.html(e).addClass("b-text-part plain")},t.prototype.flagHash=function(){return[this.deleted(),this.deletedMark(),this.unseen(),this.flagged(),this.answered(),this.forwarded(),this.isReadReceipt()].join(",")},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(e,t,i,o,r,l,c,u,d){a.call(this,"OpenPgpKeyModel"),this.index=e,this.id=i,this.ids=n.isNonEmptyArray(o)?o:[i],this.guid=t,this.users=r,this.emails=l,this.armor=u,this.isPrivate=!!c,this.selectUser(d),this.deleteAccess=s.observable(!1)}var o=i(3),s=i(2),n=i(1),r=i(33),a=i(27);o.extend(t.prototype,a.prototype),t.prototype.index=0,t.prototype.id="",t.prototype.ids=[],t.prototype.guid="",t.prototype.user="",t.prototype.users=[],t.prototype.email="",t.prototype.emails=[],t.prototype.armor="",t.prototype.isPrivate=!1,t.prototype.getNativeKey=function(){var e=null;try{if(e=r.openpgp.key.readArmored(this.armor),e&&!e.err&&e.keys&&e.keys[0])return e}catch(t){n.log(t)}return null},t.prototype.getNativeKeys=function(){var e=this.getNativeKey();return e&&e.keys?e.keys:null},t.prototype.select=function(e,t){if(this[t]){var i=this[t].indexOf(e);-1!==i&&(this.user=this.users[i],this.email=this.emails[i])}},t.prototype.selectUser=function(e){this.select(e,"users")},t.prototype.selectEmail=function(e){this.select(e,"emails")},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(e,t,i){r.call(this,"TemplateModel"),this.id=e,this.name=t,this.body=i,this.populated=!0,this.deleteAccess=s.observable(!1)}var o=i(3),s=i(2),n=i(1),r=i(27);o.extend(t.prototype,r.prototype),t.prototype.id="",t.prototype.name="",t.prototype.body="",t.prototype.populated=!0,t.prototype.parse=function(e){var t=!1;return e&&"Object/Template"===e["@Object"]&&(this.id=n.pString(e.ID),this.name=n.pString(e.Name),this.body=n.pString(e.Body),this.populated=!!e.Populated,t=!0),t},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){h.call(this),this.clear()}var o=i(14),s=i(3),n=i(48),r=i(17),a=i(4),l=i(8),c=i(1),u=i(12),d=i(23),p=i(9),h=i(88);s.extend(t.prototype,h.prototype),t.prototype.oRequests={},t.prototype.clear=function(){this.oRequests={}},t.prototype.abort=function(e,t){return this.oRequests[e]&&(!t&&this.oRequests[e].abort&&(this.oRequests[e].__aborted__=!0,this.oRequests[e].abort()),this.oRequests[e]=null,delete this.oRequests[e]),this},t.prototype.ajaxRequest=function(e,t,i,s,h,f){var m=null,g=this,b=c.microtime(),y=n.defer();return i=c.isNormal(i)?i:r.DEFAULT_AJAX_TIMEOUT,h=c.isUnd(h)?"":c.pString(h),t&&(s.XToken=p.appSettingsGet("token")),d.runHook("ajax-default-request",[e,s,h]),this.setTrigger(f,!0),m=o.ajax({type:t?"POST":"GET",url:u.ajax(h),async:!0,dataType:"json",data:t?s||{}:{},timeout:i,global:!0}).always(function(t,i){var o=!1,n=null,u=a.StorageResultType.Error;switch(t&&t.Time&&(o=c.pInt(t.Time)>c.microtime()-b),!0){case"success"===i&&t&&t.Result&&e===t.Action:u=a.StorageResultType.Success;break;case!("abort"!==i||t&&t.__aborted__):u=a.StorageResultType.Abort}d.runHook("ajax-default-response",[e,a.StorageResultType.Success===u?t:null,u,o,s]),"success"===i?t&&t.Result&&e===t.Action?(t.__cached__=o,y.resolve(t)):t&&t.Action?(n=t,y.reject(t.ErrorCode?t.ErrorCode:a.Notification.AjaxFalse)):(n=t,y.reject(a.Notification.AjaxParse)):"timeout"===i?(n=t,y.reject(a.Notification.AjaxTimeout)):"abort"===i?t&&t.__aborted__||y.reject(a.Notification.AjaxAbort):(n=t,y.reject(a.Notification.AjaxParse)),g.oRequests[e]&&(g.oRequests[e]=null,delete g.oRequests[e]),g.setTrigger(f,!1),n&&(-1o;o++)n=t[o],n&&(u=n.FullNameRaw,l=a.getFolderFromCacheList(u),l||(l=p.newInstanceFromJson(n),l&&(a.setFolderToCacheList(u,l),a.setFolderFullNameRaw(l.fullNameHash,u,l))),l&&(c.displaySpecSetting()?l.checkable(!!n.Checkable):l.checkable(!0),l.collapsed(!i.isFolderExpanded(l.fullNameHash)),n.Extended&&(n.Extended.Hash&&a.setFolderHash(l.fullNameRaw,n.Extended.Hash),r.isNormal(n.Extended.MessageCount)&&l.messageCountAll(n.Extended.MessageCount),r.isNormal(n.Extended.MessageUnseenCount)&&l.messageCountUnread(n.Extended.MessageUnseenCount)),d=n.SubFolders,d&&"Collection/FolderCollection"===d["@Object"]&&d["@Collection"]&&r.isArray(d["@Collection"])&&l.subFolders(this.folderResponseParseRec(e,d["@Collection"])),h.push(l)));return h},t.prototype.foldersList=function(e){if(e&&"Collection/FolderCollection"===e["@Object"]&&e["@Collection"]&&r.isArray(e["@Collection"])){var t=r.pInt(u.appSettingsGet("folderSpecLimit")),i=r.pInt(e.CountRec);t=t>100?100:10>t?10:t,c.displaySpecSetting(0>=i||i>t),c.folderList(this.folderResponseParseRec(r.isUnd(e.Namespace)?"":e.Namespace,e["@Collection"]))}},t.prototype.foldersAdditionalParameters=function(e){if(e&&e&&"Collection/FolderCollection"===e["@Object"]&&e["@Collection"]&&r.isArray(e["@Collection"])){r.isUnd(e.Namespace)||(c.namespace=e.Namespace),l.threadsAllowed(!!u.appSettingsGet("useImapThread")&&e.IsThreadsSupported&&!0),c.folderList.optimized(!!e.Optimized);var t=!1;e.SystemFolders&&""==""+u.settingsGet("SentFolder")+u.settingsGet("DraftFolder")+u.settingsGet("SpamFolder")+u.settingsGet("TrashFolder")+u.settingsGet("ArchiveFolder")+u.settingsGet("NullFolder")&&(u.settingsSet("SentFolder",e.SystemFolders[n.ServerFolderType.SENT]||null),u.settingsSet("DraftFolder",e.SystemFolders[n.ServerFolderType.DRAFTS]||null),u.settingsSet("SpamFolder",e.SystemFolders[n.ServerFolderType.JUNK]||null),u.settingsSet("TrashFolder",e.SystemFolders[n.ServerFolderType.TRASH]||null),u.settingsSet("ArchiveFolder",e.SystemFolders[n.ServerFolderType.ALL]||null),t=!0),c.sentFolder(this.normalizeFolder(u.settingsGet("SentFolder"))),c.draftFolder(this.normalizeFolder(u.settingsGet("DraftFolder"))),c.spamFolder(this.normalizeFolder(u.settingsGet("SpamFolder"))),c.trashFolder(this.normalizeFolder(u.settingsGet("TrashFolder"))),c.archiveFolder(this.normalizeFolder(u.settingsGet("ArchiveFolder"))),t&&i(15).saveSystemFolders(r.emptyFunction,{SentFolder:c.sentFolder(),DraftFolder:c.draftFolder(),SpamFolder:c.spamFolder(),TrashFolder:c.trashFolder(),ArchiveFolder:c.archiveFolder(),NullFolder:"NullFolder"}),d.set(n.ClientSideKeyName.FoldersLashHash,e.FoldersHash)}},e.exports=new t}()},,,function(e,t,i){!function(){"use strict";function t(){s.call(this,"login",[i(153)])}var o=i(3),s=i(39);o.extend(t.prototype,s.prototype),t.prototype.onShow=function(){i(7)["default"].setWindowTitle("")},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){g.call(this,"mailbox",[i(157),i(154),i(155),i(156)]),this.oLastRoute={}}var o=i(3),s=i(4),n=i(8),r=i(1),a=i(25),l=i(6),c=i(19),u=i(24),d=i(31),p=i(28),h=i(21),f=i(32),m=i(9),g=i(39);o.extend(t.prototype,g.prototype),t.prototype.oLastRoute={},t.prototype.updateWindowTitle=function(){var e=d.email(),t=h.foldersInboxUnreadCount();m.appSettingsGet("listPermanentFiltered")&&(t=0),i(7)["default"].setWindowTitle((""===e?"":""+(t>0?"("+t+") ":" ")+e+" - ")+l.i18n("TITLES/MAILBOX"))},t.prototype.onShow=function(){this.updateWindowTitle(),u.focusedState(s.Focused.None),u.focusedState(s.Focused.MessageList),m.appSettingsGet("mobile")&&n.leftPanelDisabled(!0),m.capa(s.Capa.Folders)?n.leftPanelType(""):n.leftPanelType(m.capa(s.Capa.Composer)||m.capa(s.Capa.Contacts)?"short":"none")},t.prototype.onRoute=function(e,t,o){var s=e.replace(/^(.+)~([\d]+)$/,"$2"),n=c.getFolderFromCacheList(c.getFolderFullNameRaw(e.replace(/~([\d]+)$/,"")));n&&(e===s&&(s=""),h.currentFolder(n),f.messageListPage(t),f.messageListSearch(o),f.messageListThreadUid(s),i(7)["default"].reloadMessageList())},t.prototype.onStart=function(){h.folderList.subscribe(r.windowResizeCallback),f.messageList.subscribe(r.windowResizeCallback),f.message.subscribe(r.windowResizeCallback),o.delay(function(){p.layout.valueHasMutated()},50),a.sub("mailbox.inbox-unread-count",o.bind(function(e){h.foldersInboxUnreadCount(e);var t=d.email();o.each(d.accounts(),function(i){i&&t===i.email&&i.count(e)}),this.updateWindowTitle()},this))},t.prototype.onBuild=function(){n.bMobileDevice||m.appSettingsGet("mobile")||o.defer(function(){i(7)["default"].initHorizontalLayoutResizer(s.ClientSideKeyName.MessageListSize)})},t.prototype.routes=function(){var e=c.getFolderInboxName(),t=function(t,i){return i[0]=r.pString(i[0]),i[1]=r.pInt(i[1]),i[1]=0>=i[1]?1:i[1],i[2]=r.pString(i[2]),""===t&&(i[0]=e,i[1]=1),[decodeURI(i[0]),i[1],decodeURI(i[2])]},i=function(t,i){return i[0]=r.pString(i[0]),i[1]=r.pString(i[1]),""===t&&(i[0]=e),[decodeURI(i[0]),1,decodeURI(i[1])]};return[[/^([a-zA-Z0-9~]+)\/p([1-9][0-9]*)\/(.+)\/?$/,{normalize_:t}],[/^([a-zA-Z0-9~]+)\/p([1-9][0-9]*)$/,{normalize_:t}],[/^([a-zA-Z0-9~]+)\/(.+)\/?$/,{normalize_:i}],[/^([^\/]*)$/,{normalize_:t}]]},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){p.call(this,[i(160),i(158),i(159)]),r.initOnStartOrLangChange(function(){this.sSettingsTitle=r.i18n("TITLES/SETTINGS")},this,function(){this.setSettingsTitle()})}var o=i(3),s=i(4),n=i(8),r=i(6),a=i(23),l=i(24),c=i(31),u=i(9),d=i(5),p=i(56);o.extend(t.prototype,p.prototype),t.prototype.setupSettings=function(e){return u.capa(s.Capa.Settings)?(d.addSettingsViewModel(i(133),"SettingsGeneral","SETTINGS_LABELS/LABEL_GENERAL_NAME","general",!0),l.contactsIsAllowed()&&d.addSettingsViewModel(i(130),"SettingsContacts","SETTINGS_LABELS/LABEL_CONTACTS_NAME","contacts"),(u.capa(s.Capa.AdditionalAccounts)||u.capa(s.Capa.Identities))&&d.addSettingsViewModel(i(128),"SettingsAccounts",u.capa(s.Capa.AdditionalAccounts)?"SETTINGS_LABELS/LABEL_ACCOUNTS_NAME":"SETTINGS_LABELS/LABEL_IDENTITIES_NAME","accounts"),u.capa(s.Capa.Sieve)&&d.addSettingsViewModel(i(131),"SettingsFilters","SETTINGS_LABELS/LABEL_FILTERS_NAME","filters"),(u.capa(s.Capa.AutoLogout)||u.capa(s.Capa.TwoFactor))&&d.addSettingsViewModel(i(135),"SettingsSecurity","SETTINGS_LABELS/LABEL_SECURITY_NAME","security"),c.isRootAccount()&&(u.settingsGet("AllowGoogleSocial")&&u.settingsGet("AllowGoogleSocialAuth")||u.settingsGet("AllowFacebookSocial")||u.settingsGet("AllowTwitterSocial"))&&d.addSettingsViewModel(i(136),"SettingsSocial","SETTINGS_LABELS/LABEL_SOCIAL_NAME","social"),u.settingsGet("ChangePasswordIsAllowed")&&d.addSettingsViewModel(i(129),"SettingsChangePassword","SETTINGS_LABELS/LABEL_CHANGE_PASSWORD_NAME","change-password"),u.capa(s.Capa.Templates)&&d.addSettingsViewModel(i(137),"SettingsTemplates","SETTINGS_LABELS/LABEL_TEMPLATES_NAME","templates"),u.capa(s.Capa.Folders)&&d.addSettingsViewModel(i(132),"SettingsFolders","SETTINGS_LABELS/LABEL_FOLDERS_NAME","folders"),u.capa(s.Capa.Themes)&&d.addSettingsViewModel(i(138),"SettingsThemes","SETTINGS_LABELS/LABEL_THEMES_NAME","themes"),u.capa(s.Capa.OpenPGP)&&d.addSettingsViewModel(i(134),"SettingsOpenPGP","SETTINGS_LABELS/LABEL_OPEN_PGP_NAME","openpgp"),a.runSettingsViewModelHooks(!1),e&&e(),!0):(e&&e(),!1)},t.prototype.onShow=function(){this.setSettingsTitle(),n.keyScope(s.KeyState.Settings),n.leftPanelType(""),u.appSettingsGet("mobile")&&n.leftPanelDisabled(!0)},t.prototype.setSettingsTitle=function(){var e=c.email();i(7)["default"].setWindowTitle((""===e?"":e+" - ")+this.sSettingsTitle)},e.exports=t}()},,,,,,,,,,,function(e,t,i){!function(){"use strict";function t(){this.allowAdditionalAccount=u.capa(r.Capa.AdditionalAccounts),this.allowIdentities=u.capa(r.Capa.Identities),this.accounts=l.accounts,this.identities=c.identities,this.accountForDeletion=n.observable(null).deleteAccessHelper(),this.identityForDeletion=n.observable(null).deleteAccessHelper()}var o=i(11),s=i(3),n=i(2),r=i(4),a=i(12),l=i(31),c=i(53),u=i(9),d=i(15);t.prototype.scrollableOptions=function(e){return{handle:".drag-handle",containment:e||"parent",axis:"y"}},t.prototype.addNewAccount=function(){i(5).showScreenPopup(i(61))},t.prototype.editAccount=function(e){e&&e.canBeEdit()&&i(5).showScreenPopup(i(61),[e])},t.prototype.addNewIdentity=function(){i(5).showScreenPopup(i(63))},t.prototype.editIdentity=function(e){i(5).showScreenPopup(i(63),[e])},t.prototype.deleteAccount=function(e){if(e&&e.deleteAccess()){this.accountForDeletion(null);var t=i(5),n=function(t){return e===t};e&&(this.accounts.remove(n),d.accountDelete(function(e,n){r.StorageResultType.Success===e&&n&&n.Result&&n.Reload?(t.routeOff(),t.setHash(a.root(),!0),t.routeOff(),s.defer(function(){o.location.reload()})):i(7)["default"].accountsAndIdentities()},e.email))}},t.prototype.deleteIdentity=function(e){e&&e.deleteAccess()&&(this.identityForDeletion(null),e&&(c.identities.remove(function(t){return e===t}),d.identityDelete(function(){i(7)["default"].accountsAndIdentities()},e.id)))},t.prototype.accountsAndIdentitiesAfterMove=function(){d.accountsAndIdentitiesSortOrder(null,l.accountsEmails.peek(),c.identitiesIDS.peek())},t.prototype.onBuild=function(e){var t=this;e.on("click",".accounts-list .account-item .e-action",function(){var e=n.dataFor(this);e&&t.editAccount(e)}).on("click",".identities-list .identity-item .e-action",function(){var e=n.dataFor(this);e&&t.editIdentity(e)})},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){this.changeProcess=s.observable(!1),this.errorDescription=s.observable(""),this.passwordMismatch=s.observable(!1),this.passwordUpdateError=s.observable(!1),this.passwordUpdateSuccess=s.observable(!1),this.currentPassword=s.observable(""),this.currentPassword.error=s.observable(!1),this.newPassword=s.observable(""),this.newPassword2=s.observable(""),this.currentPassword.subscribe(function(){this.passwordUpdateError(!1),this.passwordUpdateSuccess(!1),this.currentPassword.error(!1)},this),this.newPassword.subscribe(function(){this.passwordUpdateError(!1),this.passwordUpdateSuccess(!1),this.passwordMismatch(!1)},this),this.newPassword2.subscribe(function(){this.passwordUpdateError(!1),this.passwordUpdateSuccess(!1),this.passwordMismatch(!1)},this),this.saveNewPasswordCommand=r.createCommand(this,function(){this.newPassword()!==this.newPassword2()?(this.passwordMismatch(!0),this.errorDescription(a.i18n("SETTINGS_CHANGE_PASSWORD/ERROR_PASSWORD_MISMATCH"))):(this.changeProcess(!0),this.passwordUpdateError(!1),this.passwordUpdateSuccess(!1),this.currentPassword.error(!1),this.passwordMismatch(!1),this.errorDescription(""),l.changePassword(this.onChangePasswordResponse,this.currentPassword(),this.newPassword()))},function(){return!this.changeProcess()&&""!==this.currentPassword()&&""!==this.newPassword()&&""!==this.newPassword2()}),this.onChangePasswordResponse=o.bind(this.onChangePasswordResponse,this)}var o=i(3),s=i(2),n=i(4),r=i(1),a=i(6),l=i(15);t.prototype.onHide=function(){this.changeProcess(!1),this.currentPassword(""),this.newPassword(""),this.newPassword2(""),this.errorDescription(""),this.passwordMismatch(!1),this.currentPassword.error(!1)},t.prototype.onChangePasswordResponse=function(e,t){this.changeProcess(!1),this.passwordMismatch(!1),this.errorDescription(""),this.currentPassword.error(!1),n.StorageResultType.Success===e&&t&&t.Result?(this.currentPassword(""),this.newPassword(""),this.newPassword2(""),this.passwordUpdateSuccess(!0),this.currentPassword.error(!1),i(7)["default"].setClientSideToken(t.Result)):(t&&n.Notification.CurrentPasswordIncorrect===t.ErrorCode&&this.currentPassword.error(!0),this.passwordUpdateError(!0),this.errorDescription(a.getNotificationFromResponse(t,n.Notification.CouldNotSaveNewPassword)))},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){this.contactsAutosave=s.contactsAutosave,this.allowContactsSync=n.allowContactsSync,this.enableContactsSync=n.enableContactsSync,this.contactsSyncUrl=n.contactsSyncUrl,this.contactsSyncUser=n.contactsSyncUser,this.contactsSyncPass=n.contactsSyncPass,this.saveTrigger=o.computed(function(){return[this.enableContactsSync()?"1":"0",this.contactsSyncUrl(),this.contactsSyncUser(),this.contactsSyncPass()].join("|")},this).extend({throttle:500})}var o=i(2),s=i(24),n=i(51),r=i(15);t.prototype.onBuild=function(){this.contactsAutosave.subscribe(function(e){r.saveSettings(null,{ContactsAutosave:e?"1":"0"})}),this.saveTrigger.subscribe(function(){r.saveContactsSyncData(null,this.enableContactsSync(),this.contactsSyncUrl(),this.contactsSyncUser(),this.contactsSyncPass())},this)},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){var e=this;this.modules=l.modules,this.filters=l.filters,this.inited=o.observable(!1),this.serverError=o.observable(!1),this.serverErrorDesc=o.observable(""),this.haveChanges=o.observable(!1),this.saveErrorText=o.observable(""),this.filters.subscribe(r.windowResizeCallback),this.serverError.subscribe(function(e){e||this.serverErrorDesc("")},this),this.filterRaw=l.raw,this.filterRaw.capa=l.capa,this.filterRaw.active=o.observable(!1),this.filterRaw.allow=o.observable(!1),this.filterRaw.error=o.observable(!1),this.filterForDeletion=o.observable(null).extend({falseTimeout:3e3}).extend({toggleSubscribeProperty:[this,"deleteAccess"]}),this.saveChanges=r.createCommand(this,function(){if(!this.filters.saving()){if(this.filterRaw.active()&&""===r.trim(this.filterRaw()))return this.filterRaw.error(!0),!1;this.filters.saving(!0),this.saveErrorText(""),c.filtersSave(function(t,i){e.filters.saving(!1),n.StorageResultType.Success===t&&i&&i.Result?(e.haveChanges(!1),e.updateList()):i&&i.ErrorCode?e.saveErrorText(i.ErrorMessageAdditional||a.getNotification(i.ErrorCode)):e.saveErrorText(a.getNotification(n.Notification.CantSaveFilters))},this.filters(),this.filterRaw(),this.filterRaw.active())}return!0},function(){return this.haveChanges()}),this.filters.subscribe(function(){this.haveChanges(!0)},this),this.filterRaw.subscribe(function(){this.haveChanges(!0),this.filterRaw.error(!1)},this),this.haveChanges.subscribe(function(){this.saveErrorText("")},this),this.filterRaw.active.subscribe(function(){this.haveChanges(!0),this.filterRaw.error(!1)},this)}var o=i(2),s=i(3),n=i(4),r=i(1),a=i(6),l=i(90),c=i(15);t.prototype.scrollableOptions=function(e){return{handle:".drag-handle",containment:e||"parent",axis:"y"}},t.prototype.updateList=function(){var e=this,t=i(87);this.filters.loading()||(this.filters.loading(!0),c.filtersGet(function(i,o){if(e.filters.loading(!1),e.serverError(!1),n.StorageResultType.Success===i&&o&&o.Result&&r.isArray(o.Result.Filters)){e.inited(!0),e.serverError(!1);var l=s.compact(s.map(o.Result.Filters,function(e){var i=new t;return i&&i.parse(e)?i:null}));e.filters(l),e.modules(o.Result.Modules?o.Result.Modules:{}),e.filterRaw(o.Result.Raw||""),e.filterRaw.capa(r.isArray(o.Result.Capa)?o.Result.Capa.join(" "):""),e.filterRaw.active(!!o.Result.RawIsActive),e.filterRaw.allow(!!o.Result.RawIsAllow)}else e.filters([]),e.modules({}),e.filterRaw(""),e.filterRaw.capa({}),e.serverError(!0),e.serverErrorDesc(o&&o.ErrorCode?a.getNotification(o.ErrorCode):a.getNotification(n.Notification.CantGetFilters));e.haveChanges(!1)}))},t.prototype.deleteFilter=function(e){this.filters.remove(e),r.delegateRunOnDestroy(e)},t.prototype.addFilter=function(){var e=this,t=i(87),o=new t;o.generateID(),i(5).showScreenPopup(i(94),[o,function(){e.filters.push(o),e.filterRaw.active(!1)},!1])},t.prototype.editFilter=function(e){var t=this,o=e.cloneSelf();i(5).showScreenPopup(i(94),[o,function(){var i=t.filters(),s=i.indexOf(e);s>-1&&i[s]&&(r.delegateRunOnDestroy(i[s]),i[s]=o,t.filters(i),t.haveChanges(!0))},!0])},t.prototype.onBuild=function(e){var t=this;e.on("click",".filter-item .e-action",function(){var e=o.dataFor(this);e&&t.editFilter(e)})},t.prototype.onShow=function(){this.updateList()},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){this.displaySpecSetting=u.displaySpecSetting,this.folderList=u.folderList,this.folderListHelp=o.observable("").extend({throttle:100}),this.loading=o.computed(function(){var e=u.foldersLoading(),t=u.foldersCreating(),i=u.foldersDeleting(),o=u.foldersRenaming();return e||t||i||o},this),this.folderForDeletion=o.observable(null).deleteAccessHelper(),this.folderForEdit=o.observable(null).extend({toggleSubscribe:[this,function(e){e&&e.edited(!1)},function(e){e&&e.canBeEdited()&&e.edited(!0)}]}),this.useImapSubscribe=!!l.appSettingsGet("useImapSubscribe")}var o=i(2),s=i(4),n=i(1),r=i(6),a=i(19),l=i(9),c=i(47),u=i(21),d=i(41),p=i(15);t.prototype.folderEditOnEnter=function(e){var t=e?n.trim(e.nameForEdit()):"";""!==t&&e.name()!==t&&(c.set(s.ClientSideKeyName.FoldersLashHash,""),i(7)["default"].foldersPromisesActionHelper(d.folderRename(e.fullNameRaw,t,u.foldersRenaming),s.Notification.CantRenameFolder),a.removeFolderFromCacheList(e.fullNameRaw),e.name(t)),e.edited(!1)},t.prototype.folderEditOnEsc=function(e){e&&e.edited(!1)},t.prototype.onShow=function(){u.folderList.error("")},t.prototype.onBuild=function(e){var t=this;e.on("mouseover",".delete-folder-parent",function(){t.folderListHelp(r.i18n("SETTINGS_FOLDERS/HELP_DELETE_FOLDER"))}).on("mouseover",".subscribe-folder-parent",function(){t.folderListHelp(r.i18n("SETTINGS_FOLDERS/HELP_SHOW_HIDE_FOLDER"))}).on("mouseover",".check-folder-parent",function(){t.folderListHelp(r.i18n("SETTINGS_FOLDERS/HELP_CHECK_FOR_NEW_MESSAGES"))}).on("mouseout",".subscribe-folder-parent, .check-folder-parent, .delete-folder-parent",function(){t.folderListHelp("")})},t.prototype.createFolder=function(){i(5).showScreenPopup(i(95))},t.prototype.systemFolder=function(){i(5).showScreenPopup(i(52))},t.prototype.deleteFolder=function(e){if(e&&e.canBeDeleted()&&e.deleteAccess()&&0===e.privateMessageCountAll()){this.folderForDeletion(null);var t=function(i){return e===i?!0:(i.subFolders.remove(t),!1)};e&&(c.set(s.ClientSideKeyName.FoldersLashHash,""),u.folderList.remove(t),i(7)["default"].foldersPromisesActionHelper(d.folderDelete(e.fullNameRaw,u.foldersDeleting),s.Notification.CantDeleteFolder),a.removeFolderFromCacheList(e.fullNameRaw))}else 0e)break;t[0]&&t[1]&&t[2]&&t[1]===t[2]&&("PRIVATE"===t[1]?a.privateKeys.importKey(t[0]):"PUBLIC"===t[1]&&a.publicKeys.importKey(t[0])),e--}return a.store(),i(7)["default"].reloadOpenPgpKeys(),n.delegateRun(this,"cancelCommand"),!0}),a.constructorEnd(this)}var o=i(3),s=i(2),n=i(1),r=i(33),a=i(5),l=i(10);a.extendAsViewModel(["View/Popup/AddOpenPgpKey","PopupsAddOpenPgpKeyViewModel"],t),o.extend(t.prototype,l.prototype),t.prototype.clearPopup=function(){this.key(""),this.key.error(!1)},t.prototype.onShow=function(){this.clearPopup()},t.prototype.onShowWithDelay=function(){this.key.focus(!0)},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){c.call(this,"Popups","PopupsAdvancedSearch"),this.fromFocus=s.observable(!1),this.from=s.observable(""),this.to=s.observable(""),this.subject=s.observable(""),this.text=s.observable(""),this.selectedDateValue=s.observable(-1),this.hasAttachment=s.observable(!1),this.starred=s.observable(!1),this.unseen=s.observable(!1),this.searchCommand=n.createCommand(this,function(){var e=this.buildSearchString();""!==e&&a.mainMessageListSearch(e),this.cancelCommand()}),this.selectedDates=s.computed(function(){return r.trigger(),[{id:-1,name:r.i18n("SEARCH/LABEL_ADV_DATE_ALL")},{id:3,name:r.i18n("SEARCH/LABEL_ADV_DATE_3_DAYS")},{id:7,name:r.i18n("SEARCH/LABEL_ADV_DATE_7_DAYS")},{id:30,name:r.i18n("SEARCH/LABEL_ADV_DATE_MONTH")},{id:90,name:r.i18n("SEARCH/LABEL_ADV_DATE_3_MONTHS")},{id:180,name:r.i18n("SEARCH/LABEL_ADV_DATE_6_MONTHS")},{id:365,name:r.i18n("SEARCH/LABEL_ADV_DATE_YEAR")}]},this),l.constructorEnd(this)}var o=i(3),s=i(2),n=i(1),r=i(6),a=i(32),l=i(5),c=i(10);l.extendAsViewModel(["View/Popup/AdvancedSearch","PopupsAdvancedSearchViewModel"],t),o.extend(t.prototype,c.prototype),t.prototype.buildSearchStringValue=function(e){return-10)return this.submitError(c.getNotification(e)),!1;if(""!==t)return this.submitError(t),!1;this.submitRequest(!0);var n=this,l=this.password(),d=s.bind(function(e){m.login(s.bind(function(e,t){r.StorageResultType.Success===e&&t&&"Login"===t.Action?t.Result?t.TwoFactorAuth?(this.additionalCode(""),this.additionalCode.visibility(!0),this.submitRequest(!1),s.delay(function(){n.additionalCode.focused(!0)},100)):t.Admin?i(7)["default"].redirectToAdminPanel():i(7)["default"].loginAndLogoutReload(!1):t.ErrorCode?(this.submitRequest(!1),-1-1&&a.eq(s).removeClass("focused"),38===r&&s>0?s--:40===r&&so)?(i.top<0?this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop()+i.top-e):this.oContentScrollable.scrollTop(this.oContentScrollable.scrollTop()+i.top-o+s+e),!0):!1},t.prototype.messagesDrop=function(e,t){if(e&&t&&t.helper){var o=t.helper.data("rl-folder"),s=u.$html.hasClass("rl-ctrl-key-pressed"),n=t.helper.data("rl-uids");l.isNormal(o)&&""!==o&&l.isArray(n)&&i(7)["default"].moveMessagesToFolder(o,n,e.fullNameRaw,s)}},t.prototype.composeClick=function(){b.capa(c.Capa.Composer)&&y.showScreenPopup(i(29))},t.prototype.createFolder=function(){y.showScreenPopup(i(95))},t.prototype.configureFolders=function(){y.setHash(d.settings("folders"))},t.prototype.contactsClick=function(){this.allowContacts&&y.showScreenPopup(i(62))},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){N.call(this,"Right","MailMessageList"),this.sLastUid=null,this.bPrefetch=!1,this.emptySubjectValue="",this.mobile=!!A.appSettingsGet("mobile"),this.allowReload=!!A.capa(u.Capa.Reload),this.allowSearch=!!A.capa(u.Capa.Search),this.allowSearchAdv=!!A.capa(u.Capa.SearchAdv),this.allowComposer=!!A.capa(u.Capa.Composer),this.allowMessageListActions=!!A.capa(u.Capa.MessageListActions),this.allowDangerousActions=!!A.capa(u.Capa.DangerousActions),this.popupVisibility=p.popupVisibility,this.message=T.message,this.messageList=T.messageList,this.messageListDisableAutoSelect=T.messageListDisableAutoSelect,this.folderList=C.folderList,this.composeInEdit=S.composeInEdit,this.leftPanelDisabled=p.leftPanelDisabled,this.selectorMessageSelected=T.selectorMessageSelected,this.selectorMessageFocused=T.selectorMessageFocused,this.isMessageSelected=T.isMessageSelected,this.messageListSearch=T.messageListSearch,this.messageListThreadUid=T.messageListThreadUid,this.messageListError=T.messageListError,this.folderMenuForMove=C.folderMenuForMove,this.useCheckboxesInList=w.useCheckboxesInList,this.mainMessageListSearch=T.mainMessageListSearch,this.messageListEndFolder=T.messageListEndFolder,this.messageListEndThreadUid=T.messageListEndThreadUid,this.messageListChecked=T.messageListChecked,this.messageListCheckedOrSelected=T.messageListCheckedOrSelected,this.messageListCheckedOrSelectedUidsWithSubMails=T.messageListCheckedOrSelectedUidsWithSubMails,
+this.messageListCompleteLoadingThrottle=T.messageListCompleteLoadingThrottle,this.messageListCompleteLoadingThrottleForAnimation=T.messageListCompleteLoadingThrottleForAnimation,b.initOnStartOrLangChange(function(){this.emptySubjectValue=b.i18n("MESSAGE_LIST/EMPTY_SUBJECT_TEXT")},this),this.userQuota=v.quota,this.userUsageSize=v.usage,this.userUsageProc=v.percentage,this.moveDropdownTrigger=r.observable(!1),this.moreDropdownTrigger=r.observable(!1),this.dragOver=r.observable(!1).extend({throttle:1}),this.dragOverEnter=r.observable(!1).extend({throttle:1}),this.dragOverArea=r.observable(null),this.dragOverBodyArea=r.observable(null),this.messageListItemTemplate=r.computed(function(){return this.mobile||u.Layout.SidePreview===w.layout()?"MailMessageListItem":"MailMessageListItemNoPreviewPane"},this),this.messageListSearchDesc=r.computed(function(){var e=T.messageListEndSearch();return""===e?"":b.i18n("MESSAGE_LIST/SEARCH_RESULT_FOR",{SEARCH:e})}),this.messageListPagenator=r.computed(h.computedPagenatorHelper(T.messageListPage,T.messageListPageCount)),this.checkAll=r.computed({read:function(){return 00&&t>0&&e>t},this),this.hasMessages=r.computed(function(){return 01?" ("+(100>e?e:"99+")+")":""},t.prototype.cancelSearch=function(){this.mainMessageListSearch(""),this.inputMessageListSearchFocus(!1)},t.prototype.cancelThreadUid=function(){F.setHash(f.mailBox(C.currentFolderFullNameHash(),T.messageListPageBeforeThread(),T.messageListSearch()))},t.prototype.moveSelectedMessagesToFolder=function(e,t){return this.canBeMoved()&&i(7)["default"].moveMessagesToFolder(C.currentFolderFullNameRaw(),T.messageListCheckedOrSelectedUidsWithSubMails(),e,t),!1},t.prototype.dragAndDronHelper=function(e){e&&e.checked(!0);var t=h.draggablePlace(),i=T.messageListCheckedOrSelectedUidsWithSubMails();return t.data("rl-folder",C.currentFolderFullNameRaw()),t.data("rl-uids",i),t.find(".text").text(""+i.length),s.defer(function(){var e=T.messageListCheckedOrSelectedUidsWithSubMails();t.data("rl-uids",e),t.find(".text").text(""+e.length)}),t},t.prototype.setAction=function(e,t,o,s){i(7)["default"].messageListAction(e,t,o,s)},t.prototype.setActionForAll=function(e,t){var o=null,n=T.messageList();if(""!==e&&(o=y.getFolderFromCacheList(e))){switch(t){case u.MessageSetAction.SetSeen:o=y.getFolderFromCacheList(e),o&&(s.each(n,function(e){e.unseen(!1)}),o.messageCountUnread(0),y.clearMessageFlagsFromCacheByFolder(e)),E.messageSetSeenToAll(h.emptyFunction,e,!0);break;case u.MessageSetAction.UnsetSeen:o=y.getFolderFromCacheList(e),o&&(s.each(n,function(e){e.unseen(!0)}),o.messageCountUnread(o.messageCountAll()),y.clearMessageFlagsFromCacheByFolder(e)),E.messageSetSeenToAll(h.emptyFunction,e,!1)}i(7)["default"].reloadFlagsCurrentMessageListAndMessageFromCache()}},t.prototype.listSetSeen=function(){this.setAction(C.currentFolderFullNameRaw(),!0,u.MessageSetAction.SetSeen,T.messageListCheckedOrSelected())},t.prototype.listSetAllSeen=function(){this.setActionForAll(C.currentFolderFullNameRaw(),u.MessageSetAction.SetSeen)},t.prototype.listUnsetSeen=function(){this.setAction(C.currentFolderFullNameRaw(),!0,u.MessageSetAction.UnsetSeen,T.messageListCheckedOrSelected())},t.prototype.listSetFlags=function(){this.setAction(C.currentFolderFullNameRaw(),!0,u.MessageSetAction.SetFlag,T.messageListCheckedOrSelected())},t.prototype.listUnsetFlags=function(){this.setAction(C.currentFolderFullNameRaw(),!0,u.MessageSetAction.UnsetFlag,T.messageListCheckedOrSelected())},t.prototype.flagMessages=function(e){var t=this.messageListCheckedOrSelected(),i=[];e&&(0=t))&&(o=s(o));)i=n(o);i="rgba(0, 0, 0, 0)"===i||"transparent"===i?"":i}return i},t.prototype.fullScreen=function(){this.fullScreenMode(!0),d.windowResize()},t.prototype.unFullScreen=function(){this.fullScreenMode(!1),d.windowResize()},t.prototype.toggleFullScreen=function(){d.removeSelection(),this.fullScreenMode(!this.fullScreenMode()),d.windowResize()},t.prototype.replyOrforward=function(e){A.capa(c.Capa.Composer)&&N.showScreenPopup(i(29),[e,C.message()])},t.prototype.checkHeaderHeight=function(){this.oHeaderDom&&this.viewBodyTopValue(this.message()?this.oHeaderDom.height()+20+1:0)},t.prototype.attachmentPreview=function(e){if(e&&e.isImage()&&!e.isLinked&&this.message()&&this.message().attachments()){var t=n(""),i=0,o=0,r=s.compact(s.map(this.message().attachments(),function(t){return t&&!t.isLinked&&t.isImage()?(t===e&&(i=o),o++,{src:t.linkPreview(),thumb:t.linkThumbnail(),subHtml:t.fileName,downloadUrl:t.linkPreview()}):null}));return 0
0?100>e?e:"99+":""},t.prototype.readReceipt=function(e){e&&""!==e.readReceipt()&&(E.sendReadReceiptMessage(d.emptyFunction,e.folderFullNameRaw,e.uid,e.readReceipt(),h.i18n("READ_RECEIPT/SUBJECT",{SUBJECT:e.subject()}),h.i18n("READ_RECEIPT/BODY",{"READ-RECEIPT":v.email()})),e.isReadReceipt(!0),g.storeMessageFlagsToCache(e),i(7)["default"].reloadFlagsCurrentMessageListAndMessageFromCache()),this.checkHeaderHeight()},e.exports=t}()},function(e,t,i){!function(){"use strict";function t(){n.call(this),s.constructorEnd(this)}var o=i(3),s=i(5),n=i(99);s.extendAsViewModel(["View/User/MailBox/SystemDropDown","View/App/MailBox/SystemDropDown","MailBoxSystemDropDownViewModel"],t),o.extend(t.prototype,n.prototype),e.exports=t}()},function(e,t,i){!function(){"use strict";function t(e){d.call(this,"Left","SettingsMenu"),this.leftPanelDisabled=r.leftPanelDisabled,this.mobile=c.appSettingsGet("mobile"),this.menu=e.menu,u.constructorEnd(this)}var o=i(3),s=i(18),n=i(4),r=i(8),a=i(12),l=i(19),c=i(9),u=i(5),d=i(10);u.extendAsViewModel(["View/User/Settings/Menu","View/App/Settings/Menu","SettingsMenuViewModel"],t),o.extend(t.prototype,d.prototype),t.prototype.onBuild=function(e){this.mobile&&e.on("click",".b-settings-menu .e-item.selectable",function(){r.leftPanelDisabled(!0)}),s("up, down",n.KeyState.Settings,o.throttle(function(t,i){var o="",s=-1,n=i&&"up"===i.shortcut,r=$(".b-settings-menu .e-item",e);t&&r.length&&(s=r.index(r.filter(".selected")),n&&s>0?s--:!n&&s>2,l=(3&s)<<4|n>>4,c=(15&n)<<2|r>>6,u=63&r,isNaN(n)?c=u=64:isNaN(r)&&(u=64),t=t+i.charAt(a)+i.charAt(l)+i.charAt(c)+i.charAt(u);return t},decode:function(e){var t="",s=void 0,n=void 0,r=void 0,a=void 0,l=void 0,c=void 0,u=void 0,d=0;for(e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");d>4,n=(15&l)<<4|c>>2,r=(3&c)<<6|u,t+=String.fromCharCode(s),64!==c&&(t+=String.fromCharCode(n)),64!==u&&(t+=String.fromCharCode(r));return o._utf8_decode(t)},_utf8_encode:function(e){e=e.replace(/\r\n/g,"\n");for(var t="",i=0,o=e.length,s=0;o>i;i++)s=e.charCodeAt(i),128>s?t+=String.fromCharCode(s):s>127&&2048>s?(t+=String.fromCharCode(s>>6|192),t+=String.fromCharCode(63&s|128)):(t+=String.fromCharCode(s>>12|224),t+=String.fromCharCode(s>>6&63|128),t+=String.fromCharCode(63&s|128));return t},_utf8_decode:function(e){for(var t="",i=0,o=0,s=0,n=0;io?(t+=String.fromCharCode(o),i++):o>191&&224>o?(s=e.charCodeAt(i+1),t+=String.fromCharCode((31&o)<<6|63&s),i+=2):(s=e.charCodeAt(i+1),n=e.charCodeAt(i+2),t+=String.fromCharCode((15&o)<<12|(63&s)<<6|63&n),i+=3);return t}};e.exports=o},,function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0,t["default"]=t.CookieDriver=void 0;var n=i(13),r=i(1),a=o(r),l=i(17),c=function(){function e(){s(this,e)}return e.prototype.set=function(e,t){var i=!1,o=null;try{var s=n.$.cookie(l.CLIENT_SIDE_STORAGE_INDEX_NAME);o=null===s?null:n.JSON.parse(s)}catch(r){}(o||(o={}))[e]=t;try{n.$.cookie(l.CLIENT_SIDE_STORAGE_INDEX_NAME,n.JSON.stringify(o),{expires:30}),i=!0}catch(r){}return i},e.prototype.get=function(e){var t=null;try{var i=n.$.cookie(l.CLIENT_SIDE_STORAGE_INDEX_NAME),o=null===i?null:n.JSON.parse(i);t=o&&!a["default"].isUnd(o[e])?o[e]:null}catch(s){}return t},e.supported=function(){return!(!n.window.navigator||!n.window.navigator.cookieEnabled)},e}();t.CookieDriver=c,t["default"]=c},function(e,t,i){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0,t["default"]=t.LocalStorageDriver=void 0;var n=i(13),r=i(1),a=o(r),l=i(17),c=function(){function e(){s(this,e)}return e.prototype.set=function(e,t){var i=!1,o=null;try{var s=n.window.localStorage[l.CLIENT_SIDE_STORAGE_INDEX_NAME]||null;o=null===s?null:n.JSON.parse(s)}catch(r){}(o||(o={}))[e]=t;try{n.window.localStorage[l.CLIENT_SIDE_STORAGE_INDEX_NAME]=n.JSON.stringify(o),i=!0}catch(r){}return i},e.prototype.get=function(e){var t=null;try{var i=n.window.localStorage[l.CLIENT_SIDE_STORAGE_INDEX_NAME]||null,o=null===i?null:n.JSON.parse(i);t=o&&!a["default"].isUnd(o[e])?o[e]:null}catch(s){}return t},e.supported=function(){return!!n.window.localStorage},e}();t.LocalStorageDriver=c,t["default"]=c},,,,,,function(e,t){e.exports=window.$LAB},function(e,t){e.exports=window.Tinycon},function(e,t){e.exports=window.ifvisible}]);
diff --git a/rainloop/rainloop/v/1.10.0.103/static/js/min/boot.js b/rainloop/rainloop/v/1.10.0.103/static/js/min/boot.js
new file mode 100644
index 0000000..d14d095
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/static/js/min/boot.js
@@ -0,0 +1,2 @@
+/* RainLoop Webmail (c) RainLoop Team | Licensed under AGPL v3 */
+!function(e){function t(r){if(n[r])return n[r].exports;var s=n[r]={exports:{},id:r,loaded:!1};return e[r].call(s.exports,s,s.exports,t),s.loaded=!0,s.exports}var n={};return t.m=e,t.c=n,t.p="rainloop/v/0.0.0/static/js/min/",t(0)}({0:function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}var s=n(11),o=r(s),i=n(167),a=n(169);n(166),n(168),n(162),o["default"].$LAB=i.$LAB,o["default"].progressJs=a.progressJs},11:function(e,t){e.exports=window},14:function(e,t){e.exports=window.jQuery},162:function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}var s=n(11),o=r(s),i=n(14),a=r(i),l=n(165),u=r(l);o["default"].__rlah=function(){return u["default"]?u["default"].getHash():null},o["default"].__rlah_set=function(){u["default"]&&u["default"].setHash()},o["default"].__rlah_clear=function(){u["default"]&&u["default"].clearHash()},o["default"].__includeScr=function(e){o["default"].document.write(unescape('%3Cscript data-cfasync="false" type="text/javascript" src="'+e+'"%3E%3C/script%3E'))},o["default"].__includeAppScr=function(e){o["default"].__includeScr(e+(o["default"].__rlah?o["default"].__rlah()||"0":"0")+"/"+o["default"].Math.random().toString().substr(2)+"/")},o["default"].__includeStyle=function(e){o["default"].document.write(unescape("%3Cstyle%3E"+e+'"%3E%3C/style%3E'))},o["default"].__showError=function(e){var t=o["default"].document.getElementById("rl-loading"),n=o["default"].document.getElementById("rl-loading-error"),r=o["default"].document.getElementById("rl-loading-error-additional");t&&(t.style.display="none"),n&&(n.style.display="block"),r&&e&&(r.style.display="block",r.innerHTML=e),o["default"].rainloopProgressJs&&o["default"].rainloopProgressJs.set(100)},o["default"].__showDescription=function(e){var t=o["default"].document.getElementById("rl-loading"),n=o["default"].document.getElementById("rl-loading-desc");n&&e&&(n.innerHTML=e),t&&t.style&&(t.style.opacity=0,o["default"].setTimeout(function(){t.style.opacity=1},300))},o["default"].__runBoot=function(e,t){o["default"].__APP_BOOT&&!e?o["default"].__APP_BOOT(function(e){e||o["default"].__showError(t)}):o["default"].__showError(t)},o["default"].__runApp=function(e,t,n){var r=o["default"].rainloopAppData;o["default"].$LAB&&o["default"].progressJs&&r&&r.TemplatesLink&&r.LangLink?!function(){var s=o["default"].progressJs();o["default"].rainloopProgressJs=s,s.setOptions({theme:"rainloop"}),s.start().set(5),o["default"].$LAB.script(function(){return[{src:e,type:"text/javascript",charset:"utf-8"}]}).wait(function(){s.set(20),r.IncludeBackground&&a["default"]&&(0,a["default"])("#rl-bg").attr("style","background-image: none !important;").backstretch(r.IncludeBackground.replace("{{USER}}",o["default"].__rlah?o["default"].__rlah()||"0":"0"),{fade:100,centeredX:!0,centeredY:!0}).removeAttr("style")}).script(function(){return[{src:r.TemplatesLink,type:"text/javascript",charset:"utf-8"},{src:r.LangLink,type:"text/javascript",charset:"utf-8"}]}).wait(function(){s.set(30)}).script(function(){return{src:t,type:"text/javascript",charset:"utf-8"}}).wait(function(){s.set(50)}).script(function(){return r.PluginsLink?{src:r.PluginsLink,type:"text/javascript",charset:"utf-8"}:null}).wait(function(){s.set(70),o["default"].__runBoot(!1)}).script(function(){return{src:n,type:"text/javascript",charset:"utf-8"}}).wait(function(){o["default"].CKEDITOR&&o["default"].__initEditor&&(o["default"].__initEditor(),o["default"].__initEditor=null)})}():o["default"].__runBoot(!0)}},165:function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=n(11),i=r(o),a="__rlA",l=function(){function e(){s(this,e),this.s=null,this.t=null,this.s=i["default"].sessionStorage||null,this.t=i["default"].top||i["default"]}return e.prototype.getHash=function(){var e=null;if(this.s)e=this.s.getItem(a)||null;else if(this.t&&JSON){var t=this.t.name&&"{"===this.t.name.toString().substr(0,1)?JSON.parse(this.t.name.toString()):null;e=t?t[a]||null:null}return e},e.prototype.setHash=function(){var e="AuthAccountHash",t=i["default"].rainloopAppData;if(this.s)this.s.setItem(a,t&&t[e]?t[e]:"");else if(this.t&&JSON){var n={};n[a]=t&&t[e]?t[e]:"",this.t.name=JSON.stringify(n)}},e.prototype.clearHash=function(){this.s?this.s.setItem(a,""):this.t&&(this.t.name="")},e}();e.exports=new l},166:function(module,exports){"object"!=typeof JSON&&(JSON={}),function(){"use strict";function f(e){return 10>e?"0"+e:e}function this_value(){return this.valueOf()}function quote(e){return rx_escapable.lastIndex=0,rx_escapable.test(e)?'"'+e.replace(rx_escapable,function(e){var t=meta[e];return"string"==typeof t?t:"\\u"+("0000"+e.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+e+'"'}function str(e,t){var n,r,s,o,i,a=gap,l=t[e];switch(l&&"object"==typeof l&&"function"==typeof l.toJSON&&(l=l.toJSON(e)),"function"==typeof rep&&(l=rep.call(t,e,l)),typeof l){case"string":return quote(l);case"number":return isFinite(l)?String(l):"null";case"boolean":case"null":return String(l);case"object":if(!l)return"null";if(gap+=indent,i=[],"[object Array]"===Object.prototype.toString.apply(l)){for(o=l.length,n=0;o>n;n+=1)i[n]=str(n,l)||"null";return s=0===i.length?"[]":gap?"[\n"+gap+i.join(",\n"+gap)+"\n"+a+"]":"["+i.join(",")+"]",gap=a,s}if(rep&&"object"==typeof rep)for(o=rep.length,n=0;o>n;n+=1)"string"==typeof rep[n]&&(r=rep[n],s=str(r,l),s&&i.push(quote(r)+(gap?": ":":")+s));else for(r in l)Object.prototype.hasOwnProperty.call(l,r)&&(s=str(r,l),s&&i.push(quote(r)+(gap?": ":":")+s));return s=0===i.length?"{}":gap?"{\n"+gap+i.join(",\n"+gap)+"\n"+a+"}":"{"+i.join(",")+"}",gap=a,s}}var rx_one=/^[\],:{}\s]*$/,rx_two=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,rx_three=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,rx_four=/(?:^|:|,)(?:\s*\[)+/g,rx_escapable=/[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,rx_dangerous=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},Boolean.prototype.toJSON=this_value,Number.prototype.toJSON=this_value,String.prototype.toJSON=this_value);var gap,indent,meta,rep;"function"!=typeof JSON.stringify&&(meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},JSON.stringify=function(e,t,n){var r;if(gap="",indent="","number"==typeof n)for(r=0;n>r;r+=1)indent+=" ";else"string"==typeof n&&(indent=n);if(rep=t,t&&"function"!=typeof t&&("object"!=typeof t||"number"!=typeof t.length))throw new Error("JSON.stringify");return str("",{"":e})}),"function"!=typeof JSON.parse&&(JSON.parse=function(text,reviver){function walk(e,t){var n,r,s=e[t];if(s&&"object"==typeof s)for(n in s)Object.prototype.hasOwnProperty.call(s,n)&&(r=walk(s,n),void 0!==r?s[n]=r:delete s[n]);return reviver.call(e,t,s)}var j;if(text=String(text),rx_dangerous.lastIndex=0,rx_dangerous.test(text)&&(text=text.replace(rx_dangerous,function(e){return"\\u"+("0000"+e.charCodeAt(0).toString(16)).slice(-4)})),rx_one.test(text.replace(rx_two,"@").replace(rx_three,"]").replace(rx_four,"")))return j=eval("("+text+")"),"function"==typeof reviver?walk({"":j},""):j;throw new SyntaxError("JSON.parse")})}()},167:function(e,t){!function(e){function t(e){return"[object Function]"==Object.prototype.toString.call(e)}function n(e){return"[object Array]"==Object.prototype.toString.call(e)}function r(e,t){var n=/^\w+\:\/\//;return/^\/\/\/?/.test(e)?e=location.protocol+e:n.test(e)||"/"==e.charAt(0)||(e=(t||"")+e),n.test(e)?e:("/"==e.charAt(0)?v:_)+e}function s(e,t){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}function o(e){for(var t=!1,n=0;n0){for(var e=0;e=0;)e=O.shift(),t=t[e.type].apply(null,e.args);return t},noConflict:function(){return e.$LAB=c,x},sandbox:function(){return u()}}}var c=e.$LAB,f="UseLocalXHR",d="AlwaysPreserveOrder",p="AllowDuplicates",h="CacheBust",g="Debug",y="BasePath",_=/^[^?#]*\//.exec(location.href)[0],v=/^\w+\:\/\/\/?[^\/]+/.exec(_)[0],m=document.head||document.getElementsByTagName("head"),w=e.opera&&"[object Opera]"==Object.prototype.toString.call(e.opera)||"MozAppearance"in document.documentElement.style,b=function(){},j=b,x=document.createElement("script"),S="boolean"==typeof x.preload,E=S||x.readyState&&"uninitialized"==x.readyState,C=!E&&x.async===!0,N=!E&&!C&&!w;e.console&&e.console.log&&(e.console.error||(e.console.error=e.console.log),b=function(t){e.console.log(t)},j=function(t,n){e.console.error(t,n)}),e.$LAB=u(),function(e,t,n){null==document.readyState&&document[e]&&(document.readyState="loading",document[e](t,n=function(){document.removeEventListener(t,n,!1),document.readyState="complete"},!1))}("addEventListener","DOMContentLoaded")}(this)},168:function(e,t){!function(e,t,n){function r(e,t){return typeof e===t}function s(){var e,t,n,s,o,i,a;for(var l in m)if(m.hasOwnProperty(l)){if(e=[],t=m[l],t.name&&(e.push(t.name.toLowerCase()),t.options&&t.options.aliases&&t.options.aliases.length))for(n=0;nd;d++)if(g=e[d],y=O.style[g],a(g,"-")&&(g=l(g)),O.style[g]!==n){if(o||r(s,"undefined"))return u(),"pfx"==t?g:!0;try{O.style[g]=s}catch(v){}if(O.style[g]!=y)return u(),"pfx"==t?g:!0}return u(),!1}function y(e,t,n,s,o){var i=e.charAt(0).toUpperCase()+e.slice(1),a=(e+" "+E.join(i+" ")+i).split(" ");return r(t,"string")||r(t,"undefined")?g(a,t,s,o):(a=(e+" "+C.join(i+" ")+i).split(" "),c(a,t,n))}function _(e,t,r){return y(e,n,n,t,r)}var v=[],m=[],w={_version:"3.3.1",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,t){var n=this;setTimeout(function(){t(n[e])},0)},addTest:function(e,t,n){m.push({name:e,fn:t,options:n})},addAsyncTest:function(e){m.push({name:null,fn:e})}},b=function(){};b.prototype=w,b=new b;var j=t.documentElement,x="svg"===j.nodeName.toLowerCase();b.addTest("rgba",function(){var e=i("a").style;return e.cssText="background-color:rgba(150,255,150,.5)",(""+e.backgroundColor).indexOf("rgba")>-1});var S="Moz O ms Webkit",E=w._config.usePrefixes?S.split(" "):[];w._cssomPrefixes=E;var C=w._config.usePrefixes?S.toLowerCase().split(" "):[];w._domPrefixes=C;var N={elem:i("modernizr")};b._q.push(function(){delete N.elem});var O={style:N.elem.style};b._q.unshift(function(){delete O.style}),w.testAllProps=y,w.testAllProps=_,b.addTest("cssanimations",_("animationName","a",!0)),b.addTest("csstransitions",_("transition","all",!0)),s(),o(v),delete w.addTest,delete w.addAsyncTest;for(var T=0;Te;e++)r.call(this,this._targetElement[e])}function r(e){if(!e.hasAttribute("data-progressjs")){var t=d.call(this,e);e.setAttribute("data-progressjs",window._progressjsId);var n=document.createElement("div");n.className="progressjs-progress progressjs-theme-"+this._options.theme,"body"===e.tagName.toLowerCase()?n.style.position="fixed":n.style.position="absolute",n.setAttribute("data-progressjs",window._progressjsId);var r=document.createElement("div");r.className="progressjs-inner";var s=document.createElement("div");s.className="progressjs-percent",s.innerHTML="1%",r.appendChild(s),this._options.overlayMode&&"body"===e.tagName.toLowerCase()?(n.style.left=0,n.style.right=0,n.style.top=0,n.style.bottom=0):(n.style.left=t.left+"px",n.style.top=t.top+"px","BODY"==e.nodeName?n.style.width="100%":n.style.width=t.width+"px",this._options.overlayMode&&(n.style.height=t.height+"px")),n.appendChild(r);var i=document.querySelector(".progressjs-container");i.appendChild(n),o(e,1),++window._progressjsId}}function s(e){for(var t=0,n=this._targetElement.length;n>t;t++)o.call(this,this._targetElement[t],e)}function o(e,t){var n=this;t>=100&&(t=100),e.hasAttribute("data-progressjs")&&setTimeout(function(){"undefined"!=typeof n._onProgressCallback&&n._onProgressCallback.call(n,e,t);var r=i(e);r.style.width=parseInt(t)+"%";var r=r.querySelector(".progressjs-percent"),s=parseInt(r.innerHTML.replace("%",""));!function(e,t,n){function r(e,t,n){var i=Math.abs(t-n);3>i?o=30:20>i?o=20:intervanIn=1,t-n!=0&&(e.innerHTML=(s?++t:--t)+"%",setTimeout(function(){r(e,t,n)},o))}var s=!0;t>n&&(s=!1);var o=10;r(e,t,n)}(r,s,parseInt(t))},50)}function i(e){var t=parseInt(e.getAttribute("data-progressjs"));return document.querySelector('.progressjs-container > .progressjs-progress[data-progressjs="'+t+'"] > .progressjs-inner')}function a(e,t){var n=this,r=this._targetElement[0];if(r){var s=parseInt(r.getAttribute("data-progressjs"));"undefined"!=typeof window._progressjsIntervals[s]&&clearInterval(window._progressjsIntervals[s]),window._progressjsIntervals[s]=setInterval(function(){l.call(n,e)},t)}}function l(e){for(var t=0,n=this._targetElement.length;n>t;t++){var r=this._targetElement[t];if(r.hasAttribute("data-progressjs")){var s=i(r),a=parseInt(s.style.width.replace("%",""));a&&o.call(this,r,a+(e||1))}}}function u(){"undefined"!=typeof this._onBeforeEndCallback&&(this._options.considerTransition===!0?i(this._targetElement[0]).addEventListener(h(),this._onBeforeEndCallback,!1):this._onBeforeEndCallback.call(this));var e=this._targetElement[0];if(e){for(var t=parseInt(e.getAttribute("data-progressjs")),n=0,r=this._targetElement.length;r>n;n++){var s=this._targetElement[n],a=i(s);if(!a)return;var l=parseInt(a.style.width.replace("%","")),u=1;100>l&&(o.call(this,s,100),u=500),function(e,t){setTimeout(function(){e.parentNode.className+=" progressjs-end",setTimeout(function(){e.parentNode.parentNode.removeChild(e.parentNode),t.removeAttribute("data-progressjs")},1e3)},u)}(a,s)}if(window._progressjsIntervals[t])try{clearInterval(window._progressjsIntervals[t]),window._progressjsIntervals[t]=null,delete window._progressjsIntervals[t]}catch(c){}}}function c(){var e=this._targetElement[0];if(e){for(var t=parseInt(e.getAttribute("data-progressjs")),n=0,r=this._targetElement.length;r>n;n++){var s=this._targetElement[n],o=i(s);if(!o)return;!function(e,t){e.parentNode.className+=" progressjs-end",setTimeout(function(){e.parentNode.parentNode.removeChild(e.parentNode),t.removeAttribute("data-progressjs")},1e3)}(o,s)}if(window._progressjsIntervals[t])try{clearInterval(window._progressjsIntervals[t]),window._progressjsIntervals[t]=null,delete window._progressjsIntervals[t]}catch(a){}}}function f(){if(!document.querySelector(".progressjs-container")){var e=document.createElement("div");e.className="progressjs-container",document.body.appendChild(e)}}function d(e){var t={};"body"===e.tagName.toLowerCase()?(t.width=e.clientWidth,t.height=e.clientHeight):(t.width=e.offsetWidth,t.height=e.offsetHeight);for(var n=0,r=0;e&&!isNaN(e.offsetLeft)&&!isNaN(e.offsetTop);)n+=e.offsetLeft,r+=e.offsetTop,e=e.offsetParent;return t.top=r,t.left=n,t}function p(e,t){var n={};for(var r in e)n[r]=e[r];for(var r in t)n[r]=t[r];return n}function h(){var e,t=document.createElement("fakeelement"),n={transition:"transitionend",OTransition:"oTransitionEnd",MozTransition:"transitionend",WebkitTransition:"webkitTransitionEnd"};for(e in n)if(void 0!==t.style[e])return n[e]}var g="0.1.0",y=function(e){if("object"==typeof e)return new t(e);if("string"==typeof e){var n=document.querySelectorAll(e);if(n)return new t(n);throw new Error("There is no element with given selector.")}return new t(document.body)};return y.version=g,y.fn=t.prototype={clone:function(){return new t(this)},setOption:function(e,t){return this._options[e]=t,this},setOptions:function(e){return this._options=p(this._options,e),this},start:function(){return n.call(this),this},set:function(e){return s.call(this,e),this},increase:function(e){return l.call(this,e),this},autoIncrease:function(e,t){return a.call(this,e,t),this},end:function(){return u.call(this),this},kill:function(){return c.call(this),this},onbeforeend:function(e){if("function"!=typeof e)throw new Error("Provided callback for onbeforeend was not a function");return this._onBeforeEndCallback=e,this},onbeforestart:function(e){if("function"!=typeof e)throw new Error("Provided callback for onbeforestart was not a function");return this._onBeforeStartCallback=e,this},onprogress:function(e){if("function"!=typeof e)throw new Error("Provided callback for onprogress was not a function");return this._onProgressCallback=e,this}},e.progressJs=y,y})}});
diff --git a/rainloop/rainloop/v/1.10.0.103/static/js/min/libs.js b/rainloop/rainloop/v/1.10.0.103/static/js/min/libs.js
new file mode 100644
index 0000000..03f3772
--- /dev/null
+++ b/rainloop/rainloop/v/1.10.0.103/static/js/min/libs.js
@@ -0,0 +1,284 @@
+// Underscore.js 1.6.0
+// http://underscorejs.org
+// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+// Underscore may be freely distributed under the MIT license.
+(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,g=e.filter,d=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,w=Object.keys,_=i.bind,j=function(n){return n instanceof j?n:this instanceof j?void(this._wrapped=n):new j(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=j),exports._=j):n._=j,j.VERSION="1.6.0";var A=j.each=j.forEach=function(n,t,e){if(null==n)return n;if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a=j.keys(n),u=0,i=a.length;i>u;u++)if(t.call(e,n[a[u]],a[u],n)===r)return;return n};j.map=j.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e.push(t.call(r,n,u,i))}),e)};var O="Reduce of empty array with no initial value";j.reduce=j.foldl=j.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=j.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(O);return r},j.reduceRight=j.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=j.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=j.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(O);return r},j.find=j.detect=function(n,t,r){var e;return k(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},j.filter=j.select=function(n,t,r){var e=[];return null==n?e:g&&n.filter===g?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&e.push(n)}),e)},j.reject=function(n,t,r){return j.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},j.every=j.all=function(n,t,e){t||(t=j.identity);var u=!0;return null==n?u:d&&n.every===d?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var k=j.some=j.any=function(n,t,e){t||(t=j.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};j.contains=j.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:k(n,function(n){return n===t})},j.invoke=function(n,t){var r=o.call(arguments,2),e=j.isFunction(t);return j.map(n,function(n){return(e?t:n[t]).apply(n,r)})},j.pluck=function(n,t){return j.map(n,j.property(t))},j.where=function(n,t){return j.filter(n,j.matches(t))},j.findWhere=function(n,t){return j.find(n,j.matches(t))},j.max=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.max.apply(Math,n);var e=-1/0,u=-1/0;return A(n,function(n,i,a){var o=t?t.call(r,n,i,a):n;o>u&&(e=n,u=o)}),e},j.min=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.min.apply(Math,n);var e=1/0,u=1/0;return A(n,function(n,i,a){var o=t?t.call(r,n,i,a):n;u>o&&(e=n,u=o)}),e},j.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=j.random(r++),e[r-1]=e[t],e[t]=n}),e},j.sample=function(n,t,r){return null==t||r?(n.length!==+n.length&&(n=j.values(n)),n[j.random(n.length-1)]):j.shuffle(n).slice(0,Math.max(0,t))};var E=function(n){return null==n?j.identity:j.isFunction(n)?n:j.property(n)};j.sortBy=function(n,t,r){return t=E(t),j.pluck(j.map(n,function(n,e,u){return{value:n,index:e,criteria:t.call(r,n,e,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var F=function(n){return function(t,r,e){var u={};return r=E(r),A(t,function(i,a){var o=r.call(e,i,a,t);n(u,o,i)}),u}};j.groupBy=F(function(n,t,r){j.has(n,t)?n[t].push(r):n[t]=[r]}),j.indexBy=F(function(n,t,r){n[t]=r}),j.countBy=F(function(n,t){j.has(n,t)?n[t]++:n[t]=1}),j.sortedIndex=function(n,t,r,e){r=E(r);for(var u=r.call(e,t),i=0,a=n.length;a>i;){var o=i+a>>>1;r.call(e,n[o])t?[]:o.call(n,0,t)},j.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},j.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},j.rest=j.tail=j.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},j.compact=function(n){return j.filter(n,j.identity)};var M=function(n,t,r){return t&&j.every(n,j.isArray)?c.apply(r,n):(A(n,function(n){j.isArray(n)||j.isArguments(n)?t?a.apply(r,n):M(n,t,r):r.push(n)}),r)};j.flatten=function(n,t){return M(n,t,[])},j.without=function(n){return j.difference(n,o.call(arguments,1))},j.partition=function(n,t){var r=[],e=[];return A(n,function(n){(t(n)?r:e).push(n)}),[r,e]},j.uniq=j.unique=function(n,t,r,e){j.isFunction(t)&&(e=r,r=t,t=!1);var u=r?j.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:j.contains(a,r))||(a.push(r),i.push(n[e]))}),i},j.union=function(){return j.uniq(j.flatten(arguments,!0))},j.intersection=function(n){var t=o.call(arguments,1);return j.filter(j.uniq(n),function(n){return j.every(t,function(t){return j.contains(t,n)})})},j.difference=function(n){var t=c.apply(e,o.call(arguments,1));return j.filter(n,function(n){return!j.contains(t,n)})},j.zip=function(){for(var n=j.max(j.pluck(arguments,"length").concat(0)),t=new Array(n),r=0;n>r;r++)t[r]=j.pluck(arguments,""+r);return t},j.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},j.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=j.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},j.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},j.range=function(n,t,r){arguments.length<=1&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=new Array(e);e>u;)i[u++]=n,n+=r;return i};var R=function(){};j.bind=function(n,t){var r,e;if(_&&n.bind===_)return _.apply(n,o.call(arguments,1));if(!j.isFunction(n))throw new TypeError;return r=o.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(o.call(arguments)));R.prototype=n.prototype;var u=new R;R.prototype=null;var i=n.apply(u,r.concat(o.call(arguments)));return Object(i)===i?i:u}},j.partial=function(n){var t=o.call(arguments,1);return function(){for(var r=0,e=t.slice(),u=0,i=e.length;i>u;u++)e[u]===j&&(e[u]=arguments[r++]);for(;r=f?(clearTimeout(a),a=null,o=l,i=n.apply(e,u),e=u=null):a||r.trailing===!1||(a=setTimeout(c,f)),i}},j.debounce=function(n,t,r){var e,u,i,a,o,c=function(){var l=j.now()-a;t>l?e=setTimeout(c,t-l):(e=null,r||(o=n.apply(i,u),i=u=null))};return function(){i=this,u=arguments,a=j.now();var l=r&&!e;return e||(e=setTimeout(c,t)),l&&(o=n.apply(i,u),i=u=null),o}},j.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},j.wrap=function(n,t){return j.partial(t,n)},j.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},j.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},j.keys=function(n){if(!j.isObject(n))return[];if(w)return w(n);var t=[];for(var r in n)j.has(n,r)&&t.push(r);return t},j.values=function(n){for(var t=j.keys(n),r=t.length,e=new Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},j.pairs=function(n){for(var t=j.keys(n),r=t.length,e=new Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},j.invert=function(n){for(var t={},r=j.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},j.functions=j.methods=function(n){var t=[];for(var r in n)j.isFunction(n[r])&&t.push(r);return t.sort()},j.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},j.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},j.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)j.contains(r,u)||(t[u]=n[u]);return t},j.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]===void 0&&(n[r]=t[r])}),n},j.clone=function(n){return j.isObject(n)?j.isArray(n)?n.slice():j.extend({},n):n},j.tap=function(n,t){return t(n),n};var S=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof j&&(n=n._wrapped),t instanceof j&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==String(t);case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;var a=n.constructor,o=t.constructor;if(a!==o&&!(j.isFunction(a)&&a instanceof a&&j.isFunction(o)&&o instanceof o)&&"constructor"in n&&"constructor"in t)return!1;r.push(n),e.push(t);var c=0,f=!0;if("[object Array]"==u){if(c=n.length,f=c==t.length)for(;c--&&(f=S(n[c],t[c],r,e)););}else{for(var s in n)if(j.has(n,s)&&(c++,!(f=j.has(t,s)&&S(n[s],t[s],r,e))))break;if(f){for(s in t)if(j.has(t,s)&&!c--)break;f=!c}}return r.pop(),e.pop(),f};j.isEqual=function(n,t){return S(n,t,[],[])},j.isEmpty=function(n){if(null==n)return!0;if(j.isArray(n)||j.isString(n))return 0===n.length;for(var t in n)if(j.has(n,t))return!1;return!0},j.isElement=function(n){return!(!n||1!==n.nodeType)},j.isArray=x||function(n){return"[object Array]"==l.call(n)},j.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){j["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),j.isArguments(arguments)||(j.isArguments=function(n){return!(!n||!j.has(n,"callee"))}),"function"!=typeof/./&&(j.isFunction=function(n){return"function"==typeof n}),j.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},j.isNaN=function(n){return j.isNumber(n)&&n!=+n},j.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},j.isNull=function(n){return null===n},j.isUndefined=function(n){return n===void 0},j.has=function(n,t){return f.call(n,t)},j.noConflict=function(){return n._=t,this},j.identity=function(n){return n},j.constant=function(n){return function(){return n}},j.property=function(n){return function(t){return t[n]}},j.matches=function(n){return function(t){if(t===n)return!0;for(var r in n)if(n[r]!==t[r])return!1;return!0}},j.times=function(n,t,r){for(var e=Array(Math.max(0,n)),u=0;n>u;u++)e[u]=t.call(r,u);return e},j.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},j.now=Date.now||function(){return(new Date).getTime()};var T={escape:{"&":"&","<":"<",">":">",'"':""","'":"'"}};T.unescape=j.invert(T.escape);var I={escape:new RegExp("["+j.keys(T.escape).join("")+"]","g"),unescape:new RegExp("("+j.keys(T.unescape).join("|")+")","g")};j.each(["escape","unescape"],function(n){j[n]=function(t){return null==t?"":(""+t).replace(I[n],function(t){return T[n][t]})}}),j.result=function(n,t){if(null==n)return void 0;var r=n[t];return j.isFunction(r)?r.call(n):r},j.mixin=function(n){A(j.functions(n),function(t){var r=j[t]=n[t];j.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),z.call(this,r.apply(j,n))}})};var N=0;j.uniqueId=function(n){var t=++N+"";return n?n+t:t},j.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var q=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\t|\u2028|\u2029/g;j.template=function(n,t,r){var e;r=j.defaults({},r,j.templateSettings);var u=new RegExp([(r.escape||q).source,(r.interpolate||q).source,(r.evaluate||q).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(D,function(n){return"\\"+B[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=new Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,j);var c=function(n){return e.call(this,n,j)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},j.chain=function(n){return j(n).chain()};var z=function(n){return this._chain?j(n).chain():n};j.mixin(j),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];j.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],z.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];j.prototype[n]=function(){return z.call(this,t.apply(this._wrapped,arguments))}}),j.extend(j.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}}),"function"==typeof define&&define.amd&&define("underscore",[],function(){return j})}).call(this);
+/*! jQuery v1.12.3 | (c) jQuery Foundation | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="1.12.3",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(!l.ownFirst)for(b in a)return k.call(a,b);for(b in a);return void 0===b||k.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(h)return h.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=e.call(arguments,2),d=function(){return a.apply(b||this,c.concat(e.call(arguments)))},d.guid=a.guid=a.guid||n.guid++,d):void 0},now:function(){return+new Date},support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML=" ",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML=" ","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML=" ",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}if(f=d.getElementById(e[2]),f&&f.parentNode){if(f.id!==e[2])return A.find(a);this.length=1,this[0]=f}return this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||(e=n.uniqueSort(e)),D.test(a)&&(e=e.reverse())),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=!0,c||j.disable(),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.addEventListener?(d.removeEventListener("DOMContentLoaded",K),a.removeEventListener("load",K)):(d.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(d.addEventListener||"load"===a.event.type||"complete"===d.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll)a.setTimeout(n.ready);else if(d.addEventListener)d.addEventListener("DOMContentLoaded",K),a.addEventListener("load",K);else{d.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&d.documentElement}catch(e){}c&&c.doScroll&&!function f(){if(!n.isReady){try{c.doScroll("left")}catch(b){return a.setTimeout(f,50)}J(),n.ready()}}()}return I.promise(b)},n.ready.promise();var L;for(L in n(l))break;l.ownFirst="0"===L,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c,e;c=d.getElementsByTagName("body")[0],c&&c.style&&(b=d.createElement("div"),e=d.createElement("div"),e.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(e).appendChild(b),"undefined"!=typeof b.style.zoom&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",l.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(e))}),function(){var a=d.createElement("div");l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}a=null}();var M=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b},N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0;
+}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(M(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),"object"!=typeof b&&"function"!=typeof b||(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f}}function S(a,b,c){if(M(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=void 0)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},Z=/^(?:checkbox|radio)$/i,$=/<([\w:-]+)/,_=/^$|\/(?:java|ecma)script/i,aa=/^\s+/,ba="abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video";function ca(a){var b=ba.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}!function(){var a=d.createElement("div"),b=d.createDocumentFragment(),c=d.createElement("input");a.innerHTML=" a ",l.leadingWhitespace=3===a.firstChild.nodeType,l.tbody=!a.getElementsByTagName("tbody").length,l.htmlSerialize=!!a.getElementsByTagName("link").length,l.html5Clone="<:nav>"!==d.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,b.appendChild(c),l.appendChecked=c.checked,a.innerHTML="",l.noCloneChecked=!!a.cloneNode(!0).lastChild.defaultValue,b.appendChild(a),c=d.createElement("input"),c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),a.appendChild(c),l.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!!a.addEventListener,a[n.expando]=1,l.attributes=!a.getAttribute(n.expando)}();var da={option:[1,""," "],legend:[1,""," "],area:[1,""," "],param:[1,""," "],thead:[1,""],tr:[2,""],col:[2,""],td:[3,""],_default:l.htmlSerialize?[0,"",""]:[1,"X","
"]};da.optgroup=da.option,da.tbody=da.tfoot=da.colgroup=da.caption=da.thead,da.th=da.td;function ea(a,b){var c,d,e=0,f="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,ea(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function fa(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}var ga=/<|?\w+;/,ha=/r;r++)if(g=a[r],g||0===g)if("object"===n.type(g))n.merge(q,g.nodeType?[g]:g);else if(ga.test(g)){i=i||p.appendChild(b.createElement("div")),j=($.exec(g)||["",""])[1].toLowerCase(),m=da[j]||da._default,i.innerHTML=m[1]+n.htmlPrefilter(g)+m[2],f=m[0];while(f--)i=i.lastChild;if(!l.leadingWhitespace&&aa.test(g)&&q.push(b.createTextNode(aa.exec(g)[0])),!l.tbody){g="table"!==j||ha.test(g)?""!==m[1]||ha.test(g)?0:i:i.firstChild,f=g&&g.childNodes.length;while(f--)n.nodeName(k=g.childNodes[f],"tbody")&&!k.childNodes.length&&g.removeChild(k)}n.merge(q,i.childNodes),i.textContent="";while(i.firstChild)i.removeChild(i.firstChild);i=p.lastChild}else q.push(b.createTextNode(g));i&&p.removeChild(i),l.appendChecked||n.grep(ea(q,"input"),ia),r=0;while(g=q[r++])if(d&&n.inArray(g,d)>-1)e&&e.push(g);else if(h=n.contains(g.ownerDocument,g),i=ea(p.appendChild(g),"script"),h&&fa(i),c){f=0;while(g=i[f++])_.test(g.type||"")&&c.push(g)}return i=null,p}!function(){var b,c,e=d.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b]=c in a)||(e.setAttribute(c,"t"),l[b]=e.attributes[c].expando===!1);e=null}();var ka=/^(?:input|select|textarea)$/i,la=/^key/,ma=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,na=/^(?:focusinfocus|focusoutblur)$/,oa=/^([^.]*)(?:\.(.+)|)/;function pa(){return!0}function qa(){return!1}function ra(){try{return d.activeElement}catch(a){}}function sa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)sa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=qa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return"undefined"==typeof n||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(G)||[""],h=b.length;while(h--)f=oa.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=oa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,"type")?b.type:b,r=k.call(b,"namespace")?b.namespace.split("."):[];if(i=m=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!na.test(q+n.event.triggered)&&(q.indexOf(".")>-1&&(r=q.split("."),q=r.shift(),r.sort()),h=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),l=n.event.special[q]||{},f||!l.trigger||l.trigger.apply(e,c)!==!1)){if(!f&&!l.noBubble&&!n.isWindow(e)){for(j=l.delegateType||q,na.test(j+q)||(i=i.parentNode);i;i=i.parentNode)p.push(i),m=i;m===(e.ownerDocument||d)&&p.push(m.defaultView||m.parentWindow||a)}o=0;while((i=p[o++])&&!b.isPropagationStopped())b.type=o>1?j:l.bindType||q,g=(n._data(i,"events")||{})[b.type]&&n._data(i,"handle"),g&&g.apply(i,c),g=h&&i[h],g&&g.apply&&M(i)&&(b.result=g.apply(i,c),b.result===!1&&b.preventDefault());if(b.type=q,!f&&!b.isDefaultPrevented()&&(!l._default||l._default.apply(p.pop(),c)===!1)&&M(e)&&h&&e[q]&&!n.isWindow(e)){m=e[h],m&&(e[h]=null),n.event.triggered=q;try{e[q]()}catch(s){}n.event.triggered=void 0,m&&(e[h]=m)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())a.rnamespace&&!a.rnamespace.test(g.namespace)||(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h ]","i"),va=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,wa=/